數據結構學習筆記(四)--順序表


數據結構學習筆記(四)--順序表

順序表是用順序存儲方式實現的線性表。

點擊進入上一篇:數據結構學習筆記(三)--線性表的定義和基本操作

順序表的定義

順序表 --用順序存儲的方式實現的線性表

什么是順序存儲

順序存儲:把邏輯上相鄰的元素存儲在物理位置上也相鄰的存儲單元中,元素之間的關系由存儲單元的鄰接關系來體現。

圖形表示

X67C07_HY6KL9MS_H~Q9_Z7.png

順序表的實現方式

靜態分配

定義一個靜態數組存放數據元素。

代碼實現

用c語言舉例:

#include <stdio.h>
#define MaxSize 10 //定義最大長度
typedef struct{
    in data[MaxSize]; //用靜態的“數組”存放數據元素
    int length; //順序表的當前長度
} SqList; //順序表的類型定義(靜態分配方式),自定義命名

//基本操作 ——初始化一個順序表
void InitList(SqList &L){
    for(int i=0;i<MaxSize;i++)
        L.data[i] = 0; //將所有數據元素設置為默認初始值
    L.length = 0; //順序表初始長度為0
}

注:如果沒有初始化數據結構,直接打印順序表,打印出來的數據未知(內存中的遺留數據,也稱臟數據)

靜態分配的特性

順序表的表長開始確定后無法更改(存儲空間是靜態的)

動態分配

使用指針相關知識和c語言malloc、free函數動態申請和釋放內存空間。

代碼實現

用c語言舉例:

#include <stdlib.h>
#define InitSize 10 //默認的最大長度
typedef struct{
    int *data; //指示動態分配數組的指針
    int MaxSize; //順序表的最大容量
    int length; //順序表的當前長度
} SeqList;

//基本操作 ——初始化一個順序表
void InitList(SeqList &L){
    //用malloc函數申請一片連續的存儲空間
    L.data = (int *)malloc(InitSize * sizeof(int)); //注意類型轉換
    L.length = 0;
    L.MaxSize = InitSize; //初始化順序表最大長度
}

//基本操作 ——增加動態數組的長度
void IncreaseSize(SeqList &L,int len){
    int *p = L.data; //創建一個指針將指向原data數據所在內存,類似於一個temp;
    L.data = (int *)malloc((L.MaxSize+len)*sizeof(int));//給data分配一個新的,增大后的內存空間
    //遍歷將原來的數據賦值給新的地址(時間開銷大)
    for(int i=0;i<L.length;i++){
        L.data[i] = p[i];  //將原data數據賦值給新的data
    }
    L.MaxSize = L.MaxSize +Len; //順序表最大長度增加 len,重新定義順序表最大長度
    free(p); //釋放原來的內存空間
}

順序表的特點

  1. 隨機訪問,即可以在O(1)時間內找到第i個元素。
  2. 存儲密度高,每個節點只存儲數據元素。
  3. 拓展容量不方便(即便采用動態分配的方式實現,拓展長度的時間復雜度也比較高)。
  4. 插入、刪除操作不方便,需要移動大量元素。

順序表的基本操作

順序表的初始化

順序表的實現方式中的代碼示例

順序表的插入

ListInsert(&L,i,e):插入操作。在表中第i個位置上插入指定元素e。

代碼實現

采用靜態分配的存儲方式,用c語言舉例:

bool ListInsert(SqList &L,int i,int e){
    //首先判斷參數是否合理,保持代碼的健壯性
	if(i<1 || i>L.length+1) //判斷i的范圍是否有效
    	return false;
    if(L.length>=MaxSize)
        return false;
    for(int j=L.length;j>=1;j--) //將第i個元素及之后的元素后移
        L.data[j] = L.data[j-1];
    L.data[i-1] = e; //在指定位置i處放入e。(因為線性表是位序從1開始,代碼數組下標從0開始,故為i-1)
    L.length++; //長度加1
    return true;
}

插入操作的時間復雜度

  • 最好情況:新元素插入到表尾,不需要移動元素,i = n+1,循環0次;最好時間復雜度 = O(1)
  • 最壞情況:新元素插入到表頭,需要將原有的n 個元素全部向后移動,i = 1,循環n次;最壞時間復雜度 = O(n)
  • 平均情況:假設新元素插入到任何一個位置的概率相同,即i = 1,2,3, ... ,length+1 的概率都是 p = 1/(n+1),計算構成等差數列求得,T(n) = n/2;平均時間復雜度 = O(n)

順序表的刪除

ListDelete(&L,i,&e):刪除指定位序上的元素,並用e帶回刪除數據的值。

代碼實現

采用靜態分配的存儲方式,用c語言舉例:

bool ListDelete(SqList &L,int i,int &e){
    if(i<1 || i>L.length) //判斷i的范圍是否有效
        return false;
    e = L.data[i-1]; //將被刪除的元素賦值給e
    for(int j=i;j<L.length;j++) //將第i個位置后的元素前移
        L.data[j-1]=L.data[j];
    L.length--; //線性表長度-1
    return true;
}

刪除操作的時間復雜度

  • 最好情況:刪除表尾元素,不需要移動其他元素,i = n,循環0次;最好時間復雜度 = O(1)
  • 最壞情況:刪除表頭元素,需要將后續的n-1個元素全部向前移動,i = 1,循環 n-1次;最壞時間復雜度 = O(n)
  • 平均情況:假設刪除任何一個元素的概率相同,即i = 1,2,3, ... ,length 的概率都是 p = 1/n,計算構成等差數列求得,T(n) = (n-1)/2;平均時間復雜度 = O(n)

注意事項

刪除位序為i的元素和刪除數組下標為i的元素並不相同,前者從1開始,后者從0開始。

順序表的查找

按位查找

GetElem(L,i):按照順序表位序查找數據的值,並返回數據的值。

代碼實現

采用靜態分配的存儲方式,用c語言舉例:

int GetElem(SqList L,int i){
    return L.data[i-1]; //直接返回該位序所在數組下標的值
}

注:因調用malloc函數的內存分配和定義數組的內存分配方式相似,故動態分配與靜態分配的按位查找都是如此,以查詢數組下標的形式實現。

時間復雜度

按位查找的時間復雜度:O(1) (體現順序表“隨機存取”的特性)

按值查找

LocateElem(L,e):在表中查找具有給定關鍵字值的元素,並返回其位序

代碼實現

采用靜態分配的存儲方式(當然,動態也是這么做),用c語言舉例:

int LocateElem(SqList L,int e){
    for(int i=0;i<L.length;i++){
        if(L.data[i]==e)
            return i+1; //數組下標為i的元素值等於e,返回其位序i+1
    }
    return 0; //循環結束還沒找到,說明查找失敗
}
時間復雜度
  • 最好情況:目標元素在表頭,循環1次;最好時間復雜度 = O(1)
  • 最壞情況:目標元素在表尾,循環n次;最壞時間復雜度 = O(n)
  • 平均情況:假設目標元素出現在任何一個位置的概率相同,都是1/n,平均循環次數 = (n+1)/2,平均時間復雜度 = O(n)
注意事項

《數據結構》考研初試中,手寫代碼可以直接用 “==”,無論e的數據類型是基本數據類型還是結構類型。

手寫代碼主要考察學生是否能理解算法思想,不會嚴格要求代碼完全可運行。

但如果有的學校考《C語言程序設計》,那么對語法要求就會更加嚴格。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM