目录
线性表:全名线性存储结构
线性存储结构分为顺序存储结构和链式存储结构,前者称为顺序表,后者称为链表
顺序表就是把线性表中的所有元素按照某种逻辑顺序,依次存储到指定位置的一块连续的存储空间。
用于存储逻辑关系为“一对一”的数据
用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),包括数据与和指针域。数据域存储数据,指针域存储后继的信息。
- 静态顺序表:使用定长数组存储
- 动态顺序表:使用动态开辟的数组存储

给少了不够用 ,给多了用不完,不能灵活控制

- 如果空间不够,增容。增容会付出一定性能消耗,其次可能存在一定的空间浪费
- 头部或者中部左右的插入和删除效率低
- 空间上,按需给空间
- 不要求物理空间的连续(比如使用链表)
- //初始化
- void SeqListInit(SL* psl)
- {
- assert(psl);//这里严格要加上断言,防止在代码行数过多时,传参错误,使我们知道错误发生在那
- psl->a = NULL;
- psl->capacity = 0;
- psl->sizel = 0;
- }
- //增容
- void SeqListCheckCapacity(SL* psl)
- {
- assert(psl);
- if (psl->capacity == psl->sizel)
- {
- int newcapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
- SQDataType* temp = (SQDataType*)realloc(psl->a, newcapacity * sizeof(SQDataType));
- //realloc将第一个参数的值依次存入所申请的空间
- assert(temp);
-
- psl->a = temp;
- psl->capacity = newcapacity;
- }
- }
-
- //尾插
- void SeqListPushBack(SL* psl, SQDataType x)
- {
- assert(psl);
- SeqListCheckCapacity(psl);//判断capacity是否足够,若不够进行增容
- psl->a[psl->sizel] = x;
- psl->sizel++;
- }
使用常规的for循环进行增容。
- void SeqListPushFront(SL* psl, SQDataType x)
- {
- assert(psl);
- SeqListCheckCapacity(psl);//增容
- for (int i = psl->sizel-1; i >= 0; i--)
- {
- psl->a[i + 1] = psl->a[i];
- }
- psl->a[0] = x;
- psl->sizel++;
- }
使用memmove函数,以字节为单位,拷贝链表,使其每个元素的位置增加一个SQDataType的大小。
- //头插——方法2
- void SeqListPushFront(SL* psl, SQDataType x)
- {
- assert(psl);
- SeqListCheckCapacity(psl);//增容
- memmove(&(psl->a[1]), psl->a, psl->sizel * sizeof(SQDataType));
- psl->a[0] = x;
- psl->sizel++;
- }
这里同样可以使用两种方法,这里我使用了最方便的memmove
判断方法2可以准确的给出错误的位置,方便在代码行数过多时,找出错误
判断方法1只是在发现出错后退出函数,不利于修改错误。
大多情况我们使用方法2.
- //头删
- void SeqListPopFront(SL* psl)
- {
- assert(psl);
- //判断方法1:温柔检查
- //if (psl->size == 0)
- //{
- // printf("顺序表以为空,无法删除!\n");
- // return;
- //}
-
- //判断方法2:暴力检查
- assert(psl->sizel > 0);//判断顺序表中是否有数据
- memmove(psl->a, &(psl->a[1]), (psl->sizel - 1) * sizeof(SQDataType));
- //psl->a[psl->sizel - 1] = 0;
- //这行代码有点多余,下次尾插的值为0时将毫无意义,而顺序表是通过size1访问的,改变size1即可
- psl->sizel--;
- }
- //尾删
- void SeqListPopBack(SL* psl)
- {
- assert(psl);
- //判断方法1:温柔检查
- //if (psl->size == 0)
- //{
- // printf("顺序表以为空,无法删除!\n");
- // return;
- //}
-
- //判断方法2:暴力检查
- assert(psl->sizel > 0);//判断顺序表中是否有数据
- psl->a[psl->sizel - 1] = NULL;
- psl->sizel--;
- }
使用memmove函数调整表中元素位置后插入
- //选择插入
- void SeqListInsert(SL* psl, int index, SQDataType x)
- {
- assert(psl);
- assert(pos <= psl->sizel);
- SeqListCheckCapacity(psl);//增容
- memmove(&(psl->a[index + 1]), &(psl->a[index]), (psl->sizel - index) * sizeof(SQDataType));
- psl->a[index] = x;
- psl->sizel++;
- }
使用循环依次移动元素最终插入
- //选择插入
- void SeqListInsert(SL* psl, int index, SQDataType x)
- {
- assert(psl);
- assert(index <= psl->sizel);//判断index范围是否合法
- SeqListCheckCapacity(psl);//增容
- int cou = psl->sizel;
- while (cou > index)
- {
- psl->a[cou] = psl->a[cou - 1];
- cou--;
- }
- psl->a[index] = x;
- psl->sizel++;
- }
使用memmove函数覆盖所要删除的位置
- //选择删除
- void SeqListErase(SL* psl, int index)
- {
- assert(psl);
- assert(index < psl->sizel);
- memmove(&(psl->a[index]), &(psl->a[index + 1]), (psl->sizel - index - 1) * sizeof(SQDataType));
- psl->a[psl->sizel - 1] = NULL;
- psl->sizel--;
- }
在顺序表中查找x,若找到返回下标,找不到则说明顺序表中没有改值
- //查找
- void SeqListFind(SL* psl, SQDataType x)
- {
- assert(psl);
- int num = 0;
- while (num < psl->sizel)
- {
- if (psl->a[num] == x)
- {
- printf("%d\n", num);
- return;
- }
- num++;
- }
- printf("表中没有%d\b", x);
- return;
- }
给出要修改元素的下标和替换的值,进行替换操作。
- //修改
- void SeqListModity(SL* psl, int pos, SQDataType x)
- {
- assert(psl);
- assert(pos < psl->sizel && pos > 0);//判断给出的下标是否在范围内
- psl->a[pos] = x;
- }
在头文件定义,存放函数、头文件和结构体的声明
- #pragma once
- #include
- #include
- #include
- #include
-
- #define N 10;
- typedef int SQDataType;
-
- typedef struct SeqList
- {
- SQDataType* a;
- int sizel; //有效数据个数
- int capacity; //容量
- }SL;
-
- //初始化
- void SeqListInit(SL* psl);
-
- //尾插入
- void SeqListPushBack(SL* psl, SQDataType x);
-
- //头插入
- void SeqListPushFront(SL* psl, SQDataType x);
-
- //头删
- void SeqListPopFront(SL* psl);
-
- //尾删
- void SeqListPopBack(SL* psl);
-
- //选择插入
- void SeqListInsert(SL* psl, int index, SQDataType x);
-
- //选择删除
- void SeqListErase(SL* psl, int index);
-
- //查找
- void SeqListFind(SL* psl, SQDataType x);
-
- //修改
- void SeqListModity(SL* psl, int pos, SQDataType x);
-
- //打印
- void SeqListPrint(SL* psl);
-
- //销毁空间
- void SeqListDestroy(SL* psl);
函数的实现放在此文件
- #define _CRT_SECURE_NO_WARNINGS 1
- #include "SeqList.h"
-
- //初始化
- void SeqListInit(SL* psl)
- {
- psl->a = NULL;
- psl->capacity = 0;
- psl->sizel = 0;
- }
-
- //增容
- void SeqListCheckCapacity(SL* psl)
- {
- if (psl->capacity == psl->sizel)
- {
- int newcapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
- SQDataType* temp = (SQDataType*)realloc(psl->a, newcapacity * sizeof(SQDataType));
- assert(temp);
-
- psl->a = temp;
- psl->capacity = newcapacity;
- }
- }
-
- //尾插
- void SeqListPushBack(SL* psl, SQDataType x)
- {
- SeqListCheckCapacity(psl);//判断capacity是否足够,若不够进行增容
- psl->a[psl->sizel] = x;
- psl->sizel++;
- }
-
- //头插——方法1
- //void SeqListPushFront(SL* psl, SQDataType x)
- //{
- // SeqListCheckCapacity(psl);//增容
- // for (int i = psl->sizel-1; i >= 0; i--)
- // {
- // psl->a[i + 1] = psl->a[i];
- // }
- // psl->a[0] = x;
- // psl->sizel++;
- //}
-
- //头插——方法2
- void SeqListPushFront(SL* psl, SQDataType x)
- {
- SeqListCheckCapacity(psl);//增容
- memmove(&(psl->a[1]), psl->a, psl->sizel * sizeof(SQDataType));
- psl->a[0] = x;
- psl->sizel++;
- }
-
- //头删
- void SeqListPopFront(SL* psl)
- {
- assert(psl->sizel > 0);//判断顺序表中是否有数据
- memmove(psl->a, &(psl->a[1]), (psl->sizel - 1) * sizeof(SQDataType));
- psl->a[psl->sizel - 1] = 0;
- psl->sizel--;
- }
-
- //尾删
- void SeqListPopBack(SL* psl)
- {
- assert(psl->sizel > 0);//判断顺序表中是否有数据
- psl->a[psl->sizel - 1] = NULL;
- psl->sizel--;
- }
-
- //选择插入
- //void SeqListInsert(SL* psl, int index, SQDataType x)
- //{
- // assert(index <= psl->sizel);
- // SeqListCheckCapacity(psl);//增容
- // memmove(&(psl->a[index + 1]), &(psl->a[index]), (psl->sizel - index) * sizeof(SQDataType));
- // psl->a[index] = x;
- // psl->sizel++;
- //}
-
- //选择插入
- void SeqListInsert(SL* psl, int index, SQDataType x)
- {
- assert(index <= psl->sizel);
- SeqListCheckCapacity(psl);//增容
- int cou = psl->sizel;
- while (cou > index)
- {
- psl->a[cou] = psl->a[cou - 1];
- cou--;
- }
- psl->a[index] = x;
- psl->sizel++;
- }
-
- //选择删除
- void SeqListErase(SL* psl, int index)
- {
- assert(index < psl->sizel);
- memmove(&(psl->a[index]), &(psl->a[index + 1]), (psl->sizel - index - 1) * sizeof(SQDataType));
- psl->a[psl->sizel - 1] = NULL;
- psl->sizel--;
- }
-
- //查找
- void SeqListFind(SL* psl, SQDataType x)
- {
- int num = 0;
- while (num < psl->sizel)
- {
- if (psl->a[num] == x)
- {
- printf("%d\n", num);
- return;
- }
- num++;
- }
- printf("表中没有%d\b", x);
- return;
- }
-
- //修改
- void SeqListModity(SL* psl, int pos, SQDataType x)
- {
- assert(pos < psl->sizel);
- psl->a[pos] = x;
- }
-
- //打印链表
- void SeqListPrint(SL* psl)
- {
- for (int i = 0; i < psl->sizel; i++)
- {
- printf("%d ", psl->a[i]);
- }
- printf("\n");
- }
-
- //销毁空间
- void SeqListDestroy(SL* psl)
- {
- free(psl->a);
- psl->a = NULL;
- psl->capacity = 0;
- psl->sizel = 0;
- }
存放主函数,其它函数在此文件夹调用
- #define _CRT_SECURE_NO_WARNINGS 1
- #include
- #include "SeqList.h"
-
- //菜单
- void menu()
- {
- printf("**********************\n");
- printf("1.尾插数据,2.头插数据\n");
- printf("3.尾删数据,4.头删数据\n");
- printf("5.选择插入,6.选择删除\n");
- printf("7.查找元素,8.修改链表\n");
- printf("9.打印数据,-1,退出\n");
- printf("**********************\n");
- printf("请输入你的选择:");
- }
-
- int main()
- {
- SL slist;
- int choose = 0;
- SeqListInit(&slist);//初始化
- while (choose != -1)
- {
- int a = 0, b = 0;
- menu();
- scanf(" %d", &choose);
- switch (choose)
- {
- case 1://尾插
- printf("请输入你要插入的数据,以-1结束\n");
- while (a != -1)
- {
- scanf("%d", &a);
- if(a!=-1)
- SeqListPushBack(&slist, a);
- }
- break;
- case 2://头插
- printf("请输入你要插入的数据,以-1结束\n");
- while (a != -1)
- {
- scanf("%d", &a);
- if (a != -1)
- SeqListPushFront(&slist, a);
- }
- break;
- case 3://尾删
- SeqListPopBack(&slist);
- printf("尾删,删除成功!\n");
- break;
- case 4://头删
- SeqListPopFront(&slist);
- printf("头删,删除成功!\n");
- break;
- case 5://选择插入
- printf("请输入需要插入的下标和元素:");
- scanf("%d%d", &a, &b);
- SeqListInsert(&slist, a, b);
- break;
- case 6://选择删除
- printf("请输入需要删除的元素的下标:");
- scanf("%d", &a);
- SeqListErase(&slist, a);
- break;
- case 7://查找元素
- printf("请输入需要查找的元素的下标:");
- scanf("%d", &a);
- SeqListFind(&slist, a);
- break;
- case 8://修改链表
- printf("请输入需要修改的下标和元素:");
- scanf("%d%d", &a, &b);
- SeqListModity(&slist, a, b);
- break;
- case 9://打印
- SeqListPrint(&slist);
- break;
- case -1://退出
- SeqListDestroy(&slist);//销毁空间
- break;
- default:
- printf("输入错误,请重新输入!\n");
- break;
- }
- system("pause");
- system("cls");
- }
-
- return 0;
- }
上述分模块写的代码为修改后的,添加了一些细节性的东西,下方完整代码为修改前的,懒得改了,可以正常使用。