顺序表 --- C语言实现

简介: 顺序表 --- C语言实现

1.线性表

什么是线性表 :


线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...,本篇文章介绍一下顺序表。


线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。


2.顺序表

2.1 概念和结构

顺序表是用一段连续的物理地址连续的存储单元依次存储数据元素,一般情况下采用数组存储。在数据上完成增删改查

顺序表一般可以分为:

  1. 静态顺序表,使用定长数组存储元素。
  2. 动态顺序表:使用动态开辟的数组存储。


1.静态顺序表的定义

#define N 7 //顺序表的大小
typedef int SLDataType;
typedef struct SeqList
{
    SLDataType array[N];    //定长数组,顺序表只能存储N个元素
    int size;               //有效元素个数
}SeqList;


2.动态顺序表的定义

typedef int SLDatatype;
typedef struct SeqList
{
  SLDatatype* a; //指向动态开辟的数组,空间不够可以扩容
  int size;      //有效数据个数
  int capacity;  //容量空间大小
}SeqList;

2.2 接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。

所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。


头文件 :

typedef int SLDatatype;
typedef struct SeqList
{
  SLDatatype* a;
  int size;
  int capacity;
}SeqList;
//初始化
void SeqListInit(SeqList* ps);
//释放
void SeqListDestroy(SeqList* ps);
//打印
void SeListPrint(SeqList* ps);
//头插法
void SLPushfront(SeqList* ps, SLDatatype x);
//尾插法
void SLPushback(SeqList* ps, SLDatatype x);
//头删
void SLPopfront(SeqList* ps);
//尾删
void SLPopback(SeqList* ps);
//顺序表查找
int SeqListFind(SeqList* ps, SLDatatype x);
//在顺序表pos位置插入x
void SeqListInsert(SeqList* ps,int pos, SLDatatype x);
//删除顺序表pos位置的值
void SeqListErase(SeqList* ps,int pos);
//修改顺序表pos位置的值
void SeqListMidefy(SeqList* ps, int pos, SLDatatype x);

函数的实现:

//初始化
void SeqListInit(SeqList* ps)
{
  assert(ps);
  ps->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4);
  if (ps->a == 0)
  {
    perror("malloc fail");
    return;
  }
  ps->size = 0;
  ps->capacity = 4;
}
//释放
void SeqListDestroy(SeqList* ps)
{
  assert(ps);
  ps->size = 0;
  ps->capacity = 0;
  free(ps->a);
  ps->a = NULL;
}
//打印
void SeListPrint(SeqList* ps)
{
  assert(ps);
  for (int i = 0; i < ps->size; i++)
  {
    printf("%d ", ps->a[i]);
  }
  printf("\n");
}
//检查容量
int CheckCapacity(SeqList* ps)
{
  assert(ps);
  if (ps->size == ps->capacity)
  {
    SLDatatype* ptr = (SLDatatype*)realloc(ps->a, sizeof(SLDatatype) * ps->capacity * 2);
    if (ptr == NULL)
    {
      perror("realloc fail");
      return 0;
    }
    else
    {
      ps->a = ptr;
      ps->capacity *= 2;
    }
  }
  return 1;
}
//头插法
void SLPushfront(SeqList* ps, SLDatatype x)
{
  assert(ps);
  if (CheckCapacity(ps) == 0)
  {
    return;
  }
  int end = ps->size;
  while (end > 0)
  {
    ps->a[end] = ps->a[end - 1];
    end--;
  }
  ps->a[0] = x;
  ps->size++;
}
//尾插法
void SLPushback(SeqList* ps, SLDatatype x)
{
  assert(ps);
  if (CheckCapacity(ps) == 0)
  {
    return;
  }
  ps->a[ps->size] = x;
  ps->size++;
}
//头删
void SLPopfront(SeqList* ps)
{
  assert(ps);
  assert(ps->size > 0);
  int start = 1;
  while (start < ps->size)
  {
    ps->a[start - 1] = ps->a[start];
    start++;
  }
  ps->size--;
}
//尾删
void SLPopback(SeqList* ps)
{
  assert(ps);
  assert(ps->size > 0);
  ps->size--;
}
//顺序表查找
int SeqListFind(SeqList* ps, SLDatatype x)
{
  assert(ps);
  for (int i = 0; i < ps->size; i++)
  {
    if (ps->a[i] == x)
    {
      return i;
    }
  }
  return -1;
}
//在顺序表pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDatatype x)
{
  assert(ps);
  assert(pos >= 0 && pos <= ps->size);
  if (CheckCapacity(ps) == 0)
  {
    return;
  }
  int end = ps->size;
  while (end > pos)
  {
    ps->a[end] = ps->a[end - 1];
    end--;
  }
  ps->a[pos] = x;
  ps->size++;
}
//删除顺序表pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
  assert(ps);
  assert(pos >= 0 && pos < ps->size);//已经包含 ps->size > 0
  int start = pos + 1;
  while (start < ps->size)
  {
    ps->a[start - 1] = ps->a[start];
    start++;
  }
  ps->size--;
}
//修改顺序表pos位置的值
void SeqListMidefy(SeqList* ps, int pos, SLDatatype x)
{
  assert(ps);
  assert(pos >= 0 && pos < ps->size);//已经包含 ps->size > 0
  ps->a[pos] = x;
}

2.3 数组相关面试题

  1. 原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度为O(1)。OJ链接
  2. 删除排序数组中的重复项。OJ链接
  3. 合并两个有序数组。ОJ链接

2.4 顺序表的问题及思考

问题:


1.中间/头部的插入删除,时间复杂度为O(N)


2.增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。


3.增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。


思考:如何解决以上问题呢?可以通过看下一篇文章链表来解决。


本篇结束:

相关文章
|
22天前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
56 3
|
1月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
20 2
|
1月前
|
C语言
链式顺序表实现(C语言描述)
本文介绍了如何在C语言中实现链式顺序表,包括数据结构的定义、节点的创建、数据的插入和删除以及链表的打印和销毁。
39 2
|
1月前
|
C语言
顺序表数组法构建(C语言描述)
如何使用C语言通过数组方法构建有序顺序表,包括顺序表的创建、插入、删除和打印等。
20 2
|
2月前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
200 5
|
2月前
|
存储 算法 C语言
C语言手撕数据结构代码_顺序表_静态存储_动态存储
本文介绍了基于静态和动态存储的顺序表操作实现,涵盖创建、删除、插入、合并、求交集与差集、逆置及循环移动等常见操作。通过详细的C语言代码示例,展示了如何高效地处理顺序表数据结构的各种问题。
|
5月前
|
存储 C语言
数据结构——顺序表(C语言版)
数据结构——顺序表(C语言版)
64 5
|
6月前
|
存储 C语言
C语言实验-动态顺序表实现简易通讯录(二)
在这个C语言实验中,你将实现一个简单的通讯录,它使用动态顺序表来存储联系人信息。
51 2
|
6月前
|
存储 C语言
数据结构——顺序表(C语言)
数据结构——顺序表(C语言)
|
5月前
|
存储 C语言
数据结构之顺序表(C语言版)
数据结构之顺序表(C语言版)
28 0