線性表的順序儲存——順序表
之前我們講了線性表, 本篇來闡述下線性表的順序儲存——順序表
定義
線性表的順序儲存又稱為順序表, 它是用一組地址連續的儲存單元依次儲存線性表中的資料元素. 邏輯上相鄰的兩個資料元素在物理位置上同樣相鄰.
規律
順序表中邏輯順序與物理順序相同
L = ($a_{1}$, $a_{2}$, ..., $a_{i}$, $a_{i + 1}$, ..., $a_{n}$)
其中在邏輯上相鄰的兩個資料元素,在順序表中也存放在相同的儲存單元當中,每一個小格子就代表一個儲存單元。
注 線性表中的元素的位序是從
1
開始, 而陣列中元素下標是從0
開始的
若線性表儲存的起始位置為Loc(A)
, sizeof(ElemType)
第一個元素的地址是 LOC(A)
,計算第二個元素的地址就可以用第一個元素的地址加上第一個資料元素 $a_{1}$ 所消耗的儲存空間,用 sizeof
可求得該資料元素所消耗的儲存空間大小。這裡需要注意的一點是,n
與 MaxSize
是有含義上的不同的,其中 $a_{n}$ 代表的是順序表中最後一個數據元素
,而 MaxSize 代表的是陣列的最後一個儲存單元
。
順序表的兩種實現方法
順序表可以用陣列來實現。根據陣列的兩種分配方式,也就有兩種描述順序表的方法。分別是靜態描述分配順序表
的方法和動態描述分配順序表
- 靜態描述分配順序表
#define MaxSize 50
typedef struct{
ElemType data[MaxSize];
int length;
}SqList;
這就是描述順序表的語句。第一句是定義了一個巨集,也就是定義線性表的最大長度為 50,同時這也是陣列的最大容量。接著定義了一個結構體。結構體就是把多個基本資料型別組合到一起構成一個新的資料型別。它的定義語句是用 typedef struct
,然後用大括號圈起來所要包含的基本資料型別
。最後 SqList
代表著該結構體的名字。
在靜態分配時陣列的大小和空間已固定, 空間一旦佔滿, 再加入新資料將會產生溢位, 從而導致程式崩潰.
- 動態描述分配順序表
#define MaxSize 50
typedef struct{
ElemType *data; //指示動態分配陣列的指標
int MaxSize, length; //陣列的最大容量和當前個數
}SqList;
這是動態分配時描述順序表的語句,觀察發現這裡用的是指標
,指標是存放一個儲存單元地址的。順序表根據第一個資料元素的地址和資料元素的大小,就可以計算出任意資料元素的位置。那麼只要定義了第一個資料元素的指標
,就可以描述整個順序表。但是這一個變數它僅僅是一個地址,而沒有確切的空間,所以在使用時,需要動態的申請空間。怎樣動態的申請空間呢?:
- C的初始動態分配語句
L.data = (Elemtype*)malloc(sizeof(ElemType)*InitSize);
- C++的初始動態分配語句
L.data = new ElemType[InitSize];
動態分配時, 一旦資料空間佔滿, 就另外開闢一塊更大的儲存空間, 代替原來的儲存空間.
順序表上基本操作實現
定義
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;
//----- 順序表的順序儲存表示 -----
#define LIST_INIT_SIZE 100 // 儲存空間的初始分配量
#define LISTINCREMENT 10 // 儲存空間的分配增量
typedef struct {
ElemType *elem; // 儲存空間的基址
int length; // 表長
int size; // 儲存容量
int increment; // 擴容時,增加的儲存容量
} SqList; //順序表
初始化順序表
Status InitSqlist(SqList &L){
L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if(!L.elem) exit (OVERFLOW);
L.length = 0;
L.size = LIST_INIT_SIZE;
L.increment = LISTINCREMENT;
return OK;
}
判順序表是否為空表
Status ListEmpty(SqList L){
if (L.length == 0) return OK;
else return ERROR;
}
插入操作
Status ListInsert_Sq(SqList &L, int i, ElemType e){
if(i < 1 || i > L.length + 1)
return ERROR;
if(L.length >= L.size)
return ERROR;
for(int j = L.length; j >= i; j--)
L.elem[j] = L.elem[j - 1];
L.elem[i - 1] = e;
L.length++;
return OK;
}
刪除元素
Status ListDelete_Sq(SqList &L, int i, ElemType &e){
if(i < 1 || i > L.length)
return ERROR;
e = L.elem[i - 1];
for(int j = i; j < L.length; j++)
L.elem[j - 1] = L.elem[j];
L.length--;
return OK;
}
輸出順序表
void OutList_Sq(SqList L) {
int i;
ElemType e;
if(ListEmpty(L)) {
printf("這是一個空表!");
}
else {
printf("順序表為:");
for(i = 0; i < L.length; i++) {
printf("%6d", L.elem[i]);
}
printf("\n");
}
}
測試
int main() {
SqList L;
int cord,i; ElemType a;
printf("第一次使用必須初始化!\n");
do {
printf("\n 主選單 \n");
printf(" 1 初始化順序表 ");
printf(" 2 插入一個元素 ");
printf(" 3 刪除一個元素 ");
printf(" 4 結束程式執行 ");
printf("\n-------------------------------------------------------------------\n");
printf("請輸入您的選擇( 1, 2, 3, 4)");
scanf("%d", &cord);
printf("\n");
switch(cord) {
case 1:
InitSqlist(L);
OutList_Sq(L);
break;
case 2:
printf("\n請輸入要插入的插入位置和資料元素(如:3 20)");
scanf("%d%d", &i, &a);
ListInsert_Sq(L, i, a);
printf("\n插入%d元素之後的", a);
OutList_Sq(L);
break;
case 3:
printf("\n請輸入要刪除的資料元素的位置(如: 3)");
scanf("%d", &i);
ListDelete_Sq(L, i, a);
printf("\n刪除第%d個位置的元素之後", i);
OutList_Sq(L);
break;
case 4:
exit(0);
default: break;
}
} while(cord <= 4);
return 1;
}