顺序表
顺序表的1基本操作的代码在下文都有,并且经过初步测试,如果有大佬发现不对的地方,还望多多指正,谢谢。
1.线性表
线性表:n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结 构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物 理上存储时,通常以数组和链式结构的形式存储。(画图没弄整齐--^_^--)
顺序表:基本内容如图:
1概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组 上完成数据的增删查改。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储。 2. 动态顺序表:使用动态开辟的数组存储
#define Capacity 100 typedef int DataType; //表中保存的数据类型,在前面用typedef关键字再给类型名,方便一改全改 struct SeqList{ DataType array[Capacity]; //保存顺序表中元素,Capacity是数组总容量 size_t size; //记录有效元素个数 };
静态顺序表实质就是固定容量的数组加一个有效元素计数。
顺序表的具体操作以动态顺序表来展示:
typedef int DataType; //存放的数据类型 typedef struct SeqList{ DataType* _array; // 指向动态申请的数组空间 size_t _size; //记录有效元素个数 size_t _capacity; //记录容量,空间总大小 }SeqList;
int main() { //要用结构体定义一个变量,然后将顺序表地址交给指针,用指针对顺序表进行操作 SeqList S1; SeqListInit(&S1); //SeqList *ps = &S1; //和上面的效果是一样得 //SeqListInit(ps); return 0; }
顺序表的主要操作:初始化顺序表、销毁顺序表、检查容量和有效元素个数、尾插尾尾删、头插头删、任意下标插入、查找、删除、遍历、更改数据、更改容量等,扩展有在顺序表中进行排序、删除重复元素、合并两个或多个顺序表等。
//初始化 void SeqListInit(SeqList* ps) { if (NULL == ps) return; // assert(ps); 对指针进行判空 // 指针不为空,进行操作 ps->_array = (DataType*)malloc(sizeof(DataType)* 20); //申请空间 assert(NULL != ps->_array); //判断空间是否申请成功 ps->_capacity = 20; //空间申请成功,顺序表的容量为20个元素 ps->_size = 0; //有效元素为0 //因为是传指针,对原本的顺序表进行操作,所以不用返回值 }
初始化的容量可以更改,根据实际需要可以通过传参等等,不必一定是20。
//遍历顺序表 void SeqListPrint(SeqList* ps) { for (int i = 0; i < ps->_size; ++i) //遍历完所有有效元素即可 { printf("%d ", ps->_array[i]); } }
//顺序表销毁 void SeqListDestory(SeqList* ps) { if (NULL == ps) return; //指针为空则返回 free(ps->_array); //释放申请的空间 ps->_capacity = 0; //空间记录置为0 ps->_size = 0; //有效元素置为0 } //容量 size_t CheckCapacity(SeqList* ps) { if (NULL == ps) return 0; return ps->_capacity; } //有效元素个数 size_t CheckSize(SeqList* ps) { if (NULL == ps) return 0; return ps->_size; } //判断顺序变是否装满了,进行插入操作时,需要判断顺序变是否需要扩容 bool isFill(SeqList* ps) { if (ps->_capacity == ps->_size) return true; //满了返回真 return false; // 未满,返回假 } //扩容 不断的放入元素,可能会顺序表容量不够,需要扩容 void AddCapacity(SeqList* ps) { //扩容的方案是申请一个更大容量的新空间,然后更改顺序表中指针的指向,释放原空间 //需要对原空间的数据进行搬移(复制) //申请一个容量为原属性表中1.5倍的空间 DataType* new_array = (DataType*)malloc(sizeof(DataType)*(ps->_capacity*1.5)); assert(new_array); //判断是否申请成功 容量大小随需求而定,不必一定是倍 for (int i = 0; i < (ps->_size); ++i) { new_array[i] = ps->_array[i]; //元素搬移 } DataType* pf = ps->_array; //记录原空间,不然无法释放原空间 ps->_array = new_array; //让顺序表中的指针指向新空间 ps->_capacity = ps->_capacity*1.5; //容量计数更改 } //尾插 void SeqListPushBack(SeqList* ps, DataType x) { assert(ps); //断言ps不为空 if (isFill(ps)) //插入之前判断顺序表是否满了,已满则扩容 AddCapacity(ps); // 扩容 ps->_array[ps->_size] = x; //插入操作 ps->_size++; //插入操作完成后有效元素计数器加1 }
//尾删 void SeqListPopBack(SeqList* ps) { assert(ps && (ps->_size != 0)); //指针不为空,且顺序表中有效元素个数大于0 ps->_size--; //有效元素减1就是删除尾部元素 } //头插 void SeqListPushFront(SeqList* ps, DataType x) { assert(ps); if (isFill(ps)) //插入前判断是否顺序变是否满了,满了则扩容 AddCapacity(ps); //要在头部插入要防止将原本的元素覆盖,所以要将后面的元素往后搬移 for (int i = ps->_size; i > 0; --i) //从最后一个有效元素开始,每个往后搬移一位 { ps->_array[i] = ps->_array[i - 1]; } ps->_array[0] = x; //搬移完之后在首元素位置插入,完成头插 ps->_size++; //有效元素个数加1 } //头删 void SeqListPopFront(SeqList* ps) { assert( ps && (ps->_size != 0)); //头部删除元素,将后面每个元素往前挪一位就实现了头删操作 for (int i = 0; i < ps->_size; ++i) { ps->_array[i] = ps->_array[i + 1]; } ps->_size--; //删除元素之后有效元素计数减1 } //查找元素,找到返回元素所在下标 int SeqListFind(SeqList* ps, DataType x) { assert(ps); for (int i = 0; i < ps->_size; ++i) //到表中遍历,找到则结束循环 { if (ps->_array[i] == x) return i; } return -1; //没有在表中找到相应数据则返回-1,表示表中不存在该该元素 } void SeqListInsert(SeqList* ps, size_t pos, DataType x) { assert(ps && (pos < ps->_size)); if (isFill(ps)) AddCapacity(ps); //插入的位置应该是在最后一个有效元素的下一个位置到数组首元素,否则无法计算遍历 //在第一个位置时相当于头插,在最后一个位置时相当于尾插 //插入时将需要插入位置到最后一个有效元素都往后搬移一位 for (int i = ps->_size; i > pos; --i) { //pos位置的元素也要搬移 ps->_array[i] = ps->_array[i - 1]; } ps->_array[pos] = x; //搬移完之后插入元素 ps->_size++; } //删除指针下标元素 void SeqListErase(SeqList* ps, size_t pos) { assert(ps && (pos < ps->_size) && pos>=0); //删除首位置元素则相当于头删,删除尾部元素则相当于尾删 for (int i = pos; i < ps->_size; ++i) //将pos位置后的每一个元素往前挪一个位置,就相当于删除pos位置元素 { ps->_array[i] = ps->_array[i + 1]; } ps->_size--; } //删除指定元素, 此处只删除第一次出现 void SeqListRemove(SeqList* ps, DataType x) { assert(ps); int pos=SeqListFind(ps, x); //找到该元素的位置,元素存在则删除,不存在则返回或输出提示信息 if (pos != -1) //pos不等于-1表示元素在顺序表中 { SeqListErase(ps, pos); //删除 } else{ printf("元素不在表中"); } //SeqListErase(ps, SeqListFind(ps, x)); //也可以这样写,效果完全一样 //在此处重写一个函数也可以,通过遍历找到元素位置,然后进行删除,写法和前面的删除操作一样 } //删除表中等于x的所有元素 void SeqListRemoveAll(SeqList* ps, DataType x) { //遍历的方式比较麻烦,每次删除一个顺序表中元素个数发生变化 //因此使用一个新的表来装非x的元素,然后改变结构体中指针指向 assert(ps && (ps->_size != 0)); DataType* new_array = (DataType*)malloc(sizeof(DataType)*ps->_capacity); //c此处容量原则上大于原表中有效元素个数即可 int count = 0; for (int i = 0; i < ps->_size; ++i) { if (ps->_array[i]==x) count++; else { new_array[i-count] = ps->_array[i]; } } free(ps->_array); ps->_array = new_array; ps->_size = ps->_size - count; } //将指定位置元素修改为x void SeqListModify(SeqList* ps, size_t pos, DataType x) { assert(ps && (pos < ps->_size) && (pos >= 0)); ps->_array[pos] = x; }
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include"SeqList.h" #include<stdio.h> #include<stdlib.h>
//测试例子 int main() { SeqList S1; SeqListInit(&S1); for (int i = 0; i < 30; ++i) { SeqListPushBack(&S1, 1); SeqListPushBack(&S1, 5); } SeqListPushBack(&S1, 3); SeqListPushBack(&S1, 4); SeqListPushBack(&S1, 5); SeqListPushBack(&S1, 6); /* SeqListPrint(&S1); SeqListPopBack(&S1); SeqListPrint(&S1); SeqListPushFront(&S1, 9); SeqListPushFront(&S1, 8); SeqListPushFront(&S1, 7); SeqListPrint(&S1); SeqListPopFront(&S1); SeqListPrint(&S1); SeqListInsert(&S1,2, 7); SeqListPrint(&S1); SeqListErase(&S1, 2); SeqListPrint(&S1); SeqListRemove(&S1, 5); SeqListPrint(&S1)*/; SeqListRemoveAll(&S1, 5); SeqListModify(&S1, 5, 6); //int index = SeqListFind(&S1, 11); //printf("%d\n", index); system("pause"); return 0; }
住进火焰就成为萤火虫。