malloc/realloc 動態管理,容量可自動擴展。#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef struct {
int *elem; // 數據基址
int length; // 當前長度
int listsize; // 當前分配容量
} SqList;
// 15 操作聲明
int InitList(SqList *L);
void DestroyList(SqList *L);
void ClearList(SqList *L);
int ListEmpty(SqList L);
int ListLength(SqList L);
int GetElem(SqList L, int i, int *e);
int LocateElem(SqList L, int e);
void PriorElem(SqList L, int cur_e);
void NextElem(SqList L, int cur_e);
void ListTraverse(SqList L);
void PutElem(SqList *L, int i, int e);
void ListInsert(SqList *L, int i, int e);
void ListDelete(SqList *L, int i, int *e);
void Union(SqList *LA, SqList LB); // 合並:B中不在A的插入A
void MergeList(SqList LA, SqList LB, SqList *LC); // 歸並:有序A+B→有序C
InitList - O(1)int InitList(SqList *L) {
L->elem = (int*)malloc(LIST_INIT_SIZE * sizeof(int));
if (!L->elem) { printf("分配失敗\n"); exit(1); }
L->length = 0;
L->listsize = LIST_INIT_SIZE;
return 0;
}
DestroyList - O(1)void DestroyList(SqList *L) {
if (L->elem) { free(L->elem); L->elem = NULL; }
L->length = L->listsize = 0;
}
順序表內存連續,單次 free 即可釋放全部。
ClearList - O(1)void ClearList(SqList *L) { if (L->elem) L->length = 0; }
僅重置長度,保留內存供下次復用。
ListEmpty/ListLength - O(1)直接檢查 L.elem 和 L.length。
LocateElem - O(n)int LocateElem(SqList L, int e) {
for (int i = 0; i < L.length; i++)
if (L.elem[i] == e) return i + 1; // 返回邏輯位序(1-based)
return 0; // 未找到
}
GetElem - O(1)int GetElem(SqList L, int i, int *e) {
if (i < 1 || i > L.length) return 0;
*e = L.elem[i - 1];
return 1;
}
注意用輸出參數 int* e 返回值,避免值傳遞無效。
PriorElem/NextElem - O(n)先定位再判斷邊界,輸出邏輯鄰接元素。
ListTraverse - O(n)順序訪問數組輸出。
PutElem - O(1)void PutElem(SqList *L, int i, int e) {
if (i >= 1 && i <= L->length) L->elem[i - 1] = e;
}
ListInsert - O(n)void ListInsert(SqList *L, int i, int e) {
if (i < 1 || i > L->length + 1) return;
if (L->length >= L->listsize) { // 擴容
int *newbase = (int*)realloc(L->elem, (L->listsize + LISTINCREMENT) * sizeof(int));
if (!newbase) exit(0);
L->elem = newbase;
L->listsize += LISTINCREMENT;
}
int *p = &L->elem[i - 1]; // 插入位置
for (int *q = &L->elem[L->length - 1]; q >= p; q--)
*(q + 1) = *q; // 後移
*p = e;
L->length++;
}
關鍵點:realloc 可能移動內存,必須用臨時指針接收返回值,防止分配失敗導致原指針丟失(內存洩漏)。
平均時間:移動元素期望 n/2,O(n)。
ListDelete - O(n)void ListDelete(SqList *L, int i, int *e) {
if (i < 1 || i > L->length) return;
int *p = &L->elem[i - 1];
*e = *p;
for (; p < &L->elem[L->length - 1]; p++)
*p = *(p + 1); // 前移
L->length--;
}
平均時間:同插入,O(n)。
Union - O(LA_len * LB_len)遍歷 B,若 A 中無該元素(LocateElem),插入 A 尾部。
MergeList - O(LA_len + LB_len)雙指針法,類似歸並排序合併階段。利用有序性,單次掃描完成。
void MergeList(SqList LA, SqList LB, SqList *LC) {
InitList(LC);
int *pa = LA.elem, *pb = LB.elem;
int *pa_last = LA.elem + LA.length - 1;
int *pb_last = LB.elem + LB.length - 1;
LC->listsize = LC->length = LA.length + LB.length;
LC->elem = (int*)malloc(LC->listsize * sizeof(int));
int *pc = LC->elem;
while (pa <= pa_last && pb <= pb_last)
*pc++ = (*pa <= *pb) ? *pa++ : *pb++;
while (pa <= pa_last) *pc++ = *pa++;
while (pb <= pb_last) *pc++ = *pb++;
}
此版本直接指針操作,避免重複調用 GetElem/ListInsert 開銷,更高效。
i-1 輕易出錯,需嚴謹。動態順序表是數據結構入門的核心模型。掌握其初始化、擴容、插刪移動、有序歸並等操作的實現細節與複雜度權衡,為後續學習鏈表、樹、圖等結構打下堅實基礎。