日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【数据结构与算法】之链表的操作和使用

發布時間:2024/5/21 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据结构与算法】之链表的操作和使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

鏈表的定義

  • 鏈表:由一系列結點(鏈表中每一個元素稱為結點)組成,每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。

  • 鏈表這種存儲方式,其元素個數是不受限定的,當進行添加元素的時候存儲的個數就會隨之改變。
  • 鏈表和數組的優缺點對比:
數據形式優點缺點
鏈表運行時確定大小,快速插入和刪除元素不能隨機訪問,用戶必須提供編程支持
數組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 = 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 = temp->next; // 釋放當前free(pt); }// 頭尾清空,不然下次的頭就接著0x10head = 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;// 判斷K是不是超出了鏈表的長度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;}// 設置慢指針(慢指針不能為nullptr)ListNode *slowNode = pNode -> next;if(slowNode == nullptr){return nullptr;}// 設置快指針ListNode *fastNode = slowNode -> next;while(fastNode != nullptr && slowNode != nullptr){// 相遇返回快/慢指針if(fastNode == slowNode){return fastNode;}// slow走一步slowNode = slowNode ->next;// fast走兩步(走下一步需要判讀是不是為nullptr)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; }

總結

以上是生活随笔為你收集整理的【数据结构与算法】之链表的操作和使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。