线性表的顺序存储,其数据结构以及具体实现详见下面代码,重要知识点全部以注释的形式在代码中展示出来。
1 /*** 2 线性表的顺序存储结构是一种 随机存取 的存储结构 3 在线性顺序表中插入或者删除一个元素,时间都消耗在移动元素上,平均约移动一般的元素, 4 故ListInsert和ListDelete的时间复杂度都为O(n); 5 */ 6 #include<stdio.h> 7 #include<stdlib.h> 8 //***************线性表的动态分配顺序存储结构***************** 9 #define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量 10 #define LISTINCREMENT 10 //线性表存储空间的存储增量 11 typedef struct 12 { 13 int *elem; //数组指针,存储空间基址 14 int length; //当前长度 15 int listsize;//当前分配的存储容量(以sizeof(int)为单位) 16 }SqList; 17 18 //******************初始化线性表,构造一个空表******************** 19 void InitList(SqList &L) 20 { 21 L.elem = (int *)malloc(LIST_INIT_SIZE * sizeof(int)); 22 if (!L.elem) 23 { 24 printf("存储分配失败,任意键退出! "); 25 getchar(); 26 exit(1); 27 } 28 L.length = 0; 29 L.listsize = LIST_INIT_SIZE; 30 } 31 32 //*********************输出线性表中的数据************************** 33 void PrintList(SqList L) 34 { 35 int *p = L.elem; //顺序表的开始位置 36 int *q = L.elem + L.length - 1;//顺序表的结束位置 37 while(p<=q) 38 { 39 printf("%d ", *p++); 40 } 41 } 42 43 //*************************线性表的插入**************************** 44 //*******参数i代表插入位置,在第i个之前插入*,故 1<=i<=n+1********* 45 /** 46 一般情况下,在第i(1<=i<=n)个元素之前插入,需要将第i至n(n-i+1)个元素向后移动一个位置, 47 若i=n+1,则直接在插入在最后即可 48 */ 49 void ListInsert(SqList &L,int i,int e) 50 { 51 //在顺序线性表L中的第i个位置之前插入新的元素e 52 //i的合法值为1<=i<=ListLength(L)+1 53 if (i<1||i>L.length+1) 54 { 55 printf("输入的插入位置不合法,请确定后重新输入!任意键退出 "); 56 getchar(); 57 exit(1); 58 } 59 if (L.length >= L.listsize) 60 { 61 //当前存储空间已满,需要增加分配 62 int * newbase = (int *)realloc(L.elem,(L.listsize + LISTINCREMENT)*sizeof(int)); 63 if (!newbase) 64 { 65 printf("存储分配失败,任意键退出! "); 66 getchar(); 67 exit(1); 68 } 69 L.elem = newbase;//新基址 70 L.listsize += LISTINCREMENT;//增加存储容量 71 } 72 int * q = &(L.elem[i-1]);//q为插入位置 73 for (int * p = &(L.elem[L.length-1]); p >= q; --p) 74 { 75 *(p+1) = *p;//插入位置及其之后的元素右移 76 } 77 *q = e;//插入e 78 ++L.length;//表长加1 79 } 80 81 //***************************顺序线性表的删除****************************** 82 /** 83 参数i代表删除位置,1<=i<=n,和插入时i的取值范围不同 84 一般情况下,删除第i(1<=i<=n)个元素时需要将从第i+1至第n(n-i)个元素依次向前移动一个位置 85 */ 86 void ListDelete(SqList &L,int i) 87 { 88 //删除顺序线性表中的第i个元素,i的合法值为1<=i<=ListLength(L) 89 if (i<1 || i>L.length) 90 { 91 printf("输入的删除位置不合法,请确定后重新输入!任意键退出! "); 92 getchar(); 93 exit(1); 94 } 95 int * p = &(L.elem[i-1]);//p为删除位置 96 int * q = L.elem + L.length - 1;//q为表尾位置 97 for (++p ; p<=q; ++p) 98 { 99 *(p-1) = *p;//被删除元素之后的元素左移 100 } 101 --L.length;//表长减1 102 } 103 104 //************数值定位函数,返回元素e在L中的位置,若没有,返回0*************** 105 int LocateElem(SqList L,int e) 106 { 107 //在顺序线性表中查找第一个与元素e相同位序 108 //若找到,则返回其在L中的位序,否则返回0 109 int i = 1;//i的初始值为第一个元素的位序 110 int *p = L.elem ;//p的初始值为第一个元素的存储位置 111 while(i<=L.length && e != *p) 112 { 113 ++i; 114 ++p; 115 } 116 if (i<=L.length) 117 return i; 118 else 119 return 0; 120 } 121 122 //**********************取出指定位序的线性表中的数据元素*********************** 123 int GetElem(SqList L,int i) 124 { 125 //将线性表L中的第i个元素返回给e 126 if (i<1 || i>L.length) 127 { 128 printf("该数据元素不存在,请仔细确认!任意键退出 "); 129 getchar(); 130 exit(1); 131 } 132 // int *q = &L.elem[i-1]; 133 // int e = *q; 134 int e = L.elem[i-1]; 135 //因为elem是一个数组指针,当只用elem时,代表首地址 136 //,若具体指定某一个数elem[i],则代表第i+1个元素,故下面和上面的注释方法都可行 137 // int *p = L.elem; 138 // int e = *(p+i-1); 139 return e; 140 141 } 142 143 //****************************线性顺序表的合并******************************** 144 /** 145 该方法的线性复杂度为O(ListLength(LA) x ListLength(LB) ) 146 该方法得到的线性表是无序的,数据直接插在一个线性表的最后 147 是将所有在线性表Lb中但不在La中的数据元素插入到La中,无重复项 148 */ 149 void ListUnoin(SqList &La,SqList Lb) 150 { 151 //将所有在线性表Lb中但不在La中的数据元素插入到La中 152 int la_len = La.length; 153 int lb_len = Lb.length; 154 int e; 155 for (int i = 1; i <= lb_len; ++i) 156 { 157 e = GetElem(Lb,i);//取Lb中第i个元素赋值给e 158 //printf("%d ",e); 159 if(!LocateElem(La,e)) 160 { 161 ListInsert(La,++la_len,e);//将数据插在La的末尾 162 } 163 } 164 } 165 166 //**************************有序线性顺序表的合并******************************* 167 /** 168 通过增加一个线性表,使得时间复杂度由O(ListLength(LA) x ListLength(LB))变成 169 了O(ListLength(LA) + ListLength(LB)) 170 不过使用这种方法需要有个前提:La和Lb已经排序 171 得到的结果Lc也是排好序的线性表 172 */ 173 void MergeList(SqList La,SqList Lb,SqList &Lc) 174 { 175 //本例中以非递减排序为例 176 int * pa = La.elem; 177 int * pb = Lb.elem; 178 Lc.length = La.length + Lb.length; 179 Lc.listsize = Lc.length; 180 Lc.elem = (int *)malloc(Lc.listsize * sizeof(int)); 181 if (!Lc.elem) 182 { 183 printf("存储分配失败,任意键退出! "); 184 getchar(); 185 exit(1); 186 } 187 int *pc = Lc.elem; 188 int *pa_last = La.elem + La.length - 1; 189 int *pb_last = Lb.elem + Lb.length - 1; 190 while(pa<=pa_last && pb<=pb_last)//归并操作 191 { 192 if(*pa <= *pb) 193 *pc++ = *pa++; 194 else 195 *pc++ = *pb++; 196 } 197 while(pa <= pa_last) 198 *pc++ = *pa++;//插入La的剩余元素 199 while(pb <= pb_last) 200 *pc++ = *pb++;//插入Lb的剩余元素 201 } 202 203 204 int main() 205 { 206 //首先输入10个数据,构造一个线性表,测试建表,输出,插入,删除功能是否正确 207 SqList La,Lb,Lc; 208 InitList(La); 209 InitList(Lb); 210 InitList(Lc); 211 int count,value,location; 212 printf("请输入建立顺序表La的元素个数:"); 213 scanf("%d",&count); 214 printf("请依次输入%d个数据:",count); 215 for (int i = 0; i < count; ++i) 216 { 217 //将输入的数据插入到顺序表La中 218 scanf("%d",&value); 219 ListInsert(La,i+1,value); 220 } 221 //输出线性表的数据 222 printf("该顺序线性表的数据元素为:"); 223 PrintList(La); 224 225 //测试插入数据是否可行 226 printf(" 请输入插入位置和插入值:"); 227 scanf("%d%d",&location,&value); 228 ListInsert(La,location,value); 229 printf("插入之后的数据元素为:"); 230 PrintList(La); 231 232 //测试删除数据情况 233 printf(" 请输入删除位置:"); 234 scanf("%d",&location); 235 ListDelete(La,location); 236 printf("数据删除之后的元素为:" ); 237 PrintList(La); 238 239 //测试顺序表的合并,需要两个有序的顺序表 240 printf(" 请输入建立顺序表Lb的元素个数:"); 241 scanf("%d",&count); 242 printf("请依次输入%d个数据:",count); 243 for (int i = 0; i < count; ++i) 244 { 245 //将输入的数据插入到顺序表La中 246 scanf("%d",&value); 247 ListInsert(Lb,i+1,value); 248 } 249 MergeList(La,Lb,Lc); 250 printf("将La和Lb合并之后的Lc数据元素为:"); 251 PrintList(Lc); 252 253 printf(" 采用时间复杂度更高的合并方式为:"); 254 ListUnoin(La,Lb); 255 PrintList(La); 256 257 return 0; 258 }