生活随笔
收集整理的這篇文章主要介紹了
【数据结构与算法】之链表的操作和使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
鏈表的定義
- 鏈表:由一系列結點(鏈表中每一個元素稱為結點)組成,每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。
- 鏈表這種存儲方式,其元素個數是不受限定的,當進行添加元素的時候存儲的個數就會隨之改變。
- 鏈表和數組的優缺點對比:
數據形式優點缺點
| 鏈表 | 運行時確定大小,快速插入和刪除元素 | 不能隨機訪問,用戶必須提供編程支持 |
| 數組 | C直接支持,提供隨機訪問 | 在編譯時確定大小,插入和刪除元素很費時 |
- 在鏈表中有一個頭指針變量,這個指針變量保存一個地址,通過這個地址來找到這個鏈表,頭指針節點指向第一個節點,在鏈表中每個節點包含兩個部分:數據部分和指針部分。雖然結構體不能含有與本身類型相同的結構,但是可以含有之相同類型結構的指針,這種定義是鏈表的基礎,鏈表中每一項都包含在何處能找到下一項的信息。而最后一個節點的指針指向必須為空NULL,從鏈表的原理來看不用擔心鏈表的長度會超出范圍這種問題。
- 鏈表的聲明
typedef struct ListNode
{int val
;struct ListNode
* next
;ListNode(int x
) :val(x
), next(NULL){}
};
鏈表的基本操作
一、創建單鏈表
- 創建頭節點head,并且將當前結點p指向頭結點(p=head);
- 創建下一個結點q,當前結點p的下一結點為q(p->next=q);
- 結點p后移一位(p = p->next);
#include <iostream>
#include<vector>using namespace std
;struct ListNode
{int val
;struct ListNode
* next
;ListNode(int x
) :val(x
), next(NULL){}
};int main(){int num
;cin
>> num
;ListNode
*head
= new
ListNode(num
);ListNode
*p
= head
;while (cin
>> num
){ListNode
* q
= new
ListNode(num
);p
->next
= q
; p
= p
->next
;}ListNode
*m
= head
;while (m
!= nullptr
){cout
<< m
->val
<< endl
;m
= m
->next
;}return 0;
}
二、插入節點
- 判斷原鏈表是否是空鏈表,如果是,將head指向新增結點;
- 如果不是空鏈表,向鏈表尾部插入新結點;
ListNode
* insertNode(ListNode
* head
, int data
){ListNode
*newNode
= new
ListNode(data
);ListNode
*p
= head
;if (p
== nullptr
){head
= newNode
;} else {while (p
->next
!= nullptr
){p
= p
->next
;}p
->next
= newNode
;}return head
;
}
三、刪除節點
ListNode
*deleteNode(ListNode
* head
, int data
){ListNode
*p
= head
;if (p
== nullptr
){return head
;} else {if (p
->val
== data
){head
= p
->next
;delete p
;return head
;} else {while (p
->next
!= nullptr
&& p
->next
->val
!= data
){p
= p
->next
;}if (p
->next
== nullptr
){return head
;} else {ListNode
*deleteNode
= p
->next
;p
->next
= deleteNode
->next
;delete deleteNode
;return head
;}}}
}
四、遍歷鏈表
- 定義一個用于遍歷的臨時指針,用while循環實現遍歷輸出等操作;
void ScanList() {struct Node
*temp
= head
; while (temp
!= NULL){printf("%d\n",temp
->a
);temp
= temp
->next
; }
}
五、 查詢指定的節點(遍歷)
struct Node
*FindNode(int a
) {struct Node
*temp
= head
;while(temp
!= NULL) {if(a
== temp
->a
) {return temp
;}temp
= temp
->next
;}return NULL;
}
六、鏈表清空
- FreeList函數仍是采用遍歷的方式一個一個的將節點內存釋放,最后實現全部刪除的效果,但是要注意在最后應該講頭尾節點至NULL否則下次的鏈表將會接著這次的頭尾。
void FreeList() {struct Node
*temp
= head
; while (temp
!= NULL) {struct Node
*pt
= temp
;temp
= temp
->next
; free(pt
); }head
= NULL;end
= NULL;
}
七、反轉鏈表
- 假設pNode是當前的節點,pPrev是pNode前面的節點,PNext是PNode后面的節點,那么:
-
- 當pNode不為nullptr,且pNext不為nullptr的時候:
① 將pNode指向pPrev(pNode->next = pPrev);
② 將pNode給pPrev(pPrev= pNode);
③ 將pNext給pNode(pNode = pNext);
-
- 當pNode不為nullptr,且pNext==nullptr的時候,把反轉后的頭部指向pNode;
#include <iostream>
#include<vector>using namespace std
;struct ListNode
{int val
;struct ListNode
*next
;ListNode(int x
) :val(x
), next(NULL){}
};
ListNode
*reverse(ListNode
*head
) {ListNode
*pPrev
= nullptr
;ListNode
*p
= head
;ListNode
*pReverseHead
= nullptr
;while (p
!= nullptr
){ListNode
*pNext
= p
->next
;if (pNext
== nullptr
){pReverseHead
= p
;}p
->next
= pPrev
;pPrev
= p
;p
= pNext
;}return pReverseHead
;
}int main(){int num
;cin
>> num
;ListNode
*head
= new
ListNode(num
);ListNode
*p
= head
;while (cin
>> num
){ListNode
*q
= new
ListNode(num
);p
->next
= q
;p
= p
->next
;}p
->next
= nullptr
;ListNode
*result
= reverse(head
);ListNode
*node
= result
;while (node
!= nullptr
){cout
<< node
->val
<< endl
;node
= node
->next
;}return 0;
}
八、倒數第K個節點
- 設置快慢指針,快指針比慢指針多走k-1步,那么快指針走到終點的時候,慢指針指向倒數第K個結點;
ListNode
*FindKthToTail(ListNode
*pListHead
, unsigned int k
) {if (pListHead
== nullptr
|| k
== 0){return nullptr
;}ListNode
*pAhead
= pListHead
;for (int i
= 0; i
< k
- 1; i
++){if (pAhead
->next
!= nullptr
){pAhead
= pAhead
->next
;} else {return nullptr
;}}ListNode
*pBehind
= pListHead
;while (pAhead
->next
!= nullptr
){pAhead
= pAhead
->next
;pBehind
= pBehind
->next
;}return pBehind
;
}
九、判斷鏈表是否有環
- 可以設置快慢指針,快指針一次走兩步,慢指針一次走一步,如果快指針追上了走的慢的指針,那么鏈表有環,如果走到了鏈表尾部都沒有追上,說明鏈表無環。
- 如果有環,返回入口節點:返回的節點一定在環內,如果計算出環中節點的個數count,快指針比慢指針多走count步,那么兩個指針相遇時,就是環的入口節點。
ListNode
*MeetNode(ListNode
*pHead
){ListNode
*pNode
= pHead
;if(pNode
== nullptr
){return nullptr
;}ListNode
*slowNode
= pNode
-> next
;if(slowNode
== nullptr
){return nullptr
;}ListNode
*fastNode
= slowNode
-> next
;while(fastNode
!= nullptr
&& slowNode
!= nullptr
){if(fastNode
== slowNode
){return fastNode
;}slowNode
= slowNode
->next
;fastNode
= fastNode
-> next
;if (fastNode
-> next
!= nullptr
){fastNode
= fastNode
-> next
;}}return nullptr
;
}
int Count(ListNode
*pMeet
){int count
= 0;ListNode
* pNode
= pMeet
;while(pNode
->next
!= pMeet
){++count
;pNode
= pNode
-> next
;}++ count
;return count
;
}
ListNode
*EntryNodeOfLoop(ListNode
*pHead
) {ListNode
*meetNode
= MeetNode(pHead
);if (meetNode
== nullptr
){return nullptr
;}int count
= Count(meetNode
);ListNode
*aheadNode
= pHead
;ListNode
*behindNode
= pHead
;for(int i
= 0; i
< count
; i
++){aheadNode
= aheadNode
->next
;}while(aheadNode
!= behindNode
){aheadNode
= aheadNode
-> next
;behindNode
= behindNode
-> next
;}ListNode
*result
= aheadNode
;return result
;
}
總結
以上是生活随笔為你收集整理的【数据结构与算法】之链表的操作和使用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。