1. 程式人生 > >鏈表及數組模擬鏈表

鏈表及數組模擬鏈表

color sdn style ron 本質 變量聲明 pre 第一個 圖片

轉載請註明出處,部分內容引自百度百科、譚浩強《C程序設計》、蝸牛君的奮鬥史大神的博客



前置知識: C語言入門



數組黨的福音(本蒟蒻學鏈表時不會指針,然而好像所有人都拿指針寫)
首先,我們需要知道什麽是鏈表
百度百科
看不懂勿噴(畢竟百度百科也不是用來讓人看懂的)
我們可以從中得出鏈表的特性:
鏈表是一種物理存儲單元上非連續、非順序的存儲結構
提取主謂賓:鏈表是存儲結構。我認為這就是鏈表的本質——一種數據結構。
那麽非連續、非線性有什麽含義呢?這表明鏈表的內存是不連續的,前一個元素存儲地址的下一個地址中存儲的不一定是下一個元素。鏈表通過一個指向下一個元素地址的引用將鏈表中的元素串起來。
鏈表分為三類:單向鏈表、雙向鏈表、循環鏈表


1,單向鏈表
單向鏈表是最簡單的鏈表形式。我們將鏈表中最基本的數據稱為節點(node),每一個節點包含了數據塊和指向下一個節點的指針,鏈表有一個頭指針變量,圖中以head表示。可以看出,head指向第一個元素,第一個元素又指向第二個元素……直到最後一個元素,該元素不再指向其他元素,它稱為表尾,它的地址部分為空,鏈表到此結束。
技術分享圖片
可以看到,要找鏈表中的某一元素,必須先找到上一個元素,根據它提供的下一個元素的地址才能找到下一個元素。如果不提供頭指針,則整個鏈表都無法訪問。鏈表如同一條鐵鏈一樣,一環扣一環,中間是不能斷開的。
為了理解什麽是鏈表,打一個通俗的比方:幼兒園的老師帶領孩子們出來散步,老師牽著第一個小孩的手,第一個小孩的另一只手牽著第二個孩子……這就是一個鏈,最後一個孩子有一只手空著,他是鏈尾。要找到這個隊伍,必須先找到老師,然後順序找到每一個孩子。

變量聲明:

const int maxn=1010;
struct node{    //point即指針,data就是需要維護的數據
    int point,data;
}a[maxn];
int head,cnt;    //head即頭指針,cnt即內存池計數器

建立:

head=++cnt;        //把head設為沒有實際意義的哨兵
a[head].data=0;

插入(插入數據now到第k個元素之後):

add(++k,now);    //進入,因為計算時考慮了哨兵,所以進入時++k
void add(int k,int now)
{
    for(int i=head;i;i=a[i].point)    //
從頭指針開始遍歷鏈表 if(!(--k)) //到達插入位置 { a[++cnt].point=a[i].point; //將新插入節點的指針指向插入位置的後繼 a[i].point=cnt; //將前驅節點的指針指向新插入節點 a[cnt].data=now; break; } }

技術分享圖片
刪除(刪除第k個元素):

del(++k);    //進入
void del(int k)
{
    for(int i=head;i;i=a[i].point)
        if((--k)==1)    //找到前驅
        {
            a[i].point=a[a[i].point].point;        //將前驅的指針指向後繼
            break;
        }
}

技術分享圖片
遍歷鏈表:

for(int i=a[head].point;i;i=a[i].point)
    cout<<a[i].data<<endl;

2,雙向鏈表
顧名思義,雙向鏈表就是有兩個方向的鏈表。同單向鏈表不同,在雙向鏈表中每一個節點不僅存儲指向下一個節點的指針,而且存儲指向前一個節點的指針。它的優點是訪問、插入、刪除更方便。但“是以空間換時間”。
技術分享圖片
變量聲明:

struct node{
    int pre,nxt,data;    //前驅和後繼
}a[maxn];
int head,cnt;

插入:

void add(int k,int now)
{
    for(int i=head;i;i=a[i].nxt)
        if(!(--k))
        {
            a[++cnt].nxt=a[i].nxt;    //這兩個和單鏈表一樣
            a[i].nxt=cnt;
            a[a[cnt].nxt].pre=cnt;    //將後繼的前驅更新為新插入節點
            a[cnt].pre=i;    //將新插入節點的前驅設為其前驅
            a[cnt].data=now;
            break;
        }
}

技術分享圖片
刪除:

void del(int k)
{
    for(int i=head;i;i=a[i].nxt)
        if(!(--k))
        {
            a[a[i].pre].nxt=a[i].nxt;
            a[a[i].nxt].pre=a[i].pre;
            break;
        }
}

3,循環鏈表
(1),單向循環鏈表
最後一個節點的指針指向頭結點
(2),雙向循環鏈表
最後一個節點的指針指向頭結點,且頭結點的前驅指向最後一個結點
代碼實現就不再給出,相信大家已經能夠實現。

鏈表及數組模擬鏈表