線性表

學習內容來自數據結構詳解——線性表(C++實現)

線性表(List):零個或多個數據元素的有限序列俊犯。
順序表(數組):元素地址單元連續(xù)。
鏈表:結點地址不連續(xù)伤哺,由指針指向下個元素地址燕侠。

一、線性表的抽象數據類型

ADT 線性表(List)
Data
    線性表的數據對象集合為{a1,a2,....,an},每個元素的類型均為DataType立莉。其中绢彤,除了第一個元素a1外,每一個元素有且只有一個直接前驅元素桃序,除最后一個元素an外杖虾,每一個元素有且只有一個直接后繼元素烂瘫。數據元素之間的關系是一對一的關系媒熊。

Operation
    InitList(*L):初始化操作,建立一個空的線性表坟比。
    ListEmpty(L):若線性表為空芦鳍,返回true,否則返回false葛账。
    ClearList(*L):線性表清空柠衅。
    GetElem(L,i,*e):將線性表L中第i個位置元素返回給e。
    LocateElem(L,e):在線性表L中查找與給定值e相等的元素籍琳,如果查找成功,返回該元素在表中的序列號菲宴;否則,返回0表示失敗趋急。
    ListInsert(*L,i,e):在線性表的第i個位置插入元素e喝峦。
    ListDelete(*L,i,*e):刪除線性表L中的第i個元素,并用e返回其值
    ListLength(L):返回線性表L的元素個數呜达。
    PrintList(L):打印線性表

對于不同的應用谣蠢,線性表的基本操作是不同的,上述操作是最基本的。
對于實際問題中涉及的關于線性表的更復雜操作眉踱,完全可以用這些基本操作的組合來實現挤忙。

二、順序儲存結構

定義:用一段連續(xù)地址單元依次儲存
結構:
順序表模板類代碼:

//順序存儲
const int MaxSize = 100;
template <class DataType>
class SeqList
{
public:
    SeqList() { length = 0; } //無參數構造
    SeqList(DataType[], int n); //有參數構造
    ~SeqList() {}
    int Length() { return length; }//返回線性表長度
    DataType Get(int i);//按位查找
    int Locate(DataType x);//按值查找
    void Insert(int i, DataType x);//插入
    DataType Delete(int i);//刪除
    void PrintList();//遍歷
private:
    DataType data[MaxSize];  //順序列表采用數組實現
    int length;
};

順序表描述需要三個屬性:

  • 儲存空間的起始位置:數組data
  • 線性表最大儲存容量:數組長度MaxSize
  • 線性表當前長度:length
有參數構造:

創(chuàng)建一個長度為n的順序表谈喳,需要將給定的數組元素作為線性表的數據元素傳入順序表中册烈,并將傳入的元素個數作為順序表的長度。


template <class DataType>
SeqList<DataType>::SeqList(DataType a[],int n) 
{
    if (n > MaxSize) throw"wrong parameter";
    for (int i = 0; i < MaxSize; i++)
        data[i] = a[i];
    length = n;
}
按位查找

時間復雜度O(1).

template <class DataType>
DataType SeqList<DataType>::Get(int i)
{
    if (i<1 && i>length) throw "wrong locate";
    else
        return data[i - 1];
}
按值查找

對順序表元素依次比較叁执,返回下標+1茄厘。

template<class DataType>
int SeqList<DataType>::Locate(DataType x)
{
    for (int i = 0; i < length; i++)
        if (data[i] == x) return i + 1;
    return 0;
}
插入
  • 注意移動方向,必須從最后一個元素開始移動谈宛。
  • 表滿次哈,引發(fā)上溢異常;插入位置不合理吆录,引發(fā)位置異常窑滞。


template<class DataType>
void SeqList<DataType>::Insert(int i, DataType x)
{
    if (length == MaxSize) throw  "overSize";
    if (i<1 || i>length + 1) throw "eror Location";
    
    for (int j=length; j > i-1; j--)
    {
        data[j] = data[j-1];
    }
    data[i - 1] = x;
    length++;
}
刪除
  • 注意元素移動方向,移動元素前需取出被刪元素恢筝。
  • 表為空哀卫,則發(fā)生下溢;位置不合理異常撬槽,引發(fā)位置


template<class DataType>
DataType SeqList<DataType>::Delete(int i)
{
    if (i<1 || i>length + 1) throw "eror Location";
    DataType x = data[i - 1];
    for (int j = i; j < length; j++)
    {
        data[j-1] = data[j];
    }
    length--;
    return x;
}
遍歷
template<class DataType>
void SeqList<DataType>::PrintList()
{
    for (int i = 0; i < length; i++)
        std::cout << data[i] << std::endl;
}
順序儲存的優(yōu)缺點

優(yōu)點:

  • 隨機訪問特性此改,查找時間O(1),存儲密度高
  • 無須為邏輯關系增加額外儲存空間
    缺點:
  • 插入、刪除需移動大量數據元素
  • 線性表長度變化大侄柔,難以確定儲存空間
  • 造成儲存空間“碎片化”

三共啃、鏈式儲存

1.鏈式儲存定義

鏈表的定義是遞歸的,它或者為空null暂题,或者指向另一個節(jié)點node的引用移剪,這個節(jié)點含有下一個節(jié)點或鏈表的引用,線性鏈表的最后一個結點指針為“空”(通常用NULL或“^”符號表示)薪者。


2.鏈式儲存實現方式

儲存方法

//鏈表
template<class DataType>
struct Node  //結構體模板
{
    DataType data; //儲存數據
    Node<DataType> *next; //儲存下一節(jié)點地址(傳遞自定義類型參數DataType)
};

結點由存放數據元素的數據域和存放后繼結點地址的指針域組成纵苛。


結構
單鏈表模板類代碼:

template<class DataType>
class LinkList 
{
public:
    LinkList();
    LinkList(DataType [],int n);
    ~LinkList();
    int Length();//返回線性表長度
    DataType Get(int i);//按位查找
    int Locate(DataType x);//按值查找
    void Insert(int i, DataType x);//插入
    DataType Delete(int i);//刪除
    void PrintList();//遍歷
private:
    Node<DataType> *first;
};

特點

  • 一組任意儲存單元儲存線性表數據元素——未被占用的任意位置
  • 鏈式儲存需存放數據、后繼元素存儲地址

無參數構造
生成只有頭結點的空鏈表

template<class DataType>
LinkList<DataType>::LinkList()
{
    first = new Node<DataType>; //new頭指針指向的頭地址
    first->next = NULL; //初始化頭指針
}
有參數構造單鏈表
  • 頭插法構造


//頭插法:將新申請的結點插在頭結點后面 
template<class DataType>
LinkList<DataType>::LinkList(DataType a[], int n)
{
    first = new Node<DataType>;
    first->next = NULL;
    for (int i = 0; i < n; i++)
    {
        Node<DataType> *s = new Node<DataType>;
        s->data = a[i];
        s->next = first->next;
        first->next = s;
    }
}

  • 尾插法構造


//尾插法:將新申請的結點插在終端節(jié)點的后面 
template<class DataType>
LinkList<DataType>::LinkList(DataType a[], int n)
{
    first = new Node<DataType>;
    Node<DataType> *r = first;
    for (int i = 0; i < n; i++)
    {
        Node<DataType> *s = new Node<DataType>;
        s->data = a[i];
        r->next = s;
        r = s; 
    }
    r->next = NULL; //終端結點指針域置空
}
析構函數

單鏈表中結點通過new申請言津,需通過析構中的delete進行釋放攻人。

template<class DataType>
LinkList<DataType>::~LinkList()
{
    while (first != NULL) //頭地址不為空,鏈表有值
    {
        Node<DataType> *q = first;
        first = first->next;
        delete q;
    }
}
計算長度

將單鏈表掃描一遍,悬槽,時間復雜度為O(n)

//時間復雜度O(n)
template<class DataType>
int LinkList<DataType>::Length()
{
    Node<DataType> *p = first->next;
    int count = 0;
    while (p != NULL)
    {
        p = p->next;
        count++;
    }
    return count;
}
按位查找

單鏈表中即使知道節(jié)點位置也不能直接訪問怀吻,需要從頭指針開始逐個節(jié)點向下搜索,平均時間性能為O(n)陷谱,單鏈表是順序存取結構

DataType LinkList<DataType>::Get(int i)
{
    Node<DataType> *p = first->next;
    int count = 1;
    while (p != NULL && count < i)
    {   
        p = p->next;
        count++;
    }
    if (p == NULL) throw "no data"; //未找到
    else return p->data; 
}
按值查找

單鏈表中按值查找與順序表中的實現方法類似烙博,對鏈表中的元素依次進行比較瑟蜈,平均時間性能為O(n).

template<class DataType>
int LinkList<DataType>::Locate(DataType x)
{
    Node<DataType> *p = first->next;
    int count = 1;
    while (p != NULL)
    {
        if (p->data == x)
            return count;
        p = p->next;//移動查詢指針
        count++;
    }
    return 0;//no found
}
插入

單鏈表在插入過程中需要注意分析在表頭、表中間渣窜、表尾的三種情況铺根,由于單鏈表帶頭結點,這三種情況的操作語句一致乔宿,不用特殊處理位迂,時間復雜度為O(n).

template<class DataType>
void LinkList<DataType>::Insert(int i, DataType x)
{
    Node<DataType> *p = first;
    int count = 0;
    while (p != NULL && count < i - 1){
        p = p->next;
        count++;
    }
    if (p == NULL) throw"Location";
    else {
        Node<DataType> *s = new Node<DataType>;
        s->data = x;
        s->next = p->next;
        p->next = s;
    }
}
刪除

刪除操作時需要注意表尾的特殊情況,此時雖然被刪結點不存在详瑞,但其前驅結點卻存在掂林。因此僅當被刪結點的前驅結點存在且不是終端節(jié)點時,才能確定被刪節(jié)點存在坝橡,時間復雜度為O(n)

template<class DataType>
DataType LinkList<DataType>::Delete(int i)
{
    Node<DataType> *p = first;
    int count = 0;
    while (p != NULL && count < i -1 )
    {
        p = p->next;
        count++;
    }
    if (p == NULL || p->next == NULL) throw "Location"; //注意不能是終端結點
    else
    {
        Node<DataType> *q = p->next;
        p->next = q->next;
        return q->data;
    }
}

遍歷
template<class DataType>
void LinkList<DataType>::PrintList()
{
    Node<DataType> *p = first->next;
    while (p != NULL )
    {
        std::cout << p->data << std::endl; 
        p = p->next;    
    }
}
鏈式儲存優(yōu)缺點

優(yōu)點:

  • 插入泻帮、刪除無需移動其他元素,只用改變指針
  • 鏈表各結點內存空間無需連續(xù)计寇,利用率高

缺點:

  • 查找需遍歷

四锣杂、其他類型鏈表

循環(huán)鏈表
  • 特點是表中最后一個結點的指針域指向頭結點,整個鏈表形成一個環(huán)番宁。(通常為了使空表和非空表的處理一致元莫,通常也附加一個頭結點)
  • 通常以判斷指針是否等于某一指定指針來判定是否掃描了整個循環(huán)鏈表。


雙鏈表

循環(huán)鏈表雖然可以從任意結點出發(fā)掃描其他結點蝶押,但是如果要查找其前驅結點踱蠢,則需遍歷整個循環(huán)鏈表。為了快速確定任意結點的前驅結點棋电,可以再每個節(jié)點中再設置一個指向前驅結點的指針域茎截,這樣就形成了雙鏈表。


儲存方法:

template<class DataType>
struct Node
{
    DataType data;
    Node<DataType> *prior,*next;
};

結點p的地址既存儲在其前驅結點的后繼指針域內离陶,又存儲在它后繼結點的前驅指針域中
需要注意:

  • 循環(huán)雙鏈表中求表長稼虎、按位查找衅檀、按值查找招刨、遍歷等操作的實現與單鏈表基本相同。
  • 插入操作需要修改4個指針哀军,并且要注意修改的相對順序沉眶。
靜態(tài)鏈表

靜態(tài)鏈表是用數組來表示單鏈表,用數組元素的下標來模擬單鏈表的指針.
靜態(tài)鏈表儲存儲存:

const int MaxSize = 100;
template<class DataType>
struct Node{
    DataType data;
    int next;
}SList[MaxSize];

靜態(tài)鏈表雖然是用數組來存儲線性表的元素杉适,但在插入和刪除操作時谎倔,只需要修改游標,不需要移動表中的元素猿推,從而改進了在順序表中插入和刪除操作需要移動大量元素的缺點片习,但是它并沒有解決連續(xù)存儲分配帶來的表長難以確定的問題

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末捌肴,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子藕咏,更是在濱河造成了極大的恐慌状知,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孽查,死亡現場離奇詭異饥悴,居然都是意外死亡,警方通過查閱死者的電腦和手機盲再,發(fā)現死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門西设,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人答朋,你說我怎么就攤上這事贷揽。” “怎么了梦碗?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵擒滑,是天一觀的道長。 經常有香客問我叉弦,道長丐一,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任淹冰,我火速辦了婚禮库车,結果婚禮上,老公的妹妹穿的比我還像新娘樱拴。我一直安慰自己柠衍,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布晶乔。 她就那樣靜靜地躺著珍坊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪正罢。 梳的紋絲不亂的頭發(fā)上阵漏,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音翻具,去河邊找鬼履怯。 笑死,一個胖子當著我的面吹牛裆泳,可吹牛的內容都是我干的叹洲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼工禾,長吁一口氣:“原來是場噩夢啊……” “哼运提!你這毒婦竟也來了蝗柔?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤民泵,失蹤者是張志新(化名)和其女友劉穎诫咱,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體洪灯,經...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡坎缭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了签钩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掏呼。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖铅檩,靈堂內的尸體忽然破棺而出憎夷,到底是詐尸還是另有隱情,我是刑警寧澤昧旨,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布拾给,位于F島的核電站,受9級特大地震影響兔沃,放射性物質發(fā)生泄漏蒋得。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一乒疏、第九天 我趴在偏房一處隱蔽的房頂上張望额衙。 院中可真熱鬧,春花似錦怕吴、人聲如沸窍侧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伟件。三九已至,卻和暖如春议经,著一層夾襖步出監(jiān)牢的瞬間斧账,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工爸业, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留其骄,地道東北人亏镰。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓扯旷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親索抓。 傳聞我的和親對象是個殘疾皇子钧忽,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容