一.顺序表的线性结构:
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储;即通过数据元素物理存储的连续性来反应元素之间逻辑上的相邻关系。
采用顺序存储结构存储的线性表通常简称为顺序表。
二.顺序表的特点:
1.空间连续;
2.支持随机访问;
3.在中间或前面部分的插入删除时间复杂度为O(n),增容的代价比较大;
4.顺序表的优点:更适合频繁访问第n个元素的场景;
(1)根据下标随机访问时间复杂度为O(1);
(2)不会造成内存碎片化;
(3)缓存更优化;
(4)代码简单;
三.顺序表的存储结构示意图:
假设线性表中有n个元素,每个元素占k个单元;则第一个元素的地址为Loc(a1),第i个元素的地址为Loc(ai);
Loc(ai)=Loc(a1) + (i-1) * k; Loc(a1)称为基地址;
四.顺序表的分类:
顺序表分为静态顺序表和动态顺序表;
静态顺序表:使用定长的数组进行存储;
#define N 100
typedef int SLDataType;
typedef struct Seqlist{
SLDataType array[N]; //定长数组;
int size; //有效数字的个数;
} Seqlist;
动态顺序表:使用动态开辟的内存进行存储;
typedef int SLDataType;
typedef struct Seqlist{
SLDataType* array; //指向动态开辟的数组;
int size; //有效数据的个数;
int capacity; //容量的空间大小;
}Seqlist;
五.顺序表的基本操作:
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多 了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小;
1.顺序表的初始化:
顺序表的初始化过程就是申请内存空间,把空间容量和有效数据设为0;
void SeqlistInit(Seqlist *seqlist,int capacity){
assert(seqlist!=NULL);
seqlist->array=(SLDataType*)malloc(sizeof(SLDataType)*capacity);
seqlist->capacity=capacity;
seqlist->size=0;
}
2.顺序表的销毁:
顺序表的销毁就是释放申请的内存空间;
void SeqlistDestory(Seqlist *seqlist){
assert(seqlist!=NULL);
assert(array!=NULL);
free(seqlist->array); //释放空间
seqlist->size=0;
seqlist->capacity=seqlist->size=0;
}
3.顺序表的头插:
顺序表的头插就是将数据整体往后移动,然后把指定数插到数组的第一个位置;注意在移动的时候从数组的最后一个元素移动,如果从第一个移动会覆盖数组元素;
void SqlistPushFront(Sqlist * sqlist, SLDataType num){
CheckCapaticy(seqlist); //检查顺序表的容量;
for(int i=capacity->size;i>=1;++i){
seqlist->array[i]=seqlist->array[i-1]; //头插;
}
seqlist->array[0]=num;
seqlist->size++;
}
4.顺序表的尾插:
顺序表尾插时定数组长,然后把该数放到数组的size位置;
void SeqlistPushBack(Seqlist *seqlist,SLDataType num){
CheckCapacity(seqlist);
seqlist->array[seqlist->size]=num;
seqlist->size++;
}
5.顺序表中间插入:
顺序表的中间插入将该插入位置的以后的所有数组元素向后移一个位置;
void SeqlistPushInsert(Seqlist* seqlist,int post,SLDataType num){
assert(post>0 && post<=seqlist->size);
for(int i>pose;i=sqlist->size;--i){
seqlist->array[i]=seqlist->array[i-1];
}
seqlist->
array[post]=num;
++size;
}
6.顺序表尾删:
void SeqlistPopBack(Seqlist *seqlist){
assert(seqlist!=NULL);
assert(seqlist->size>0);
seqlist->size--;
}
7.顺序表的头删:
删除顺序表中的第一个元素,只要将顺序表中的元素从第2个开始,依次向前移动1位,覆盖原来顺序表中元素对应位置的前一个值,在删除元素之前要判断顺序表是否为空,删除顺序表元素之后将顺序表长度seqlist->size–;
void SeqlistPopFront(Seqlist *seqlist){
assert(seqlist!=NULL);
assert(seqlist->size>0);
for(int i=0;isize-1;++i){
seqlist->array[i]=seqlist->array[i+1];
}
seqlist->size--;
}
8.顺序表的中间删除:
顺序表的中间删除过程,删除指定数组元素后将该位置以后的元素向前移动一个位置;
void SeqlistPopInsert(Seqlist *seqlist, int pose,SLDataType){
assert(seqlist!=NULL);
assert(post>0 && post<=seqlist->size-1);
assert(size>0);
for(int i>post,i=seqlist->size-2;++i){
seqlist->array[i]=seqlist->array[i+1];
}
seqlist->size--;
}
9.查找:返回第一个遇到num的下标,否则返回-1;
通过对数组进行遍历查找;查找数据元素num在表中的位置,可以从表头开始一直遍历表中元素,如果找到与要查找元素e相等的元素,则返回元素在表中的位置,数组下标从0开始,则元素在表中对应的位置序号值应为对应数组下标加1,没有找到则返回-1;
int SeqlistFind(Seqlist * seqlist,SLDataType num){
for (int i=0;isize-1;++i){
if(seqlist->size[i]==num){
return i;
}
return -1;
}
10.删除:删除所有遇到的num;
void SeqlistRemoveAll(Seqlist *seqlist, SLDataType num){
int i, j;
for (int i = 0, j = 0; i < seqlist->size; ++i){
if (seqlist->arr[i] != num){
seqlist->arr[j] = seqlist->arr[i];
j++;
}
}
seqlist->size = j;
}
关于顺序表的完整代码:
Seqlist.h文件;
#pragma once
//静态顺序表:顺序表的容量是在编译期间(或静态期间)决定的。----写死在代码里的;
typedef struct Seqlist{
int arr[100]; //容量是100
int size; //表示数据结构中存储已有的个数;
//顺便表示了顺序表,最后插入的数据的下标;
}Seqlist;
typedef int SLDataType; //动态顺序表:顺序表的容量是在运行期间(动态)决定的;
typedef struct Seqlist{
SLDataType *arr; //初始化的时候在堆上开辟一个空间用来保存要存的数据;
int capacity; //容量;表示顺序表上一共能存多少数据;
int size; //表示顺序表中的有效顺序有多少个;
}Seqlist;
void SeqlistInit(Seqlist *seqlist, int capacity); //初始化过程
void SeqlistDestroy(Seqlist *seqlist); //销毁的过程
//插入过程;
void SeqlistPushBack(Seqlist *seqlist, SLDataType num); //尾插
SeqlistPushFront(Seqlist* seqlist,SLDataType num); //头插;
void SeqliatPushInsert(Seqlist *seqlist,int pose, SLDataType num); //中间插入;
//删除过程;
void SeqlistPopBack(Seqlist *seqlist); //表示尾删;
void SeqlistPopFront(Seqlist *seqlist); //表示头删;
void SeqlistPopErase(Seqlist* seqlist, int pose); //表示中间删除;
//修改;
//line 内联函数;
inline void SeqlistModify(Seqlist* seqlist, int pose, SLDataType num){
seqlist->arr[pose] = num;
}
//查找;返回遇到第一个num的下标,没找到返回-1;
inline int SeqListFind(Seqlist *seqlist, SLDataType num){
for (int i = 0; i < seqlist->size; ++i){
if (seqlist->arr[i] == num){
return i;
}
}
return -1;
}
#include //打印;
inline int SeqlistPrint(const Seqlist * seqlist){
for (int i = 0; i < seqlist->size; ++i){
printf("%d", seqlist->arr[i]);
}
printf("\n");
}//
删除第一次遇到的num;
void SeqlistRemove(Seqlist * seqlist, SLDataType num);
//删除遇到的所有num;
void SeqlistRemoveAll(Seqlist *seqlist, SLDataType num){
int i, j;
for (int i = 0, j = 0; i < seqlist->size; ++i){
if (seqlist->arr[i] != num){
seqlist->arr[j] = seqlist->arr[i];
j++;
}
}
seqlist->size = j;
}
Seqlist.c文件:
#include "SeqList.h"
#include
#include
#include
//static 修饰函数更改链接属性,从外部链接属性改变为内部链接属性;
//检查数据是否需要扩容,如果需要则进行扩容;
static void CheckCapacity(Seqlist *seqlist){
if (seqlist->size < seqlist->capacity){
return;
}
}
//需要扩容的情况:
//申请新空间;
int newCapaticy =2 * seqlist->capacity;
SLDataType *newArray = (SLDataType*)malloc(sizeof(SLDataType)) * newCapacity;
for (int i = 0; i < seqlist->size; ++i){
newArray[i] = seqlist->arr[i];
}
//释放老空间,把新空间绑定到顺序表结构体;
free(seqlist->arr);
seqlist->arr = newArray;
//更新容量;
seqlist->capacity = newCapaticy;
//初始化过程:
void SeqlistInit(Seqlist *seqlist, int capacity){
//在堆上分配顺序表的空间;
//初始化容量,size字段;
assert(seqlist != NULL);
seqlist->arr = (SLDataType*)malloc(sizeof(SLDataType)*capacity);
seqlist->capacity = capacity;
seqlist->size = 0;
}
//销毁过程
void SeqlistDestroy(Seqlist *seqlist){
//释放顺序表的存储空间;
//额外工作,把字段 reset 为初始值;
assert(seqlist != NULL);
assert(seqlist->arr != NULL);
free(seqlist->arr);
//锦上添花
seqlist->arr = NULL;
seqlist->capacity = seqlist->size = 0;
}
//尾插;
void SeqlistPushBack(Seqlist *seqlist, SLDataType num){
CheckCapaticy(seqlist);
seqlist->arr[seqlist->size] = num;
seqlist->size++;
}
//头插;
void SeqlistPushFront(Seqlist* seqlist, SLDataType num){
CheckCapaticy(seqlist);
//数据的移动过程;
for (int i = seqlist->size; i >= 1; ++i){ //空间的过程
seqlist->arr[i] = seqlist->arr[i - 1];
}
seqlist->arr[0] = num;
seqlist->size++;
}
//中间插入;
void SeqliatPushInsert(Seqlist *seqlist,int pose, SLDataType num){
assert(pose >= 0 && pose <= seqlist->size);
CheckCapacity(seqlist);
for (int i = seqlist->size; i > pose; --i){
seqlist->arr[i] = seqlist->arr[i-1];
}
seqlist->arr[pose] = num;
seqlist->size++;
}
//尾删过程;
void SeqlistPopBack(Seqlist *seqlist){
assert(seqlist != NULL);
assert(seqlist->size >0);
seqlist->size--;
}
//头删过程:
void SeqlistPopFront(Seqlist *seqlist){
assert(seqlist != NULL);
assert(seqlist->size > 0);
for (int i = 0; i < seqlist->size - 1; i++){
seqlist->arr[i] = seqlist->arr[i + 1];
}
seqlist->size--;
}
//中间删除;
void SeqlistPopErase(Seqlist* seqlist, int pose){
assert(seqlist != NULL);
assert(seqlist->size>0);
assert(pose = 0 && pose <= seqlist->size - 1);
for (int i = pose; i <= seqlist->size - 2; ++i){
seqlist->arr[i] = seqlist->arr[i + 1];
}
seqlist->size--;
}
//删除第一个遇到的num;
void SeqlistRemove(Seqlist * seqlist, SLDataType num){
int pose = SeqlistFind(seqlist, num);
if (pose == -1){
SeqlistPopErase(seqlist, pose);
}
}