之前我們講了線性表, 本篇來闡述下線性表的順序存儲——順序表
定義
線性表的順序存儲又稱為順序表, 它是用一組地址連續的存儲單元依次存儲線性表中的數據元素. 邏輯上相鄰的兩個數據元素在物理位置上同樣相鄰.
規律
順序表中邏輯順序與物理順序相同
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;
}