文章目录
🍔一、前言
停更了一个月限时返场啦😍从本篇文章开始就进入了我们数据结构的学习喽!本篇文章也是《数据结构与算法》 专栏的第一篇文章,本篇的内容是顺序表的学习,也是数据结构的开胃小菜,希望烙铁们可以理解消化哦🥰!!!
在我们学习顺序表之前呢,我们大家肯定会有疑问,什么是数据结构,为什么要去学习数据结构,顺序表在数据结构里面代表什么呢?,这里我来给大家一次解惑,让大家真正的搞懂数据结构,学习起来才更加有动力🥰!
🍟1. 什么是数据结构
🚩简单地说,数据结构是以某种特定的布局方式存储数据的容器。这种“布局方式”决定了数据结构对于某些操作是高效的,而对于其他操作则是低效的。首先我们需要理解各种数据结构,才能在处理实际问题时选取最合适的数据结构。
🚩数据的逻辑结构****是指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后间关系,而与他们在计算机中的存储位置无关。逻辑结构分为以下几种:
🔴集合结构:数据元素同属一个集合,单个数据元素之间没有任何关系。
🔴线性结构:数据结构中的元素存在一对一的相互关系。
🔴树形结构:数据结构中的元素存在一对多的相互关系。
🔴图形结构:数据结构中的元素存在多对多的相互关系。
🚩数据的物理结构****是指数据的逻辑结构在计算机存储空间的存放形式,它包括数据元素的机内表示和关系的机内表示。物理结构又叫存储结构,分为以下几种:
🔴顺序存储结构:一段连续的内存空间。优点:随机访问;缺点:插入删除效率低,大小固定。
🔴链式存储结构:不连续的内存空间。优点:大小动态扩展,插入删除效率高;缺点:不能随机访问。
🔴索引存储结构:为了方便查找,整体无序,但索引块之间有序,需要额外空间,存储索引表。优点:对顺序查找的一种改进,查找效率高;缺点:需额外空间存储索引。
🔴散列存储结构:选取某个函数,数据元素根据函数计算存储位置可能存在多个数据元素存储在同一位置,引起地址冲。优点:查找基于数据本身即可找到,查找效率高,存取效率高;缺点:存取随机,不便于顺序查找。
🍔二、顺序表的概念----线性表
🍟1. 什么是线性表
本次我们要来介绍,第一种数据结构,也是数据结构中最简单的一部分:线性表
此时此刻,肯定会有烙铁会有疑问,为什么难道他会像一条线一样一次连接吗?
没错,当数据首尾依次相连接,这种数据结构就被叫做线性表。
注意 :相连接是逻辑上的连接,不是空间上的连接。
此时,可能还会有烙铁站出来说:你说的这不就是数组嘛,小意思,我会!
其实 数组只是一种线性表,可是线性表还有很多种形式哦!
线性表的形式: 数组、链表、顺序表、队列等 (其中数组我们在C语言已经学过,不再提及) 。
🚨官方解释:线性表(linear list)是 n 个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就是说是连续的一条直线。但是在物理结构上不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
🍟2. 顺序表与数组的区别
🚩顺序表:顺序表是用 一段物理地址连续存储单元 ,依次存储数据元素的线性结构
顺序表就是将数据连着存放,存放的数据空间也是连着的
🚩数组:数据不用按顺序的存放,可以随意的存放
🚩区别:数组不按空间顺序随意地存放数据,但是顺序表的数据是要按照空间的的顺序存放
说的这里估计有些烙铁已经开始有点 晕晕的状态了,我来给大家画图解释一下:
🍔三、顺序表详解
💧 静态顺序表
🚩静态顺序表:使用定长数组存储
🚩优点:操作简单,代码实现容易
🚩缺点:定长数组很受限制,数组开小了不够用,开大了又浪费
//静态顺序表#defineN10;typedefint SLDatatype;typedefstructSeqList{
SLDatatype a[N];int size;}SL;
💧 动态顺序表
🚩动态顺序表:使用动态开辟的数组进行数据的存储
🚩优点:数组大小可以根据自己的需求进行调节
🚩缺点:代码比较复杂
//动态顺序表typedefint SLDatatype;typedefstructSeqList{
SLDatatype* a;//指向动态开辟的数组int size;//存储的有效数据的个数int capacity;//当前容量}SL;
🍎创建动态顺序表
🥰这里先创建三个文件:
1️⃣:SeqList.h文件,用于函数的声明
2️⃣:SeqList.c文件,用于函数的定义
3️⃣:Test.c文件,用于测试函数
建立三个文件的目的: 将顺序表作为一个项目来进行书写,方便我们的学习与观察。
⭕接口1:定义结构体SL
🥰请看代码与注释👇
typedefint SLDatatype;//数据类型typedefstructSeqList{
SLDatatype* a;//指向动态开辟的数组int size;//存储的有效数据的个数int capacity;//当前容量}SL;
⭕接口2:初始化结构体(SLInit)
🥰请看代码与注释👇
voidSLInit(SL* psl){assert(psl);
psl->a =(SLDatatype*)malloc(sizeof(SLDatatype)*4);if(psl->a ==NULL){perror("malloc fail");return;}
psl->capacity =4;
psl->size =0;}
⭕接口3:检查结构体中的数组是否需要扩容(SLCheckCapacity)
🥰请看代码与注释👇
voidSLCheckCapacity(SL* psl){assert(psl);if(psl->size == psl->capacity){
SLDatatype* tmp =(SLDatatype*)realloc(psl->a,sizeof(SLDatatype)* psl->capacity *2);if(tmp ==NULL);{perror("realloc fail");return;}
psl->a = tmp;
psl->capacity *=2;}}
⭕接口4:结构体销毁(SLDestroy)
销毁顺序表所开辟的空间,防止内存泄漏
🥰请看代码与注释👇
voidSLDestroy(SL* psl){assert(psl);free(psl->a);
psl->a =NULL;
psl->size =0;
psl->capacity =0;}
⭕接口5:打印(SLPrint)
🥰请看代码与注释👇
voidSLPrint(SL* psl){assert(psl);for(int i =0; i < psl->size; i++){printf("%d ", psl->a[i]);}printf("\n");}
⭕接口6:尾插(SLPushBack)
🥰请看代码与注释👇
voidSLPushBack(SL* psl, SLDatatype x){assert(psl);SLCheckCapacity(psl);//检查是否需要扩容
psl->a[psl->size]= x;
psl->size++;}
⭕接口7:头插(SLPushFront)
(1)从第一个数据开始向后挪动:会发生覆盖----不可取❌
(2)从最后一个数据开始向后挪动:理想状态✅
🥰请看代码与注释👇
voidSLPushFront(SL* psl, SLDatatype x){assert(psl);SLCheckCapacity(psl);//挪动数据int end = psl->size -1;while(end >=0){
psl->a[end +1]= psl->a[end];
end--;}
psl->a[0]= x;
psl->size++;}
⭕接口8:尾删(SLPopBack)
🥰请看代码与注释👇
voidSLPopBack(SL* psl){//暴力检查assert(psl->size >0);//温柔的检查//if (psl->size == 0)// return;
psl->size--;}
⭕接口9:头删(SLPopFront)
(1)从最后一个数据开始向前挪动:会发生覆盖----不可取❌
(1)先从下标为 1 的数据开始向前挪动:理想状态✅
🥰请看代码与注释👇
voidSLPushFront(SL* psl, SLDatatype x){assert(psl);SLCheckCapacity(psl);//挪动数据int end = psl->size -1;while(end >=0){
psl->a[end +1]= psl->a[end];
end--;}
psl->a[0]= x;
psl->size++;}
⭕接口10:在指定位置(pos)插入(SLInsert)
🚨要实现这一功能,我们依然需要一个end下标,数据从后往前依次后挪,直到pos下标移动完毕。另外,别忘了检查容量。
🥰请看代码与注释👇
voidSLInsert(SL* psl,int pos, SLDatatype x){assert(0<= pos && pos <= psl->size);SLCheckCapacity(psl);int end = psl->size -1;while(end >= pos){
psl->a[end +1]= psl->a[end];
end--;}
psl->a[pos]= x;
psl->size++;}
🥰拓展:了解了以上在指定位置插入的代码之后,我们就可以在头插和尾插中复用该功能
👇请看代码👇
//尾插voidSLPushBack(SL* psl, SLDatatype x){SLInsert(psl, psl->size, x);}//头插voidSLPushFront(SL* psl, SLDatatype x){SLInsert(psl,0, x);}
🥰这样写是不是非常滴香!
⭕接口11:在指定位置(pos)删除(SLErase)
🚨要实现这一功能,我们依然需要一个start下标,数据从前往后依次前挪,直到移动完毕。
🥰请看代码与注释👇
voidSLErase(SL* psl,int pos){assert(0<= pos && pos < psl->size);int start = pos +1;while(start < psl->size){
psl->a[start -1]= psl->a[start];
start++;}
psl->size--;}
🥰拓展:同样的了解了以上在指定位置删除的代码之后,我们就可以在头删和尾删中复用该功能
👇请看代码👇
//尾删voidSLPopBack(SL* psl){SLErase(psl, psl->size -1);}//头删voidSLPopFront(SL* psl){SLErase(psl,0);}
⭕接口12:查找某一个数据的位置(SLFind)
找到返回下标,没找到返回-1
🥰请看代码与注释👇
intSLFind(SL* psl, SLDatatype x){assert(psl);for(int i =0; i < psl->size; i++){if(psl->a[i]== x){return i;}}return-1;}
⭕接口13:查找某一个数据的位置(SLFind)
🥰请看代码与注释👇
voidSLModify(SL* psl,int pos, SLDatatype x){assert(0<= pos && pos < psl->size);
psl->a[pos]= x;}
⭕菜单
🚨数据结构阶段不建议写菜单,不便于调试,本篇文章菜单写在下面的完整代码中的 Test.c文件和 main主函数中了,需要的烙铁自行学习查看🥰
🍔四、完整代码
🍪SeqList.h
#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<string.h>#include<assert.h>//动态顺序表typedefint SLDatatype;//数据类型typedefstructSeqList{
SLDatatype* a;//指向动态开辟的数组int size;//存储的有效数据的个数int capacity;//当前容量}SL;//初始化voidSLInit(SL* psl);//销毁voidSLDestroy(SL* psl);//检查是否需要扩容voidSLCheckCapacity(SL* psl);//打印voidSLPrint(SL* psl);//尾插voidSLPushBack(SL* psl, SLDatatype x);//头插voidSLPushFront(SL* psl, SLDatatype x);//尾删voidSLPopBack(SL* psl);//头删voidSLPopFront(SL* psl);//在pos位置插入voidSLInsert(SL* psl,int pos, SLDatatype x);//在pos位置删除voidSLErase(SL* psl,int pos);//查找(找到返回下标,没找到返回-1)intSLFind(SL* psl, SLDatatype x);//修改voidSLModify(SL* psl,int pos, SLDatatype x);
🍪SeqList.c
#include"SeqList.h"//初始化voidSLInit(SL* psl){assert(psl);
psl->a =(SLDatatype*)malloc(sizeof(SLDatatype)*4);if(psl->a ==NULL){perror("malloc fail");return;}
psl->capacity =4;
psl->size =0;}//销毁voidSLDestroy(SL* psl){assert(psl);free(psl->a);
psl->a =NULL;
psl->size =0;
psl->capacity =0;}//检查是否需要扩容voidSLCheckCapacity(SL* psl){assert(psl);if(psl->size == psl->capacity){
SLDatatype* tmp =(SLDatatype*)realloc(psl->a,sizeof(SLDatatype)* psl->capacity *2);if(tmp ==NULL);{perror("realloc fail");return;}
psl->a = tmp;
psl->capacity *=2;}}//打印voidSLPrint(SL* psl){assert(psl);for(int i =0; i < psl->size; i++){printf("%d ", psl->a[i]);}printf("\n");}//尾插voidSLPushBack(SL* psl, SLDatatype x){//SLCheckCapacity(psl);//psl->a[psl->size] = x;//psl->size++;SLInsert(psl, psl->size, x);}//头插voidSLPushFront(SL* psl, SLDatatype x){//SLCheckCapacity(psl);//挪动数据//int end = psl->size - 1;//while (end >= 0)//{// psl->a[end + 1] = psl->a[end];// end--;//}//psl->a[0] = x;//psl->size++;SLInsert(psl,0, x);}//尾删voidSLPopBack(SL* psl){//暴力检查//assert(psl->size > 0);//温柔的检查//if (psl->size == 0)// return;//psl->size--;SLErase(psl, psl->size -1);}//头删voidSLPopFront(SL* psl){//暴力检查//assert(psl->size > 0);//int start = 1;//while (start < psl->size)//{// psl->a[start - 1] = psl->a[start];// start++;//}//psl->size--;SLErase(psl,0);}//在pos位置插入voidSLInsert(SL* psl,int pos, SLDatatype x){assert(0<= pos && pos <= psl->size);SLCheckCapacity(psl);int end = psl->size -1;while(end >= pos){
psl->a[end +1]= psl->a[end];
end--;}
psl->a[pos]= x;
psl->size++;}//在pos位置删除voidSLErase(SL* psl,int pos){assert(0<= pos && pos < psl->size);int start = pos +1;while(start < psl->size){
psl->a[start -1]= psl->a[start];
start++;}
psl->size--;}//查找(找到返回下标,没找到返回-1)intSLFind(SL* psl, SLDatatype x){assert(psl);for(int i =0; i < psl->size; i++){if(psl->a[i]== x){return i;}}return-1;}//修改voidSLModify(SL* psl,int pos, SLDatatype x){assert(0<= pos && pos < psl->size);
psl->a[pos -1]= x;}
🥝Test.c
#include"SeqList.h"//尾插测试voidTestSeqList1(){
SL s;SLInit(&s);SLPushBack(&s,1);SLPushBack(&s,2);SLPushBack(&s,3);SLPushBack(&s,4);SLPushBack(&s,5);SLPushBack(&s,6);SLPushBack(&s,7);SLPushBack(&s,8);SLPrint(&s);SLDestroy(&s);}//头插测试voidTestSeqList2(){
SL s;SLInit(&s);SLPushBack(&s,1);SLPushBack(&s,2);SLPushBack(&s,3);SLPushBack(&s,4);SLPushBack(&s,5);SLPushFront(&s,6);SLPushFront(&s,7);SLPushFront(&s,8);SLPrint(&s);SLDestroy(&s);}//尾删测试voidTestSeqList3(){
SL s;SLInit(&s);SLPushBack(&s,1);SLPushBack(&s,2);SLPushBack(&s,3);SLPushBack(&s,4);SLPushBack(&s,5);SLPushFront(&s,6);SLPushFront(&s,7);SLPushFront(&s,8);SLPrint(&s);SLPopBack(&s);SLPopBack(&s);SLPrint(&s);SLDestroy(&s);}//头删测试voidTestSeqList4(){
SL s;SLInit(&s);SLPushBack(&s,1);SLPushBack(&s,2);SLPushBack(&s,3);SLPushBack(&s,4);SLPushBack(&s,5);SLPushFront(&s,6);SLPushFront(&s,7);SLPushFront(&s,8);SLPrint(&s);SLPopBack(&s);SLPopBack(&s);SLPrint(&s);SLPopFront(&s);SLPopFront(&s);SLPrint(&s);SLDestroy(&s);}//指定位置插入测试voidTestSeqList5(){
SL s;SLInit(&s);SLPushBack(&s,1);SLPushBack(&s,2);SLPushBack(&s,3);SLPushBack(&s,4);SLPushBack(&s,5);SLPushFront(&s,6);SLPushFront(&s,7);SLPrint(&s);SLInsert(&s,2,30);SLPrint(&s);SLDestroy(&s);}//指定位置删除测试voidTestSeqList6(){
SL s;SLInit(&s);SLPushBack(&s,1);SLPushBack(&s,2);SLPushBack(&s,3);SLPushBack(&s,4);SLPushBack(&s,5);SLPushBack(&s,6);SLPrint(&s);SLInsert(&s,2,30);SLPrint(&s);SLErase(&s,2);SLPrint(&s);SLDestroy(&s);}//菜单voidmenu(){printf("***********************************************************\n");printf("1、尾插数据 2、尾删数据\n");printf("\n");printf("3、头插数据 4、头删数据\n");printf("\n");printf("5、在任意位置插入数据(位置3插入20)\n");printf("\n");printf("6、在任意位置删除数据 \n");printf("\n");printf("7、查找某个数据的位置 \n");printf("\n");printf("8、修改数据 \n");printf("\n");printf("9、打印数据 \n");printf("\n");printf("-1、退出 \n");printf("\n");printf("***********************************************************\n");}intmain(){printf("************* 欢迎大家来到动态顺序表的测试 **************\n");int option =0;
SL s;SLInit(&s);do{menu();printf("请输入你的操作:>");scanf("%d",&option);int sum =0;int x =0;int y =0;int z =0;int pos =0;int w =0;int o =0;int p =0;switch(option){case1:printf("请依次输入你要尾插的数据:,以-1结束\n");scanf("%d",&sum);while(sum !=-1){SLPushBack(&s, sum);// 1.尾插scanf("%d",&sum);}break;case2:SLPopBack(&s);// 2.尾删break;case3:scanf("%d",&x);SLPushFront(&s, x);// 3.头插break;case4:SLPopFront(&s);// 4.头删break;case5:SLInsert(&s,3,20);// 5.在任意位置插入数据break;case6:SLErase(&s,3);// 6.在任意位置删除数据break;case7:printf("请输入要删除序列的中的某个数据>\n");scanf("%d",&z);
y =SLFind(&s, z);// 7.查找某个数字的位置printf("%d的位置在%d处: \n", z, y);break;case9:SLPrint(&s);break;case8:printf("请输入要修改序列的中的某个数据的下标:>\n");scanf("%d",&o);printf("请输入要修改成什么:>\n");scanf("%d",&p);SLModify(&s, o, p);break;default:if(option ==-1){exit(0);// 退出程序 }else{printf("输入错误,请重新输入\n");}break;}}while(option !=-1);// 退出程序SLDestroy(&s);return0;}
✅运行界面
😍这期内容些许复杂,需要慢慢理解消化哦!
总结🥰
以上就是 【数据结构】顺序表—C语言版 的全部内容啦🥳🥳🥳🥳
本文章所在【数据结构与算法】专栏,感兴趣的烙铁可以订阅本专栏哦🥳🥳🥳
前途很远,也很暗,但是不要怕,不怕的人面前才有路。💕💕💕
小的会继续学习,继续努力带来更好的作品😊😊😊
创作写文不易,还多请各位大佬uu们多多支持哦🥰🥰🥰
版权归原作者 C-调战士 所有, 如有侵权,请联系我们删除。