順序表是線性表最基礎的存儲結構,本文提供一個教學級完整程序,涵蓋初始化、插入、刪除、查找、遍歷、逆置、去重、求最大值八大操作,並深度解析**二級指針傳參**的內存管理原理,是數據結構入門必練項目。
typedef int ElementType;
typedef struct {
ElementType data[100]; // 固定容量 100
int length; // 當前長度,-1 表示空表
} SeqList;
void InitSeq(SeqList **L) {
*L = (SeqList*)malloc(sizeof(SeqList));
(*L)->length = -1;
}
為何用 `SeqList **L`?
主函數傳 `&L`(一級指針地址),函數內 `*L = malloc(...)` 修改的是主函數的指針變量本身。若傳一級指針 `SeqList *L`,函數內修改 `L` 只改副本,主函數指針仍為野指針 → 段錯誤。
int Add(SeqList *L, ElementType v) { // 尾插
if (L->length >= 99) return 0;
L->data[++L->length] = v; return 1;
}
void Insert(SeqList *L, int pos, ElementType v) { // 1-based 位置
if (pos < 1 || pos > L->length + 2) return;
for (int i = L->length; i >= pos - 1; i--) L->data[i+1] = L->data[i];
L->data[pos-1] = v; L->length++;
}
void Delete(SeqList *L, ElementType v) { // 刪除所有值為 v 的元素
for (int i = 0; i <= L->length; i++)
if (L->data[i] == v) {
for (int j = i; j < L->length; j++) L->data[j] = L->data[j+1];
L->length--; i--; // 同位置可能連續重複
}
}
int Search(SeqList *L, ElementType v) { // 返回 1-based 位置,0 表未找到
for (int i = 0; i <= L->length; i++)
if (L->data[i] == v) return i + 1;
return 0;
}
void Reverse(SeqList *L) { // 原地逆置
ElementType *tmp = malloc((L->length+1)*sizeof(ElementType));
for (int i = 0, j = L->length; j >= 0; i++, j--) tmp[i] = L->data[j];
memcpy(L->data, tmp, (L->length+1)*sizeof(ElementType));
free(tmp);
}
int MaxValue(SeqList *L) {
int max = L->data[0];
for (int i = 1; i <= L->length; i++)
if (L->data[i] > max) max = L->data[i];
return max;
}
void RemoveDuplicates(SeqList *L) {
int cnt = 0;
for (int i = 0; i <= L->length; i++) {
if (Search(L, L->data[i])) { Delete(L, L->data[i]); cnt++; }
}
printf("刪除重複 %d 項\n", cnt);
}
int main() {
SeqList *L; InitSeq(&L);
while (1) {
printf("1.Add 2.Insert 3.Delete 4.Search 5.Reverse 6.Max 7.Travel 8.RemoveDup\n");
int op; scanf("%d", &op);
// ... switch 分支調用對應函數 ...
}
free(L); return 0;
}
// 錯誤示範
void BadInit(SeqList *L) {
L = malloc(...); // 修改副本,主函數 L 不變
}
// 正確示範
void GoodInit(SeqList **L) {
*L = malloc(...); // 解引用修改主函數變量
}
// 內存圖:
// 主函數 L -----> 0x1000 (未初始化)
// 函數參數 P = &L ---> L 的地址
// *P = 0x3000 (malloc 結果) => 主函數 L 現在指向 0x3000