一: 顺序表是什么
在c语言描述的数据结构里,顺序表是一种线性存储结构。线性存取结构又是什么?
我们可以这样理解,线性存取就是将一串具有相同特征的数据用一根线串接起来,然后再放到我们的存储之中。当然,数据结构都是抽象出来的概念,但是这种抽象的理解方式也就掩盖了底层的复杂,也就方便我们去操作内存。
二:顺序表与链表的区别
顺序表是将元素放到一块连续的内存存取空间的。在存取元素数据之前,需要申请一块足够大的内存空间,数据之间是一个挨一个,所以我们说是顺序表,就是按照顺序依次存放。
链表在存放数据之时,什么时候存储数据,什么时候才申请存储空间,数据之间并不是顺序相连,而是链式相连,这条链,我们可以认为是每个元素所包含的指针。每个节点含有一个数据域和指针域,指针域存放了下一个元素的存储位置信息,构成了链。
链式存储是很容易产生碎片化信息的,因为元素前后并不是顺序相连,中间可能会含有部分未使用的空间,所以比较浪费空间,但是顺序表没有这种缺点,含有在空间占用上,肯定是链式存取更加占用空间,除了碎片化的一些东西,还有携带的指针域也会占用一部分的空间,所以内存的空间占用率比较大。
我们考虑具体的操作,我们在查找元素的时候还是顺序存储结构比较方便啦!因为我们直接可以从数组下标访问,很明显,这种查找方式的时间复杂度为o(1),相比之下,链式存储结构的查找方式就是从开始进行遍历,所以时间复杂度是o(n)。
但是呢,链式存储结构总不是一无是处的吧!不然我们还要它干嘛?我们考虑除去查找方式的其它操作,还有插入,删除操作这些,比如我们进行插入操作的时候,在顺序表中进行插入操作的时候,我们在表中插入一个元素,那么后面的元素就都得往后面移动,需要移动大量的元素,但是链表呢,我们通过链式存储结构,就不需要进行大量的移动。
想要了解链表请参考下面这篇博文。具体静态动态,这里都以代码实现了。
单链表的静态建立以及动态链表建立(红芯书院的研学)
三: 顺序表的代码实现操作
现在我们考虑如何实现简简单单的顺序表
偷个懒,我们完全可以写一个数组,说它是顺序表。但是我们为了s更加深刻的理解,我们就还是采用结构体的这种方式。
理一下思路的话,数据储存的话,我们就用数组啦!因为是顺序存储嘛。
我们先看部分的关键代码,我们先看下面这一部分。这里主要显示的是顺序表的结构体存储方式。
#include<stdio.h> # define MAX 1000 typedef struct Student { /* data */ int data[MAX] }stu1;
我们稍微对比一下链表的结构体
#include<stdio.h> typedef struct Student{ int age; struct Student *next; }stu1;
我们可以对比到,我们先都把两者的 int 类型的数据age来看,一个是直接先申请了空间的,一个是没有先申请空间。当然,顺序表后面也可以申请空间的,我们这边先不做赘述。还有就是一个没有指针域,一个有指针域。可以说,这些就是两者比较在代码实现上最根本的区别。当然顺序表的组成结构体中我们还可以定义其它的有意义的数据,这个就看这人构造啦!比如用来记录顺序表的元素的计数器,这些都决定不了它是顺序表的本质。所以说,编程不是照搬照做!
甚至我我们在给顺序表空间的时候,我们也可以进行申请函数进行空间申请。我们这边就以数组定长来进行举例,因为比较反应本质,简单易懂。
来了哦!
下面我嗯实现顺序表的各种操作,包括增删改查!
1:我们先创建一个顺序表需要的结构体
typedef struct Student1 { int data[MAX]; int length;//length定义了表的长度,用作记录表长 /* data */ }Student;//结构体名
2:下面我们初始化表,我们初始化表长为0
chushi(Student *L){ L->length = 0;//初始化表长为0,因为没有任何元素 printf("初始化完毕!\n"); }
释疑
当L是指针类型的时候我们用L->data这样的格式引用数据,不是指针类型而是结构体对象类型的时候我们用L.data。我们这样简单的去理解,但是指针结构体这些内部还是有许多学问的。
解释部分内容
你可能会疑惑为什么L前面会加一个*号,有的时候会加,有的时候不加。我要对表进行操作,改变表的时候就会进行再主函数中传入表地址。如果我不对表进行改变的化,我就直接传入变量l,按照结构体的方式进行操作。
3:下面我们创建表(给表添加一些基本的元素)
create(Student * l,int size){ if(size>MAX){ printf("超出最大限制长度"); } srand(time(0));//播种 for(int i =0;i<size;i++){ l->data[i]=rand()%20+1; l->length++; //printf("%d\t",l->data[i]); } //printf("%d",l->length); printf("基本创建完毕\n"); }
释疑
我们用到的不过是随机生成函数,rand()这边,以及srand()函数,用来生成种子。想要了解,可以去问度娘。
4:下面我们进行输出表的部分元素
print(Student L){ for(int i =0;i<L.length;i++){ printf("%d\t",L.data[i]); } printf("元素输出完毕!\n"); }
5:插入操作的函数
insert(Student *L){ int n,loc =0; printf("请输入插入元素的个数:"); scanf("%d",&n); // printf("执行到此处!"); if(n>(MAX-L->length)){ printf("插入元素的个数超出限定的元素个数"); } else { printf("执行到此处!"); for(int i =0;i<n;i++){ printf("请输入要插入的位置\n:"); scanf("%d",&loc); if((loc>L->length)||(loc<0)){ printf("不允许这样插入!\n"); } else{ printf("请输入要插入的元素:\n"); int ele = 0; scanf("%d",&ele); for(int j = L->length;j>i-1;j--){ L->data[j+1] = L->data[j];//将插入位置的元素以及之后的元素依次往后移动 } L->data[loc-1] = ele;//指定位置将元素插入 L->length++; //更新表长 } } }
6:删除操作函数
delet(Student *L){ int n =0; if(L->length ==0){ printf("此表为空表,不能再执行删除操作!\n"); } printf("请输入要删除的位置:\n"); scanf("%d",&n); if(n<=0||n>=L->length){ printf("删除位置不合理!\n"); } else{ for(int j =n-1;j<L->length;j++){ L->data[j] =L->data[j+1]; } L->length--; } }
7:进行查询函数
find(Student L){ int find_1 =0; printf("请输入要查找的元素:\n"); scanf("%d",&find_1); for(int i =0;i<L.length;i++){ if(L.data[i]==find_1){ printf("已经找到该元素!所在位置为%d\n",i+1); break; } if (i==L.length-1) { printf("元素没有找到!\n"); /* code */ } } // printf("元素没有查找到!\n"); }
来看完整的源代码
#include<stdio.h> #include<stdlib.h> #include<time.h> #include<windows.h> #define MAX 1000 typedef struct Student1 { int data[MAX]; int length; /* data */ }Student; chushi(Student *L){ L->length = 0;//初始化表长为0,因为没有任何元素 printf("初始化完毕!\n"); } create(Student * l,int size){ if(size>MAX){ printf("超出最大限制长度\n"); } srand(time(0));//播种 for(int i =0;i<size;i++){ l->data[i]=rand()%20+1; l->length++; //printf("%d\t",l->data[i]); } //printf("%d",l->length); printf("基本创建完毕\n"); } print(Student L){ for(int i =0;i<L.length;i++){ printf("%d\t",L.data[i]); printf("\n"); } printf("元素输出完毕!\n"); } insert(Student *L){ int n,loc =0; printf("请输入插入元素的个数:\n"); scanf("%d",&n); // printf("执行到此处!"); if(n>(MAX-L->length)){ printf("插入元素的个数超出限定的元素个数!\n"); } else { printf("执行到此处!\n"); for(int i =0;i<n;i++){ printf("请输入要插入的位置:\n"); scanf("%d",&loc); if((loc>L->length)||(loc<0)){ printf("不允许这样插入!\n"); } else{ printf("请输入要插入的元素:\n"); int ele = 0; scanf("%d",&ele); for(int j = L->length;j>i-1;j--){ L->data[j+1] = L->data[j];//将插入位置的元素以及之后的元素依次往后移动 } L->data[loc-1] = ele;//指定位置将元素插入 L->length++; //更新表长 } } } } delet(Student *L){ int n =0; if(L->length ==0){ printf("此表为空表,不能再执行删除操作!\n"); } printf("请输入要删除的位置:\n"); scanf("%d",&n); if(n<=0||n>=L->length){ printf("删除位置不合理!\n"); } else{ for(int j =n-1;j<L->length;j++){ L->data[j] =L->data[j+1]; } L->length--; } } find(Student L){ int find_1 =0; printf("请输入要查找的元素:\n"); scanf("%d",&find_1); for(int i =0;i<L.length;i++){ if(L.data[i]==find_1){ printf("已经找到该元素!所在位置为%d\n",i+1); break; } if (i+1==L.length) { printf("元素没有找到!\n"); /* code */ } } // printf("元素没有查找到!\n"); } int main() { Student l; int size=0; int n1,loc=0; printf("请输入初始化数据元素的个数:\n"); scanf("%d",&size); chushi(&l); create(&l,size); print(l); insert(&l); printf("元素插入完毕!\n"); printf("顺序表新的元素构造如下:\n"); print(l); delet(&l); printf("删除完毕!\n"); printf("顺序表新的构造如下\n"); print(l); find(l); system("pause");//防止闪退 }
功能函数都已经写出来了,我们要是想要更加灵活的对标进行操作,可以进行进一步的封装。所用代码编辑器vscode,轻量级,非常好用。
下面看一下整体的代码运行效果