1.线性表 :(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串等。线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
2.顺序表:
概念与结构:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。顺序表的本质就是数组,动态增长,并且要求里面存储的数据必须是从左往右连续的。逻辑结构与物理结构是一致的。
逻辑结构和物理结构的概念:
- 逻辑结构: 人为想象出来的,实际并不存在.
- 物理结构: 实际存在,可以被观察到
顺序也分成静态和动态:
1.静态顺序表:使用定长数组存储。
2.动态顺序表:使用动态开辟的数组存储,容量不受限制,支持数据插入,删除,修改等一系列操作,简单一点就四个字:增删查改!
建立三个文件
先搭建好数据结构体框架:
typedef int SQDataType; typedef struct SeqList { SQDataType* data; int size; int capacity; }SL;
为什么要用typedef?万一数据是char、int、double等,每个接口函数是不是还得一个一个修改啊,是不是麻烦死了,所以一开始我们就确定了结构体中的变量类型,后续在项目过程中如果需要对这个变量类型进行调整,那么所需的操作是很繁琐的。故使用typedef,后续若是需要修改,改动typedef就足够了。
顺序表初始化:
在初始化当中要注意一点:看代码
//SeqList.c void SeqListInit(SL ps) { ps.a=NULL; pa.size=ps.capacity=0; } //test.c int main() { SL plist; SeqListInit(plist); return 0; }
这种初始化方式显然不行,大家可以回想下函数传参的内容,函数内的ps
只是plist
的一份临时拷贝,此时拷贝量的改变不会影响plist
。那我们想要改变plist怎么办?答案:传址!
修改后:
//SeqList.c void SeqListInit(SL* ps) { assert(ps); //加个判断,ps不能为空指针,为空报错 ps->a = NULL; ps->size = ps->capacity = 0; } //test.c int main() { SL plist; SeqListInit(&plist); return 0; }
顺序表的增容:
1.首先检查是否容量已经满了(ps->size == ps->capacity)
2.如果没满就无所谓,如果满了并且ps->capacity!=0
,就增加容量,增加方式是2倍增加,如果满了并且ps->capacity=0
,说明还是空容量,就增加4个空间。
void SeqListCheckCapacity(SL* ps) { if(ps->size == ps->capacity) { //如果capacity为0就给他4个空间,否则进行2倍增容. int newcapacity = ps->capacity == 0 ? 4:ps->capacity*2; ps->data =(SQDataType*)realloc(ps->data,sizeof(SQDataType)*newcapacity); ps->capacity = newcapacity;//容量要更新 } }
顺序表的尾插:
1.和初始化类似,需要进行传址。
2.检查顺序表是否还有容量。
3.在最后一个位置上插入新数据
void SeqListPushBack(SL* ps,SQDataType val) { assert(ps); SeqListCheckCapacity(ps);//检查容量是否足够,不够就增容 ps->data[ps->size] = val; //尾部插入 ps->size++;//实际容量加1 }
顺序表的头插:
1.和初始化类似,需要进行传址。
2.检查顺序表是否还有容量。
3.挪动数据,给第一个位置空出来,在空出来的位置上插入新数据
void SeqListPushFront(SL* ps,SQDataType val) { assert(ps); SeqListCheckCapacity(ps);//检测是否还有空间 for(int i= ps->size;i>0;i--) { ps->data[i] = ps->data[i-1]; } ps->data[0] = val; ps->size++; }
顺序表的尾删:很简单,直接让ps->size-1
即可。
void SeqListPopBack(SL* ps) { assert(ps->size > 0); //必须保证有数据可以删除 ps->size--; }
顺序表头删:直接挨个把数据向前挪进行覆盖,然后ps->size-1
void SeqListPopFront(SL* ps) { assert(ps->size > 0); for(int i= 0;i<ps->size-1;i++) { ps->data[i] = ps->data[i+1]; } ps->size--; }
顺序表查找操作:
1.给一个元素,查找是否在顺序表内,如果在,返回下标.
2.如果不在,返回-1
int SeqListFind(SL* ps,SQDataType val) { assert(ps->size > 0); assert(ps); for(int i= 0;i<ps->size;i++) { if(ps->data[i] == val) return i; } return -1; }
顺序表的插入操作:
函数包含:指定插入下标,和想插入的元素
实现方法: 输入的下标位置及其后,所有数据都往后面挪,然后插入数据,ps->size+1
void SeqListInsert(SL* ps,size_t pos,SQDataType val) { assert(ps); assert(ps->size >= pos); //被插入的位置必须小于等于size SeqListCheckCapacity(ps); //检查容量 for(int i = ps->size;i>pos;i--) { ps->a[i] = ps->a[i-1]; } ps->a[pos] = val; ps->size++; }
顺序表删除操作:
函数包含:指定被删除元素的下标
实现方法: 直接覆盖被删除元素,并挨个往前覆盖,然后ps->size-1
void SeqListErease(SL* ps,size_t pos) { assert(ps); assert(ps->size > 0);//必须有元素可以删除 for(int i = pos;i< ps->size-1;i++) { ps->data[i] = ps->data[i+1]; } ps->size--; }
顺序表的元素个数:
int SeqListSize(SL* ps) { assert(ps); return ps->size; }
顺序表某个元素修改操作:
void SeqListAt(SL* ps, size_t pos, SQDataType val) { assert(ps); assert(pos < ps->size); ps->a[pos] = val; }
顺序表的销毁操作:
void SeqListDestroy(SL* ps) { assert(ps); if(ps->data != NULL) { free(ps->data); ps->data = NULL; } ps->size = ps->capacity = 0; }
以上是动态顺序表:增加数据都要检查容量,删除数据就不必了;
静态顺序表代码如下:(不是重点,了解一下)超纲:涉及到了C++布尔值(bool)和引用(&)
还有头文件改成 ( test.cpp ) bool和& 是C++里的
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define MaxSize 10 #define SQDataType int typedef struct { SQDataType data[MaxSize];//数组的大小 int length;//长度 }SqList; //尾删 bool Delete(SqList* L) { if (L->length == 0) { printf("空间没有数据,删除失败\n"); return false; } L->data[L->length - 1] = 0; L->length--; return true; } //头删 bool Erase(SqList* L) { if (L->length == 0) { printf("空间没有数据,删除失败\n"); return false; } for (int i = 0; i < L->length-1; i++) { L->data[i] = L->data[i + 1]; } L->length--; return true; } //头插 bool Insert(SqList* L, SQDataType x) { if (L->length == MaxSize) { printf("空间已满,插入失败\n"); return false; } for (int i = L->length - 1; i >= 0; i--) { L->data[i + 1] = L->data[i]; } L->data[0] = x; L->length++; return true; } //尾插 bool Push_back(SqList* L, SQDataType x) { if (L->length == MaxSize) { printf("空间已满,插入失败\n"); return false; } L->data[L->length] = x; L->length++; return true; } //静态初始化 void InitList(SqList* L) { for (int i = 0; i < MaxSize; i++) { L->data[i] = 0; } L->length = 0; } //插入元素 bool ListInsert(SqList* L, SQDataType i, SQDataType e) { if (i < 1 || i > L->length + 1) return false; if (L->length >= MaxSize) return false; for (int j = L->length; j >= i; j--) { L->data[j] = L->data[j - 1]; } L->data[i - 1] = e; L->length++; return true; } //删除元素 bool ListDelete(SqList* L, SQDataType i, SQDataType &e) { if (i<1 || i>L->length) return false; e = L->data[i - 1]; for (int j = i; j < L->length; j++) { L->data[j - 1] = L->data[j]; } L->length--; return true; } //拿到第几位数字 SQDataType GetList(SqList L, SQDataType i) { return L.data[i - 1]; } //判断数字在哪个位置 SQDataType LocateElem(SqList L, SQDataType e) { for (int i = 0; i < L.length; i++) { if (L.data[i] == e) return i + 1; } return 0; } //打印 void Print(SqList* L) { for (int i = 0; i < L->length; i++) { printf("%d ", L->data[i]); } printf("\n"); }
数据结构的顺序表内容到此设计结束了,感谢您的阅读!!!
如果内容对你有帮助的话,记得给我三连(点赞、收藏、关注)——做个手有余香的人。谢谢大家的支持!!!