第1天线性表顺序存储
线性表是一种最简单的线性结构
线性结构的基本特征为:线性结构是一个数据元素的有序(次序)集
1.集合中必存在唯一的一个“第一元素”;
2.集合中必存在唯一的一个 “最后元素” ;
3.除最后元素在外,均有 唯一的后继;
4.除第一元素之外,均有 唯一的前驱
线性表:n个数据元素组成的有限序列。表示为(a1,a2,…,ai,ai+1,…,an)
一:线性表的顺序存储方式:
线性表的顺序存储方式定义为:用一组地址连续的存储单元依次存放线性表中的数据元素以“存储位置相邻”表示有序对<ai-1,ai>
线性表的起始地址称作线性表的基地址
即:LOC(ai) = LOC(ai-1) + C
LOC(ai) = LOC(a1) + (i-1)×C
所有数据元素的存储位置均取决于第一个数据元素的存储位置
线性表的表示方法:
1 #define LIST_INIT_SIZE 80 // 线性表存储空间的初始分配量
3 #define LISTINCREMENT 10 // 线性表存储空间的分配增量
5 typedef struct {
7 ElemType *elem; // 存储空间基址
9 int length; // 当前长度
11 int listsize; // 当前分配的存储容量,(以sizeof(ElemType)为单位)
13 } SqList; // 俗称 顺序表
算法1:合并线性表(利用已有的函数实现)
假设:有两个集合 A 和 B 分别用两个线性表 LA 和 LB 表示,即:线性表中的数据元素即为集合中的成员。
现要求一个新的集合A=A∪B。上述问题可演绎为:要求对线性表作如下操作:
扩大线性表 LA,将存在于线性表LB 中而不存在于线性表 LA 中的数据元素插入到线性表 LA 中去。
操作步骤:
- 从线性表LB中依次察看每个数据元素;
GetElem(LB, i)→e
- 依值在线性表LA中进行查访;
LocateElem(LA, e, equal( ))
- 若不存在,则插入之。
ListInsert(LA, n+1, e)
例: LA=(8,5,11,3)
LB=(6,8,2,9,20,15,11)
则: LA=(8,5,11,3,6,2,9,20,15}
代码实现:
1 void union(List &La, List Lb) {
3 La_len = ListLength(La); // 求线性表的长度
5 Lb_len = ListLength(Lb);
7 for (i = 1; i <= Lb_len; i++) {
9 GetElem(Lb, i, e); // 取Lb中第i个数据元素赋给e
11 if (!LocateElem(La, e, equal( )) )
13 ListInsert(La, ++La_len, e); // La中不存在和 e 相同的数据元素,则插入之
15 }
17 }
算法2:合并有序表,用已知函数实现
有序表:若线性表中的数据元素依值非递减或非递增有序排列,
即 ai≥ai-1 或 ai≤ai-1(i = 2,3,…, n),则称该线性表为有序表。
比如:1,3,5,6,8,10,20,23,
已知线性表La和Lb中的数据元素按值非递减有序排列,现要求La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列
实现步骤:
1.分别从La和Lb中取得当前元素ai和bj;
2.若ai≤bj,则将ai插入到Lc中,否则将bj插入到Lc中。
例: La=(3,5,8,11)
Lb=(2,6,8,9,11,15,20)
则: Lc=(2,3,5,6,8,8,9,11,11,15,20}
代码实现:
1 void MergeList(List La, List Lb, List &Lc) // 本算法将非递减的有序表 La 和 Lb 归并为 Lc
3 {
5 initList(Lc); // 构造空的线性表 Lc
7 i = j = 1; k = 0;
9 La_len = ListLength(La);
11 Lb_len = ListLength(Lb);
13 while ((i <= La_len) && (j <= Lb_len))
15 { GetElem(La, i, ai);
17 GetElem(Lb, j, bj);
19 if (ai <= bj) { ListInsert(Lc, ++k, ai); ++i; }// 将 ai 插入到 Lc 中
21 else { ListInsert(Lc, ++k, bj); ++j; }// 将 bj 插入到 Lc 中
23 }
25 while (i<=La_len) // 当La不空时
27 { GetElem(La, i++, ai); ListInsert(Lc, ++k, ai);} // 插入 La 表中剩余元素
29 while (j<=Lb_len) // 当Lb不空时
31 { GetElem(Lb, j++, bj); ListInsert(Lc, ++k, bj); } // 插入 Lb 表中剩余元素
32
33 }
算法3:直接实现有序表的合并操作,不用已知函数。
1 void MergeList(List La, List Lb, List &Lc) {
5 pa=La.elem; pb=Lb.elem;
9 Lc.listsize=Lc.length=La.length+Lb.length; //Lc的长度赋值
13 Pc=Lc.elem=(elemtype *)malloc(Lc.listsize*sizeof(elemtype));
17 If(!Lc.elem) exit(overflow); //给Lc动态分配存储空间
21 pa_last = La.elem+La.length-1; //记录La的最后元素存放位置
25 pb_last = Lb.elem+Lb.length-1 ; //记录Lb的最后元素存放位置
29 while (pa <= pa_last) && (pb<= pb_last)
33 { if(*pa<=*pb) *pc++=*pa++;
37 eles *pc++=*pb++;}//归并操作
41 while (pa <= pa_last) *pc++=*pa++; // 若 La 不空
45 while (pb<= pb_last) *pc++=*pb++; // 若 Lb 不空
49 }
算法4:线性表的结构初始化
1 Status InitList_Sq( SqList& L ) {
5 L.elem = (ElemType*) malloc (LIST_INIT_SIZEsizeof (ElemType));
9 if (!L.elem) exit(OVERFLOW);
13 L.length = 0;
17 L.listsize = LIST_INIT_SIZE;
21 return OK;
25 } // InitList_Sq算法时间复杂度:O(1)
26
27
算法5:输出线性表内容
1 Void Printlist( SqList L ) {
5 int i;
9 printf("\n*********************");
13 printf("\nThe element of the sqlist are:\n");
17 for(i=0;i<L.length;i++)
21 printf("%d ",L.elem[i]);
25 printf("\n*********************\n");
29 return;
33 }//算法时间复杂度:O(L.length)
算法6:线性表的插入元素
1 Status ListInsert_Sq(SqList &L, int i, ElemType e)
3 { // 在顺序表L的第 i 个元素之前插入新的元素e,
5 // i 的合法范围为 1≤i≤L.length+1
7 if (i < 1 || i > L.length+1) return ERROR// 插入位置不合法
9 if (L.length >= L.listsize)
13 { // 当前存储空间已满,增加分配
17 newbase = (ElemType *)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof (ElemType));
19 if (!newbase) exit(OVERFLOW); // 存储分配失败
23 L.elem = newbase; // 新基址
27 L.listsize += LISTINCREMENT; // 增加存储容量
31 }
35 q = &(L.elem[i-1]); // q 指示插入位置
37 for (p = &(L.elem[L.length-1]); p >= q; ---p) // p表尾元素的位置
39 *(p+1) = *p; // 插入位置及之后的元素右移
41 *q = e; // 插入e
43 ++L.length; // 表长增1
45 return OK;
47 } // ListInsert_Sq 算法时间复杂度为: O( ListLength(L) )
算法7:线性表的删除元素
3 Status ListDelete_Sq (SqList &L, int i, ElemType &e) {
5 if ((i < 1) || (i > L.length)) return ERROR; // 删除位置不合法
7 p = &(L.elem[i-1]); // p 为被删除元素的位置
9 e = *p; // 被删除元素的值赋给 e
11 q = L.elem+L.length-1; // 表尾元素的位置
13 for (++p; p <= q; ++p)
15 *(p-1) = *p; // 被删除元素之后的元素左移
17 --L.length; // 表长减1
19 return OK;
21 } // ListDelete_Sq
顺序存储结构的优缺点:
优点:
1:逻辑相邻,物理相邻:
2:可随机存取任一元素
3:存储空间使用紧凑
缺点::
1:插入、删除操作需要移动大量的元素
2:预先分配空间需按最大空间分配,利用不充分:
3:表容量难以扩充
1 附:代码参考
3 #define list_size 15
5 #define increment 5
7 #define ok 1
9 #define overflow -1
11 #define error -2
13 #include "stdlib.h"
15 #include "stdio.h"
17 typedef struct{ int *elem;
19 int length;
21 int listsize;}sqlist;
23 int initlist(sqlist *L)
25 { L->elem=(int *)malloc(list_size*sizeof(int));
27 if(!L->elem) exit(overflow);
29 L->length=0;
31 L->listsize=list_size;
33 return ok; }
35 int listinsert( sqlist *L, int i, int e )
37 { int *p,*q,*newbase;
39 if(i<1||i>L->length+1) return error;
41 if(L->length>=L->listsize)
43 {newbase=(int *)realloc(L->elem,(L->listsize+increment)*sizeof(int));
45 if(!newbase)exit(overflow);
47 L->listsize+=increment;}
49 q=&(L->elem[i-1]);
51 for(p=&(L->elem[L->length-1]);p>=q;--p) *(p+1)=*p; *q=e; ++L->length;
53 return ok;}
55 void printlist(sqlist *L)
57 {int i;
59 printf("\n*********************");
61 printf("\nThe element of the sqlist are:\n");
63 for(i=0;i<L->length;i++)
65 printf("%d ",L->elem[i]);
67 printf("\n*********************\n");
69 return;
71 }
73 main( )
75 { int i,j,e;
77 sqlist L1;
79 initlist(&L1);
81 printf(“\n Please insert the length of the sqlist:\n");
83 scanf("%d",&L1.length);
85 printf(“\n Please insert the element of the sqlist:\n");
87 for(i=0; i<L1.length; i++)
89 scanf( “%d”, &L1.elem[ i ]);
91 printlist(&L1);
93 printf("\nPlease insert the value of j ane e :\n");
95 scanf("%d%d",&j,&e);
97 listinsert(&L1, j, e);
99 printlist(&L1);
101 }