首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言順序表有序插入:將元素插入適當位置保持有序性

     編輯:關於C語言

問題描述

給定一個**已按升序排列**的順序表(動態陣列),將新元素 e 插入適當位置,使表仍保持有序。需處理:插入頭部、中間、尾部、擴容(若滿)等情況。

資料結構定義


#define TRUE  1
#define FALSE 0
#define OK    1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

#define LIST_INIT_SIZE 100
#define LIST_INCREMENT 10

typedef int ElemType;
typedef int Status;

typedef struct {
    ElemType *elem;   // 動態陣列基址
    int length;       // 當前長度
    int listsize;     // 當前分配容量
} SqList;

初始化函數


Status InitList(SqList *L) {
    L->elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
    if (!L->elem) exit(OVERFLOW);
    L->length = 0;
    L->listsize = LIST_INIT_SIZE;
    return OK;
}

核心插入演算法(兩種實作)

版本一:分步驟清晰版


Status InsertOrdered_V1(SqList *L, ElemType e) {
    // 1. 擴容檢查
    if (L->length >= L->listsize) {
        ElemType *newbase = (ElemType *)realloc(L->elem,
            (L->listsize + LIST_INCREMENT) * sizeof(ElemType));
        if (!newbase) return ERROR;
        L->elem = newbase;
        L->listsize += LIST_INCREMENT;
    }

    // 2. 尋找插入位置:第一個大於 e 的元素索引
    int i;
    for (i = 0; i < L->length; i++) {
        if (L->elem[i] > e) break;
    }

    // 3. 後移元素騰出空位
    for (int j = L->length - 1; j >= i; j--) {
        L->elem[j + 1] = L->elem[j];
    }

    // 4. 插入並更新長度
    L->elem[i] = e;
    L->length++;
    return OK;
}

版本二:合併尋找與後移(更優雅)


Status InsertOrdered_V2(SqList *L, ElemType e) {
    // 擴容檢查同上...

    int j;
    // 從尾部向前掃描,邊掃描邊後移,直到找到 <= e 的位置
    for (j = L->length; j > 0 && e < L->elem[j - 1]; j--) {
        L->elem[j] = L->elem[j - 1];
    }
    L->elem[j] = e;
    L->length++;
    return OK;
}

版本二優勢: 單迴圈完成「找位置 + 移元素」,無需額外變數 i,邏輯緊湊,效能略優。

完整測試主程式


#include 
#include 

// ... 以上結構體、InitList、InsertOrdered_V2 定義 ...

int main() {
    SqList L;
    InitList(&L);

    // 預置有序資料 0~9
    L.length = 10;
    for (int i = 0; i < 10; i++) L.elem[i] = i;

    printf("插入前: ");
    for (int i = 0; i < L.length; i++) printf("%d ", L.elem[i]);
    printf("\n");

    int e;
    printf("請輸入要插入的整數: ");
    scanf("%d", &e);

    InsertOrdered_V2(&L, e);

    printf("插入後: ");
    for (int i = 0; i < L.length; i++) printf("%d ", L.elem[i]);
    printf("\n");

    free(L.elem);
    return 0;
}

測試案例

輸入 e插入位置結果陣列
-5頭部 (索引 0)-5 0 1 2 3 4 5 6 7 8 9
5中間 (索引 5)0 1 2 3 4 5 5 6 7 8 9
15尾部 (索引 10)0 1 2 3 4 5 6 7 8 9 15

複雜度分析

  • 時間:O(n)(最壞情況頭部插入需移動所有元素)。
  • 空間:O(1) 額外空間(原地操作)。
  • 均攤擴容:若使用 realloc 指數增長,均攤 O(1)。

常見錯誤與避坑

  1. 忘記擴容檢查 → 陣列滿時緩衝區溢出。
  2. 迴圈邊界錯誤:j >= i vs j > i,配合 L->elem[j+1] = L->elem[j] 需 j >= i。
  3. 未更新 length → 邏輯長度與實際不符。
  4. 使用 malloc 而非 realloc → 需手動複製舊資料,realloc 更簡潔高效。

擴展:降序表、重複值處理

  • 降序:將比較條件改為 e > L->elem[j-1]。
  • 允許重複:當前邏輯插入到**第一個大於 e 的元素之前**,相同值會聚在一起(穩定插入)。若需插到最後一個相同值之後,條件改為 e <= L->elem[j-1]。

總結

有序表插入是順序表操作的基礎範本。版本二「逆向掃描邊移邊找」是教科書級寫法,簡潔、高效、邊界清晰。掌握擴容、邊界、穩定性三要素,即可靈活應用於各類有序容器實作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved