線性表的順序表示和實現
線性表的順序表示指的是用一組地址連續的存儲單元依次存儲線性表的數據元素。
線性表的第一個數據元素a1的存儲位置,通常稱作線性表的起始位置或基地址。
只要確定了存儲線性表的起始位置,線性表中任一數據元素都可隨機存取,所以線性表的順序存儲結構是一種隨機存取的存儲結構。
數組類型有隨機存取的特性,因此通常都用數組來描述數據接哦故中的順序存儲結構。由於線性表的長度可變,且所需最大存儲空間隨問題不同而不同,在C語言中可用動態分配的一維數組,如下描述。
/* 線性表的動態分配順序存儲結構 */ #define LIST_INIT_SIZE 100 /* 線性存儲空間的初始分配量 */ #define LISTINCREMENT 10 /* 線性存儲空間的分配增量 */ typedef struct { ElemType *elem; /* 存儲空間基址 */ int length; /* 當前長度 */ int listsize; /* 當前分配的存儲容量(以sizeof(ElemType)為單位) */ } SqList;
在上述定義中,數組指針elem指示線性表的基地址,length指示線性表的當前長度。順序表的初始化操作就是為順序表分配一個預定定義大小的數組空間,並將線性表的當前長度設為“0”。listsize指示順序表當前分配的存儲空間大小,一旦因插入元素而空間不足時,可進行再分配,即為順序表增加一個大小為存儲LISTINCREMENT個數據元素的空間。
要特別注意的是,C語言中數組的下標是從“0”開始,因此,若L是SqList類型的順序表,則表中第i個數據元素是L.elem[i-1]。

1 //構造一個空的線性表 2 Status InitList_Sq(SqList &L) { 3 L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType)); 4 if (!L.elem) exit(OVERFLOW); 5 L.length = 0; //空表長度為0 6 L.listsize = LIST_INIT_SIZE; //初始存儲容量 7 return OK; 8 }
一般情況下,在第i(1<= i <= n)個元素之前插入一個元素時,需將第n至第i(共n-i+1)個元素向后移動一個位置。如下算法:
1 //在線性表中插入元素 2 //在順序線性表L中第i個位置之前插入新的元素e, i的合法值為 1<= i <= ListLength_Sq(L) + 1 3 Status ListInsert_Sq(SqList &L, int i, ElemType e) { 4 ElemType *newbase = NULL; 5 ElemType *p = NULL; 6 ElemType *q = NULL; 7 if (i <1 || i >L.length + 1) return ERROR; 8 if (L.length >= L.listsize) { 9 newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType)); 10 if (!newbase) exit(OVERFLOW); 11 L.elem = newbase; 12 L.listsize += LISTINCREMENT; 13 } 14 q = &(L.elem[i - 1]); //q為插入位置 15 for (p = &(L.elem[L.length - 1]); p >= q; --p) 16 *(p + 1) = *p; //插入位置及之后的元素右移 17 *q = e; 18 ++L.length; 19 return OK; 20 }
刪除第i(1<= i <= n)個元素時需將從第i+1至第n(共n-i)個元素依次向前移動一個位置。如下算法:
1 //刪除線性表中的元素 2 //在順序線性表L中刪除第i個元素, 並用e返回其值, i的合法值為 1<= i <= ListLength_Sq(L) 3 Status ListDelete_Sq(SqList &L, int i, ElemType &e) { 4 ElemType *p = NULL; 5 ElemType *q = NULL; 6 if ((i < 1) || (i > L.length)) return ERROR; 7 p = &(L.elem[i - 1]); //p為被刪除元素的位置 8 e = *p; 9 q = L.elem + L.length - 1; //表尾元素位置 10 for (++p; p <= q; ++p) *(p - 1) = *p; //被刪除元素之后的元素左移 11 --L.length; //表長減1 12 return OK; 13 }
在順序表L中查訪是否存在和e相同的數據元素的最簡便的方法是,令e和L中的數據元素逐個比較。如下算法:
1 int LocateElem_Sq(SqList L , ElemType e , Status (*compare)(ElemType , ElemType)) 2 { 3 //在順序線性表L中查找第1個值與e滿足compare()的元素的位序 4 //若找到,則返回其在L中的位序,否則返回0 5 i = 1; //i的初值為第1個元素的位序 6 p = L.elem; //p的初值為第1個元素的存儲位置 7 while(i <= L.length && !(*compare)(*p++ , e)) 8 ++i; 9 if(i <= L.length) return i; 10 else 11 return 0; 12 }
順序線性表的實現代碼如下:
1 //線性表的順序表示與實現 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 /****************************************************************************** 6 /* 數據類型和常量定義 7 /******************************************************************************/ 8 #define TURE 1 9 #define FALSE 0 10 #define OK 1 11 #define ERROR 0 12 #define OVERFLOW -2 13 14 typedef int Status; 15 typedef int ElemType; 16 17 /****************************************************************************** 18 /* 數據結構聲明 19 /******************************************************************************/ 20 /* 線性表的動態分配順序存儲結構 */ 21 #define LIST_INIT_SIZE 2 /* 線性存儲空間的初始分配量 */ 22 #define LISTINCREMENT 1 /* 線性存儲空間的分配增量 */ 23 24 typedef struct { 25 ElemType *elem; /* 存儲空間基址 */ 26 int length; /* 當前長度 */ 27 int listsize; /* 當前分配的存儲容量(以sizeof(ElemType)為單位) */ 28 } SqList; 29 30 31 32 //構造一個空的線性表 33 Status InitList_Sq(SqList &L) { 34 L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType)); 35 if (!L.elem) exit(OVERFLOW); 36 L.length = 0; //空表長度為0 37 L.listsize = LIST_INIT_SIZE; //初始存儲容量 38 return OK; 39 } 40 41 42 //在線性表中插入元素 43 //在順序線性表L中第i個位置之前插入新的元素e, i的合法值為 1<= i <= ListLength_Sq(L) + 1 44 Status ListInsert_Sq(SqList &L, int i, ElemType e) { 45 ElemType *newbase = NULL; 46 ElemType *p = NULL; 47 ElemType *q = NULL; 48 if (i <1 || i >L.length + 1) return ERROR; 49 if (L.length >= L.listsize) { 50 newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType)); 51 if (!newbase) exit(OVERFLOW); 52 L.elem = newbase; 53 L.listsize += LISTINCREMENT; 54 } 55 q = &(L.elem[i - 1]); 56 for (p = &(L.elem[L.length - 1]); p >= q; --p) *(p + 1) = *p; 57 58 *q = e; 59 ++L.length; 60 return OK; 61 } 62 63 //刪除線性表中的元素 64 //在順序線性表L中刪除第i個元素, 並用e返回其值, i的合法值為 1<= i <= ListLength_Sq(L) 65 Status ListDelete_Sq(SqList &L, int i, ElemType &e) { 66 ElemType *p = NULL; 67 ElemType *q = NULL; 68 if ((i < 1) || (i > L.length)) return ERROR; 69 p = &(L.elem[i - 1]); 70 e = *p; 71 q = L.elem + L.length - 1; //表尾元素位置 72 for (++p; p <= q; ++p) *(p - 1) = *p; //被刪除元素之后的元素左移 73 --L.length; 74 return OK; 75 } 76 77 78 //遍歷線性表 79 Status ListTraverse_Sq(SqList &L, Status (*Visit)(ElemType)) { 80 ElemType *p = NULL; 81 ElemType *q = NULL; 82 if (L.length == 0) return ERROR; 83 p = &(L.elem[0]); 84 q = L.elem + L.length - 1; //表尾元素位置 85 for (; p <= q; ++p) Visit(*p); 86 return OK; 87 } 88 89 90 //訪問線性表中的元素 91 Status Visit(ElemType e) 92 { 93 printf("%d ", e); 94 return OK; 95 } 96 97 98 // 測試函數 99 void main() 100 { 101 SqList L; InitList_Sq(L); ElemType e; 102 103 //遍歷空表 104 if (OK == ListTraverse_Sq(L, Visit)) printf("visit succeed!\n"); 105 106 //插入元素 107 if (OK == ListInsert_Sq(L, 1, 10)) printf("insert succeed!\n"); 108 if (OK == ListInsert_Sq(L, 2, 20)) printf("insert succeed!\n"); 109 if (OK == ListInsert_Sq(L, 1, 30)) printf("insert succeed!\n"); 110 if (OK == ListInsert_Sq(L, 2, 40)) printf("insert succeed!\n"); 111 if (OK == ListInsert_Sq(L, 1, 50)) printf("insert succeed!\n"); 112 113 //遍歷非空表 114 if (OK == ListTraverse_Sq(L, Visit)) printf("visit succeed!\n"); 115 116 //刪除元素 117 if (OK == ListDelete_Sq(L, 1, e)) printf("delete %d succeed!\n", e); 118 if (OK == ListDelete_Sq(L, 3, e)) printf("delete %d succeed!\n", e); 119 if (OK == ListDelete_Sq(L, 2, e)) printf("delete %d succeed!\n", e); 120 121 //遍歷非空表 122 if (OK == ListTraverse_Sq(L, Visit)) printf("visit succeed!\n"); 123 }
