c语言数据结构之线性表的顺序存储结构
线性表,即线性存储结构,将具有“一对一”关系的数据“线性”地存储到物理空间中,这种存储结构就称为线性存储结构,简称线性表。
注意:使用线性表存储的数据,要求数据类型必须一致,线性表存储的数据,要么全不都是整形,要么全部都是字符串。一半是整形,另一半是字符串的一组数据无法使用线性表存储。
线性表存储数据可以分为:
顺序存储结构和链式存储结构
数据结构中,一组数据中的某一元素的左侧相邻元素称为“直接前驱”,位于此元素左侧的所有元素都统称为“前驱元素”;某一元素的右侧相邻元素称为“直接后继”,位于此元素右侧的所有元素都统称为“后继元素”;
先介绍顺序表
顺序表全名顺序存储结构,顺序表存储数据时,会提前申请一整块足够大小的物理空间,然后将数据依次存储起来,存储时做到数据元素之间是不间断的。
顺序表的初始化
顺序表除了要申请足够大小的物理空间还需要申请顺序表的存储容量,顺序表的长
度,也就是顺序表中元素的个数。
注意:顺序表申请的存储容量要大于顺序表的长度。
首先我们得自定义顺序表
1 typedef struct SeqList{ 2 int * head;//声明了一个名为head的长度不确定的数组,也叫“动态数组” 3 int length;//记录当前顺序表的长度 4 int size;//记录顺序表分配的存储容量 5 }sqlt;
接着初始化顺序表的主要工作:
给 head 动态数据申请足够大小的物理空间
给 size 和 length 赋初值
1 #define Size 5 2 sqlt init_SeqList(){ 3 sqlt s; 4 s.head=(int*)malloc(sizeof(int)*Size); 5 //构造一个空的顺序表,动态申请存储空间 6 if(!s.head)//如果申请失败,作出提示并直接退出程序 7 { 8 printf("初始化失败\n"); 9 exit(0); 10 } 11 s.length=0;//空表的长度初始化为0 12 s.size=Size;//空表的初始存储空间为Size 13 return s; 14 }
顺序表插入元素
通过遍历,找到数据元素要插入的位置
将要插入位置元素以及后续的元素整体向后移动一个位置;
将元素放到腾出来的位置上
1 //插入函数,其中,elem为插入的元素,p为插入到顺序表的位置 2 sqlt insert_SeqList(sqlt s,int elem,int p) 3 { 4 //判断插入本身是否存在问题(如果插入元素位置比整张表的长度+1还大(如果相等,是尾随的情况),或者插入的位置本身不存在,程序作为提示并自动退出) 5 if(p>s.length+1||p<1){ 6 printf("插入的位置有问题\n"); 7 return s; 8 } 9 //做插入操作时,首先需要看顺序表是否有多余的存储空间提供给插入的元素,如果没有,需要申请 10 if(s.length>=s.size){ 11 s.head=(int *)realloc(s.head,(s.size+1)*sizeof(int)); 12 if(!s.head){ 13 printf("存储分配失败\n"); 14 } 15 } 16 //插入操作,需要将从插入位置开始的后续元素,逐个后移 17 for(int i=s.length-1;i>=p-1;i--){ 18 s.head[i+1]=s.head[i]; 19 } 20 //后移完成后,直接将所需插入元素,添加到顺序表的相应位置 21 s.head[p-1]=elem; 22 s.length++;//由于添加了元素,所以长度+1 23 return s; 24 }
注意,动态数组额外申请更多物理空间使用的是 realloc 函数。并且,在实现后续元素整体后移的过程,目标位置其实是有数据的,还是原来的数字,只是下一步新插入元素时会把旧元素直接覆盖。
顺序表删除元素
只需找到目标元素,并将其后续所有元素整体前移 1 个位置即可。(后续元素整体前移一个位置,会直接将目标元素删除,可间接实现删除元素的目的。)
1 sqlt del_SeqList(sqlt s,int p){ 2 if(p>s.length||p<1){ 3 printf("被删除的元素有误\n"); 4 return s; 5 } 6 //删除操作 7 for(int i=p;i<s.length;i++){ 8 s.head[i-1]=s.head[i]; 9 } 10 s.length--;//删除一个元素表的长度要减1 11 return s; 12 }
顺序表查找元素
在这里只选择简单的顺序查找算法
1 //查找函数,其中,elem表示要查找的数据元素的值 2 int select_SeqList(sqlt s, int elem){ 3 for(int i=0;i<s.length;i++){ 4 if(s.head[i]==elem){ 5 return i+1; 6 } 7 } 8 return -1;//如果查找失败,返回-1 9 }
顺序表更改元素
找到目标元素;
直接修改该元素的值;
1 //更改函数,其中,elem为要更改的元素,newElem为新的数据元素 2 sqlt amend_SeqList(sqlt s, int elem, int newElem){ 3 int p=select_SeqList(s,elem); 4 s.head[p-1]=newElem; 5 //由于返回的是元素在顺序表中的位置,所以p-1就是该元素在数组中的下标 6 return s; 7 }
以下实现增删改查的整体顺序存储结构线性表
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define Size 5 5 typedef struct SeqList{ 6 int * head;//声明了一个名为head的长度不确定的数组,也叫“动态数组” 7 int length;//记录当前顺序表的长度 8 int size;//记录顺序表分配的存储容量 9 }sqlt; 10 sqlt init_SeqList(){ 11 sqlt s; 12 s.head=(int*)malloc(sizeof(int)*Size); 13 //构造一个空的顺序表,动态申请存储空间 14 if(!s.head)//如果申请失败,作出提示并直接退出程序 15 { 16 printf("初始化失败\n"); 17 exit(0); 18 } 19 s.length=0;//空表的长度初始化为0 20 s.size=Size;//空表的初始存储空间为Size 21 return s; 22 } 23 //插入函数,其中,elem为插入的元素,p为插入到顺序表的位置 24 sqlt insert_SeqList(sqlt s,int elem,int p) 25 { 26 //判断插入本身是否存在问题(如果插入元素位置比整张表的长度+1还大(如果相等,是尾随的情况),或者插入的位置本身不存在,程序作为提示并自动退出) 27 if(p>s.length+1||p<1){ 28 printf("插入的位置有问题\n"); 29 return s; 30 } 31 //做插入操作时,首先需要看顺序表是否有多余的存储空间提供给插入的元素,如果没有,需要申请 32 if(s.length>=s.size){ 33 s.head=(int *)realloc(s.head,(s.size+1)*sizeof(int)); 34 if(!s.head){ 35 printf("存储分配失败\n"); 36 } 37 } 38 //插入操作,需要将从插入位置开始的后续元素,逐个后移 39 for(int i=s.length-1;i>=p-1;i--){ 40 s.head[i+1]=s.head[i]; 41 } 42 //后移完成后,直接将所需插入元素,添加到顺序表的相应位置 43 s.head[p-1]=elem; 44 s.length++;//由于添加了元素,所以长度+1 45 return s; 46 } 47 sqlt del_SeqList(sqlt s,int p){ 48 if(p>s.length||p<1){ 49 printf("被删除的元素有误\n"); 50 return s; 51 } 52 //删除操作 53 for(int i=p;i<s.length;i++){ 54 s.head[i-1]=s.head[i]; 55 } 56 s.length--;//删除一个元素表的长度要减1 57 return s; 58 } 59 //查找函数,其中,elem表示要查找的数据元素的值 60 int select_SeqList(sqlt s, int elem){ 61 for(int i=0;i<s.length;i++){ 62 if(s.head[i]==elem){ 63 return i+1; 64 } 65 } 66 return -1;//如果查找失败,返回-1 67 } 68 //更改函数,其中,elem为要更改的元素,newElem为新的数据元素 69 sqlt amend_SeqList(sqlt s, int elem, int newElem){ 70 int p=select_SeqList(s,elem); 71 s.head[p-1]=newElem; 72 //由于返回的是元素在顺序表中的位置,所以p-1就是该元素在数组中的下标 73 return s; 74 } 75 //输出顺序表中元素的函数 76 void display_SeqList(sqlt s){ 77 for(int i=0; i<s.length; i++){ 78 printf("%d",s.head[i]); 79 } 80 printf("\n"); 81 } 82 83 int main(){ 84 sqlt s1=init_SeqList(); 85 //向顺序表中添加元素 86 for(int i=1;i<=Size;i++){ 87 s1.head[i-1]=i; 88 s1.length++; 89 } 90 printf("原顺序表:\n"); 91 display_SeqList(s1); 92 93 printf("删除元素2:\n"); 94 s1=del_SeqList(s1,2); 95 display_SeqList(s1); 96 97 printf("在第3的位置插入元素5:\n"); 98 s1=insert_SeqList(s1,5,3); 99 s1=insert_SeqList(s1,5,3); 100 s1=insert_SeqList(s1,5,3); 101 s1=insert_SeqList(s1,5,3); 102 display_SeqList(s1); 103 104 printf("查找元素3的位置:\n"); 105 int p=select_SeqList(s1,3); 106 printf("%d\n",p); 107 108 printf("将元素3改为6:\n"); 109 s1=amend_SeqList(s1,3,6); 110 display_SeqList(s1); 111 return 0; 112 }