博客ID:LanFuRen
C系列专栏:C语言重点部分 C语言注意点 C++基础 Linux 数据结构 C++注意点
声明等级:黑色->蓝色->红色欢迎新粉加入,会一直努力提供更优质的编程博客,希望大家三连支持一下啦
目录
今天我们来聊一聊顺序表,顺序表是数据结构的入门算法,不过依旧要拿出来深入细致地探讨一下。
1.线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中⼴泛使
⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
我们今天要了解的顺序表是物理结构和逻辑结构都是连续(线性)的,而数组是物理与逻辑结构都是线性的。顺序表的底层结构就是数组。
2.静态与动态顺序表
1)静态顺序表
静态顺序表的意思就是底层数组开辟的空间是已经定下来不可以修改的。如以下代码:
#define N 10 line 1
typedef int Datatype; line 2
typedef struct SeqList line 3
{ line 4
Datatype arr[N]; line 5
int size;//已经存储数据的数量 line 6
}SL; line 7
第一行,我们定义了一个宏N,注意书写的规范性,我们一般把宏用大写表示,这样可以突出常量的用法(高质量C/C++)。第二行typedef用来给类型取别名,这样在大型工程中相当于对类型一件替换。那第七行也是如此。因为顺序表之后的实现是需要size来记录已经存储数据的数量,所以用了一个变量size。
但是静态顺序表有一弊端就是空间的开辟过于死板,可能会出现开辟过大的空间致使空间的浪费,消耗虚拟内存。所以我们有一种更好的顺序表就是动态顺序表,动态有没有想到是动态内存管理那一节的知识呢?
2)动态顺序表
typedef int Datatype;
typedef struct SeqList
{
Datatype* arr;
int capacity;//已经开辟的空间大小
int size;//已经存储数据的数量
}SL;
跟静态顺序表的构建类似,但是数组变成了一级指针,在以后的malloc等一系列动态开辟之后就能开辟空间了。
3.完善静态顺序表内部方法
这里只提供了一些方法,大家有兴趣地可以自己去实现自己想要的方法哦。
void Init(SL* ps);//未初始化,所以传址(因为在第一次传入参数的时候,结构体和结构体变量是没有初始化的,这样是很危险的,所以我们考虑到了传址调用)
void PushBack(SL* ps, int x);//修改arr,我们需要修改空间数据,所以得需要该空间的地址,即修改arr,所以传址。
void PushFront(SL* ps, int x);
void Print(SL*ps);//保持接口一致性
void SLInsert(SL* ps, int pos, Datatype x);
void SLErase(SL* ps, int pos);
//简单的初始化方法
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->capacity = 0;
ps->size = 0;
}
//尾插(给开辟的空间尾部插入新数据x)
//扩容
void SLCheckCapacity(SL* ps)
{
if (ps->size == ps->capacity)//这两个的参数是值比较
{
int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
DataType* tmp = (DataType*)realloc(ps->arr, newcapacity * sizeof(DataType));
if (tmp == NULL) {
perror("realloc fail!");
exit(1);//开辟失败也要考虑
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
}
void SLPushBack(SL* ps, DataType x) {
assert(ps != NULL);
//空间不足
SLCheckCapacity(ps);
//空间足够
ps->arr[ps->size] = x;
ps->size++;
}
尾插代码要注意,结构体指针不能为空,即指向的结构体为空。
这里的扩容代码很细节,需要非常注意。我们realloc是2倍扩容,保证了空间不过度浪费。而且realloc有一个好处就是如果原来的空间不支持新扩容的空间大小,realloc会单独开辟一个新空间装下一共的空间大小并销毁原空间。还要注意:这里给了一个tmp指针,为的是假如开辟空间失败就停止,这样代码严谨性更高。
//尾删代码
void SLPopBack(SL* ps) {
assert(ps);
assert(ps->size);
ps->size--;
}
这个代码的思想在之后的头插也可以用到,只要我们把size进行挪动,那么我们读取数据是读不到size这里的,那么就相当于删除了,图示如下:
这些都是重点,其余的方法都是依靠这些思想来解决的。
http://t.csdnimg.cn/rFEFG 这是顺序表的方法,大家可以去看看。