數據結構之順序表(C語言實現)

Table of Contents

定義

實現定義結構

定義操作創建順序表

初始化順序表

插入元素

刪除元素

銷燬順序表


定義


數據結構是相互之間存在一種或多種特定關係的數據元素的集合。根據數據元素之間關係的不同特性,通常有如下4類基本結構:

  • 集合:結構中的數據元素之間除了“同屬於一個集合”的關係外,別無其他的關係。如:廣義表。
  • 線性結構:結構中的數據元素之間存在一個對一個的關係。如:鏈表。
  • 樹形結構:結構中的數據元素之間存在一個對多個的關係。如:二叉樹。
  • 圖(網)狀結構:結構中的數據元素之間存在多個對多個的關係。


在線性結構中,根據存儲方式分爲順序表、鏈表,根據對錶的操作限制,分爲棧和隊列。

順序表的特徵是,在內存中佔用連續的存儲單元,可以簡單的理解爲順序表就是數組。只是根據需要,在實際應用中動態分配順序表佔用的內存單元。而數組是在編譯的時候,預分配了指定大小的內存單元,因此如下代碼段會在編譯的時候報錯。

int len = 10;
char arr[len];

但是順序表又會有數據全部的特點:可以根據下標直接訪問、不方便插入和刪除元素(因爲需要移動後續的元素)。

實現
定義結構

typedef int SeqType; //存儲單元類型

typedef struct{
    SeqType *elem; //存儲空間基地址
    int length; //當前長度
    int listsize; //當前分配的存儲容量(以sizeof(ElemType)爲單位)
} SqList;

結構體內,有三個元素:存儲空間基地址,類似於數組首地址;當前長度,記錄順序表中有效存儲單元個數;當前分配的存儲容量,順序表中,最多容納的存儲單元個數。當順序表中所有存儲單元已經被使用,在下次插入元素之前,需要新增存儲單元。這點是數組所不具有的特性。

*注:定義一個存儲單元類型SeqType是爲了使順序表適和更多數據類型,使用的時候修改SeqType類型即可。

定義操作
創建順序表

/**
 * 創建順序表
 */
SqList createList_sq() {
    //SqList list;
    //return list;

    SqList* list = (SqList*)malloc(sizeof(SqList));
    return *list;
}

這裏提供兩種創建順序表的代碼,一種是由系統分配list佔用的內存,一種是自己動態分配的內存,需要在程序運行之前手動釋放佔用的內存空間。

初始化順序表

/**
 * 初始化順序表
 * 返回1 表示初始化成功
 * 返回0 表示初始化失敗
 */
int initList_sq(SqList &L) { //只有在C++中才會有引用的存在
    L.elem = (SeqType *) malloc(sizeof(SeqType) * LIST_INIT_SIZE);
    if (!L.elem)
        return 0; //內存分配失敗,存儲空間不夠
    L.length = 0; //表示順序表爲空
    L.listsize = LIST_INIT_SIZE; //表示順序表裏,最大存儲單元個數
    return 1;
}

分配順序表的存儲單元,初始化順序表屬性的值。

插入元素

/**
 * 插入順序表
 * 下標是負數就插入到結尾
 */
int insertList_sq(SqList &L, int index, SeqType val) {
    if (index > L.length) { //存儲的下表超出順序表實際的長度
        printf("插入的下標超出順序表的實際長度");
        return 0;
    }
    if (index < 0) //下標是負數,插入到結尾
        index = L.length;
    if (L.length == L.listsize) { //順序表的存儲單元已經存滿
        printf("順序表的存儲單元已滿,繼續分配新的存儲單元。");
        SeqType* newBase = (SeqType*) realloc(L.elem,
                (L.listsize + LISTINCREMENT) * sizeof(SeqType)); //繼續分配存儲單元
        if (!newBase) {
            printf("分配內存單元失敗");
            return 0;
        }
        L.elem = newBase;
        L.listsize += LISTINCREMENT;
    }
    //尋找合適的插入位置,index後面的元素向後移動
    for (int i = L.length; i > index; i--) {
        L.elem[i] = L.elem[i - 1]; //向後移動
    }
    L.elem[index] = val; //插入元素
    L.length++;
    return 1;
}

將元素插入到指定的位置。插入之前,需要先判斷順序表中是否已經存滿,再根據需要新增存儲單元,最後插入元素。

/**
 * 插入順序表(結尾的位置)
 * 與上面的函數是重名函數,這叫函數重載,在C++裏面支持
 */
int insertList_sq(SqList &L, SeqType val) {
    return insertList_sq(L, L.length, val);
}

*引用和重載,是C++中才支持,因此需要在cpp文件中編譯。

刪除元素

/**
 * 刪除指定的元素
 * 返回0 找不到指定的元素,刪除失敗。
 * 返回1 找到待刪除的元素,刪除成功。
 */
int removeList_sq(SqList &L, SeqType val) {
    int index = -1; //記錄匹配到的下標
    for (int i = 0; i < L.length; i++) {
        if (L.elem[i] == val) {
            //找到匹配的val,結束循環
            index = i;
            break;
        }
    }
    if (index < 0)
        return 0;
    for (; index < L.length - 1; index++) {
        L.elem[index] = L.elem[index + 1];
    }
    L.length--;
    return 1;
}

刪除指定元素,需要先找到下標。依次移動下標後面的結點,修改length值。

/**
 * 根據下標刪除是指定的結點,並返回元素的值
 * 返回0 下標超出順序表長度,刪除失敗。
 * 返回1 下標正確,刪除元素,並且將已刪除元素值轉給elem
 */
int removeList_sq(SqList &L, int index, SeqType &elem) {
    if (index >= L.length) //下標超出順序表的長度
        return 0;
    index = index < 0 ? L.length : index; //下標負數表示刪除最後一個節點
    elem = L.elem[index];
    for (int i = index; i < L.length - 1; i++) {
        L.elem[i] = L.elem[i + 1];
    }
    L.length--;
    return 1;
}

先取到指定下標的元素,賦值給elem,然後依次移動下標後面的結點。最後修改length值。

銷燬順序表

/**
 * 銷燬順序表
 */
void destoryList_sq(SqList &L) {
    free(L.elem); //釋放存儲空間
    L.length = 0;
    L.listsize = 0;
//  free(&L);
}

重點釋放順序表的存儲單元。如果順序表自身的內存也是動態分配的,需要手動釋放。

最後附上,頭文件的定義。

/*
 * sqlist.h
 *
 * 線性表的順序存儲
 *  Created on: 2016年8月30日
 *      Author: flueky
 */

#ifndef SQLIST_H_
#define SQLIST_H_

#define LIST_INIT_SIZE 50
#define LISTINCREMENT 10

typedef int SeqType; //存儲單元類型

typedef struct{
    SeqType *elem; //存儲空間基地址
    int length; //當前長度
    int listsize; //當前分配的存儲容量(以sizeof(ElemType)爲單位)
} SqList;

/**
 * 創建順序表
 */
SqList createList_sq();

/**
 * 初始化順序表
 */
int initList_sq(SqList &);

/**
 * 插入順序表
 */
int insertList_sq(SqList &,int index,SeqType);

/**
 * 插入順序表(結尾的位置)
 */
int insertList_sq(SqList &,SeqType);

/**
 * 在順序表中移除指定位置元素,下標從0開始
 */
int removeList_sq(SqList &,int,SeqType &);

/**
 * 在順序表中刪除指定元素
 */
int removeList_sq(SqList &,SeqType);
/**
 * 銷燬順序表
 */
void destoryList_sq(SqList &);

#endif /* SQLIST_H_ */

摘自嚴蔚敏版《數據結構》
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章