顺序表
一:前言(初步认识)
- 1.1 顺序表概念
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用 数组 存储。在数组上完成数据的增删查改。- 1.2 顺序表一般可以分为:
a. 静态顺序表:使用定长数组存储。
b. 动态顺序表:使用动态开辟的数组存储。
二:代码实现
A:顺序表的两种定义方式
首先定义一个全局变量
typedef int SDataType;
- a.定义静态存储结构
typedef struct SeqList{
//静态顺序表定义
int array[100]; // 能存 100 个数的静态顺序表
int size; //当前顺序表中存放的数,顺序表为空size=0
//顺便表示了即将插入的下标
} Seqlist;
- b.定义动态存储结构
typedef struct SeqList{
//动态顺序表定义
SDataType *array;
int size; //当前顺序表中存放的数,顺序表为空size=0,当顺序表不为空是表示数据中元素的下标
int capacity; //顺序表的容量
} SeqList;
B:顺序表的初始化与销毁
a:初始化
void SeqListInit(SeqList *seqlist, int capacity){
assert(seqlist != NULL);
seqlist->array = (SDataType*)malloc(sizeof(SDataType)*capacity);
seqlist->size = 0;
seqlist->capacity = capacity;
}
- 首先需要申请空间,而参数中的 capacity 指的是你在初始化时所需要的空间大小。
b:销毁建立的顺序表
- 代码
void SeqListDestroy(SeqList *seqlist){
assert(seqlist != NULL);
assert(seqlist->array!=NULL);
seqlist->array = NULL;
seqlist->size = 0;
seqlist->capacity = 0;
free(seqlist->array); //重点
}
- 辅助理解
- 在销毁时只需要将指向定义数组的指针设置为空(而非将顺序表中的元素一个一个的往掉删除),并且将记录顺序表中元素数量的 size 置为 0 。
- 将申请的空间释放。(必须释放,不然会造成内存泄漏)
C:增(往顺序表中添加元素)
a:头插
- 代码
//头插
//1.从后往前搬,避免覆盖
//2.写循环
// 先确定循环的边界
// i 空间下标[size,0)
// i 数据下标[size-1,0]
//3. 搬移
// i对应空间下标: array[i]=array[i-1];
// i对应数据下标: array[i+1]=array[i];
void SeqListPushFront(SeqList *seqlist, SDataType value){
assert(seqlist != NULL);
assert(seqlist->array != NULL);
for (int i = seqlist->size ; i > 0; i--){ //做数据的搬移,i代表空间下标
seqlist->array[i] = seqlist->array[i - 1];
}
seqlist->array[0] = value;
seqlist->size++;
}
- 辅助理解
- 在进行头插运算时,需要考虑将原来顺序表中的元素从最后一位开始往后挪动一位,防止数据的丢失。
(若从第一位开始挪动,则会造成数的丢失。当打印时打印出来的顺序表元素全都是一个数字)
如下例中将value插入数组首地址时,应按顺序将数组中的元素往后移,然后再家将value的值插入。
b:尾插
- 代码
void SeqListPushBack(SeqList *seqlist, SDataType value){
assert(seqlist != NULL);
assert(seqlist->array != NULL);
CheckCapccity(seqlist);
seqlist->array[seqlist->size] = value;
seqlist->size++;
}
//尾插时直接将 value 的值插入到顺序表的最后一位即可。
c: 从指定的位置 (position)处插入value
- 代码示例
void SeqListInsert(SeqList *seqlist, int pos, SDataType value){
assert(seqlist != NULL);
assert(seqlist->array != NULL);
assert(pos >= 0 && pos <= seqlist->size); //检查要插入的位置是否合法
for (int i = seqlist->size - 1; i >= pos; i--){
seqlist->array[i+1] = seqlist->array[i];
}
//做数组搬移,将pos位置往后的元素按顺序依次从往后移动一位
seqlist->array[pos] = value;
seqlist->size++;
}
D: 删(从顺序表中删除制定的元素)
a:头删
- 代码示例
//头删
//1.从后往前搬,避免覆盖
//2.写循环
// 先确定循环的边界
// i 空间下标 [0,size-2]
// i 数据下标 [1,size-1]
//3. 搬移
// i对应空间下标: array[i-1]=array[i];
// i对应数据下标: array[i]=array[i+1];
void SeqListPopFront(SeqList* seqlist){
assert(seqlist != NULL);
assert(seqlist->array != NULL);
assert(seqlist->size > 0);
//i 代表的是空间下标
for (int i = 1; i <seqlist->size ; i++){
seqlist->array[i - 1] = seqlist->array[i];
}
seqlist->size--;
}
b:中间删除(指定位置删除某位置元素)
- 代码示例
//删除 pos 所在的下标数据
void SeqListErase(SeqList *seqlist, int pos){
assert(seqlist!=NULL);
assert(seqlist->array!=NULL);
assert(seqlist ->size>0);
assert(pos >= 0 && pos < seqlist->size);
//做数据的搬移,因为是将指定位置的元素删除既可直接将其覆盖
for (int i = pos; i <seqlist->size; i++){
seqlist->array[i] = seqlist->array[i+1];
}
seqlist->size--;
}
c:尾删
- 代码示例
void SeqListPopBack(SeqList*seqlist){gai
assert(seqlist!=NULL);
assert(seqlist->array!=NULL);
assert(seqlist->size > 0);
seqlist->size--;
}
E:改(修改pos 所在下标的所在数据)
- 代码示例
//修改pos 所在下标的所在数据为 value
void SeqListModify(SeqList *seqlist, int pos, SDataType value){
assert(pos>=0&&pos<seqlist->size);
seqlist->array[pos] = value;
}
F:查(查找指定元素)
a:查找
- 代码示例
//查找
//如果找到,返回第一个找到的下标
//如果没找到返回-1
int SeqListFind(const SeqList *seqlist, SDataType value){
assert(seqlist!=NULL);
for (int i = 0; i < seqlist->size;i++){
if (seqlist->array[i] == value)
return i;
}
return -1;
}
b:找到并删除第一个遇到的 value
- 代码示例
void SeqListRemove(SeqList *seqlist, SDataType value){
int pos = SeqListFind(sqlist,value);
if (pos != -1){
SeqListErase(seqlist,pos);
}
}
- 以上即为数据结构顺序表中最基本的操作增 、删、改、查四种操作的代码示例。
尽管理解起来比较抽象,但是只用自己敲一遍,并且理解透彻的话。你会发现也没有想象中的那么难以理解。
此链接是我自己搭建的hexo博客,关于该片博客的详尽版(当然内容更加丰富,排版更加漂亮了)。
https://jack-wang128801.github.io/2019/03/14/数据结构/