鏈表及數組模擬鏈表
阿新 • • 發佈:2018-05-14
color sdn style ron 本質 變量聲明 pre 第一個 圖片
1,單向鏈表
單向鏈表是最簡單的鏈表形式。我們將鏈表中最基本的數據稱為節點(node),每一個節點包含了數據塊和指向下一個節點的指針,鏈表有一個頭指針變量,圖中以head表示。可以看出,head指向第一個元素,第一個元素又指向第二個元素……直到最後一個元素,該元素不再指向其他元素,它稱為表尾,它的地址部分為空,鏈表到此結束。
可以看到,要找鏈表中的某一元素,必須先找到上一個元素,根據它提供的下一個元素的地址才能找到下一個元素。如果不提供頭指針,則整個鏈表都無法訪問。鏈表如同一條鐵鏈一樣,一環扣一環,中間是不能斷開的。
為了理解什麽是鏈表,打一個通俗的比方:幼兒園的老師帶領孩子們出來散步,老師牽著第一個小孩的手,第一個小孩的另一只手牽著第二個孩子……這就是一個鏈,最後一個孩子有一只手空著,他是鏈尾。要找到這個隊伍,必須先找到老師,然後順序找到每一個孩子。
變量聲明:
轉載請註明出處,部分內容引自百度百科、譚浩強《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),雙向循環鏈表
最後一個節點的指針指向頭結點,且頭結點的前驅指向最後一個結點
代碼實現就不再給出,相信大家已經能夠實現。
鏈表及數組模擬鏈表