02-2.3.2_1 單鏈表的插入和刪除

喜歡《數據結構》部分筆記的小伙伴可以訂閱專欄,今后還會不斷更新。
此外,《程序員必備技能》專欄和《程序員必備工具》專欄(該專欄暫未開設)日后會逐步更新,

插入

按位序插入

(1)帶頭結點

ListInsert(&L, i, e)插入操作——在表L中的i個位置上插入指定元素e
找到第i-1個結點,將新結點插入其后
具體代碼實現:

//在第i個位置插入元素e(帶頭結點)
bool ListInsert(LinkList &L, int i, ElemType e){if(i<1)return false;LNode *p;//指針p指向當前掃描到的結點int j = 0;//當前p指向的是第幾個結點p = L;//L指向頭結點,頭結點是第0個結點(不存數據)while(p != NULL && j < i-1){//循環找到i-1個結點p = p->next;j++;}if(p == NULL)//i值不合法return false;LNode *s = (LNode *) malloc(sizeof(LNode));s->data = e;s->next = p->next;p->next = s;//將結點s連到p之后return true;//插入成功
}

代碼分析:

  • 如果i=1(插在表頭)
  • 如果i=3,那么i-1=2,那么j=0p會指向下個結點,所以j=1,因為j=1 < 2,所以j會再+1變成2
  • 如果i=5(插在表尾),這種情況是最壞的,最壞時間復雜度= O ( n ) O(n) O(n)
  • 如果i=6i>length),執行之后發現p == NULL,返回false
    需要注意的是:
    s->next = p->next;p->next = s;兩句順序不能顛倒

(2)不帶頭結點

ListInsert(&L, i, e)插入操作——在表L中的i個位置上插入指定元素e
找到第i-1個結點,將新結點插入其后
但是因為不存在所謂的“第0個”結點,因此當i=1時需要進行特殊處理
具體代碼實現:

bool ListInsert(LNode &L, int i, ElemType e){if(i>1)return false;if(i==1){//插入第一個結點的操作和其他結點的操作不同LNode *s = (LNode *) malloc (sizeof(LNode));s->data = e;s->next = L;L = s;//頭指針指向新結點return true;}LNode *p;//指針p指向當前掃描到的結點int j = 1;//當前p指向的是第幾個結點p = L;//p指向第1個結點(注意:不是頭結點)while(p! = NULL && j < i-1){//循環找到第i-1個結點p = p->next;j++;}if(p == NULL)//i值不合法return false;LNode *s = (LNode *) malloc (sizeof(LNode));s->data = e;s->next = p->next;p->next = s;return true;//插入成功
}

代碼分析:

  • i=1時,如果單鏈表不帶頭結點,則插入、刪除第1個元素時,需要修改頭指針L
  • i>1時,這種情況和帶頭結點的情況是一樣的,唯一需要注意的是:我們修改了int j = 1

指定結點的后插操作

//后插:在p結點之后插入元素e
bool InsertNextNode(LNode *p, ElemType e){if(p == NULL)return false;LNode *s = (LNode *) malloc (sizeof(LNode));if(s == NULL)return false;s->data = e;//用結點s保存元素es->next = p->next;p->next = s;//將結點s連到p之后return true;
}

指定結點的前插操作

//前插:在p結點之前插入元素e
bool InsertPriorNode(LNode *p, ElemType e)

前插的困難在于,單鏈表只能往后查找結點,對于給定的結點p,之前有哪些結點都是未知的
那么如何操作呢?我們可以傳入頭指針

bool InsertPriorNode(LinkList L, LNode *p, ElemType e)

傳入頭指針之后,通過循環的方式查找p的前驅結點q,然后再對q進行后插操作,并且通過這種方式操作時,時間復雜度為 O ( n ) O(n) O(n)


但是還有另一種實現方式:

bool InsertPriorNode(LNode *p, ElemType e){if(p == NULL)return false;LNode *s = (LNode *) malloc (sizeof(LNode));if(s == NULL)return false;s->next = p->next;p->next = s;//新結點s連接到p之后s->data = p->data;//將p中的元素復制到s中p->data = e;//p中的元素覆蓋為ereturn true;
}

通過這種方式的時間復雜度為 O ( 1 ) O(1) O(1)


王道書版本:

bool InsertPriorNode(LNode *p, LNode *s){if(p == NULL || s == NULL)return false;s->next = p->next;p->next = s;               //s連到p之后ElemType temp = p->data;   //交換數據部分p->data = s->data;s->data = temp;return true;
}

代碼分析:

  1. p->data: 訪問指針p所指向的結點的data成員
  2. ElemType temp: 聲明一個類型為ElemType的局部變量tempElemType通常是一個自定義的類型(例如intfloat結構體等),它表示結點中存儲的數據類型
  3. temp = p->data: 將p->data的值賦值給temp
ElemType temp = p->data; // 將 p 結點的 data 值存儲到 temp 變量中
p->data = s->data;       // 將 s 結點的 data 值賦值給 p 結點的 data
s->data = temp;          // 將 temp 中保存的原 p 結點的 data 值賦值給 s 結點的 data

通過以上步驟,p和s之間的data值就被交換了,但結點本身的位置沒有改變。這樣做的目的是為了在邏輯上實現插入前驅結點的效果。

刪除

按位序刪除

只探討帶頭結點的情況:
ListDelete(&L, i, &e)刪除操作——刪除表L中第i個位置的元素,并用e返回刪除元素的值
找到第i-1個結點,將其指針指向第i+1個結點,并釋放第i個結點
頭結點可以看做“第0個”結點
具體代碼實現:

bool ListDelete(LinkList &L, int i, ElemType &e){if(i<1)return false;LNode *p;                     //指針p指向當前掃描到的結點int j = 0;                    //當前p指向的是第幾個結點p = L;                        //L指向頭結點,頭結點是第0個結點(不存數據)while(p != NULL && j < i-1){  //循環找到第 i-1 個結點p = p->next;j++;}if(p == NULL)                 //i值不合法return false;if(p->next == NULL)           //第 i-1 個結點后,已經沒有其他結點return false;LNode *q = p->next;           //令q指向被刪除的結點e = q->data;                  //用e返回元素的值p->next = q->next;            //將 *q 結點從鏈中斷開free(q);                      //釋放結點的存儲空間return true;
}

代碼分析:

  • 在這部分代碼中:
    • LNode *q = p->next;: q 指向要刪除的第 i 個結點
    • e = q->data;: 將被刪除結點的數據存儲在 e 中
    • p->next = q->next;: 這是關鍵的一步,將 pnext 指針指向 q 的后繼結點,從而將 q 結點從鏈表中斷開。具體來說,p->next 本來指向 q,現在改為指向 q 的后繼結點 q->next
    • free(q);: 釋放 q 結點的內存。
  • 我們來更詳細地解釋 p->next = q->next; 的意義:
    • 在這條語句之前,鏈表的鏈接是這樣的:
      p --> q --> q->next
    • 執行這條語句后,鏈表的鏈接變成了這樣:
      p -> q->next
    • 這樣,q 結點就從鏈表中被移除了
  • 平均、最壞時間復雜度: O ( n ) O(n) O(n)最好時間復雜度: O ( 1 ) O(1) O(1)

指定結點的刪除

//刪除指定結點p
bool DeleteNode(LNode *p)

刪除結點p,需要修改其前驅結點的next指針
解決方法:

  1. 傳入頭指針,循環尋找 p 的前驅結點
  2. 偷天換日(類似于結點前插的實現)
bool Delete(LNode *p){if(p == NULL)return false;LNode *q = p->next;       //令q指向*p的后繼結點p->data = p->next->data;  //和后繼結點交換數據域p->next = q->next;        //將*q結點從鏈中斷開free(q);                  //釋放后繼結點的存儲空間return true;
}

p->next指向 q 結點的后繼結點(可能是NULL),這個時候 q 結點就被斷開了,釋放存儲空間即可
時間復雜度: O ( 1 ) O(1) O(1)
但是,如果 p 是最后一個結點,這一段代碼是有 bug 的。這種情況下,我們只能從頭開始依次尋找 p 的前驅
時間復雜度: O ( 1 ) O(1) O(1)

單鏈表的局限性

無法逆向檢索,有時候不太方便。如果有指向前面的指針,情況就不一樣了
這種表就是雙鏈表

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21342.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21342.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21342.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

量子加速超級計算簡介

本文轉載自&#xff1a;量子加速超級計算簡介(2024年 3月 13日) By Mark Wolf https://developer.nvidia.cn/zh-cn/blog/an-introduction-to-quantum-accelerated-supercomputing/ 文章目錄 一、概述二、量子計算機的構建塊&#xff1a;QPU 和量子位三、量子計算硬件和算法四、…

代碼隨想錄算法訓練營第三十七 | ● 738.單調遞增的數字 ● 968.監控二叉樹

738.單調遞增的數字 講解鏈接&#xff1a;https://programmercarl.com/0738.%E5%8D%95%E8%B0%83%E9%80%92%E5%A2%9E%E7%9A%84%E6%95%B0%E5%AD%97.html class Solution { public:int monotoneIncreasingDigits(int n) {//整數轉字符串&#xff0c;變為字符串訪問比諸位取出數字要…

項目集成過程中的makefile記錄

項目集成過程中的makefile記錄 文章目錄 項目集成過程中的makefile記錄1.基礎概念注釋打印賦值方式常用變量$ 偽目標函數wildcard 多目錄、文件操作 2.思路梳理**需求分析**目錄結構 3.可行示例 持續更新中1.基礎概念 注釋 # 示例&#xff1a; # 項目名稱打印 echo "H…

控制臺相關

輸入輸出 輸出 Console.WriteLine("123123");//光標空行 Console.Write("123123123123");//不空行輸入 string str Console.ReadLine(); //如果在ReadKey(true)不會把輸入的內容顯示在控制臺上 char c Console.ReadKey(true).KeyChar; Console.WriteL…

ACM實訓第25天

第四套 第一道&#xff08;修改&#xff09; #include<stdio.h> #include<string.h> int cnt[10]; void count_digits(int n,int* cnt){for(int i1;i<n;i){int numi;while(num){cnt[num%10];num/10;}} } int main(){int t;scanf("%d\n",&t);whi…

力扣刷題--2553. 分割數組中數字的數位【簡單】

題目描述 給你一個正整數數組 nums &#xff0c;請你返回一個數組 answer &#xff0c;你需要將 nums 中每個整數進行數位分割后&#xff0c;按照 nums 中出現的 相同順序 放入答案數組中。 對一個整數進行數位分割&#xff0c;指的是將整數各個數位按原本出現的順序排列成數…

名為投資實為借貸,如何處理

投資近百萬參與號稱“高回報、零風險”的內部商鋪投資項目&#xff0c;與公司簽訂商鋪投資合同及租賃合同。本想投資商鋪收取租金&#xff0c;沒想到不僅租金沒拿到手&#xff0c;連本金都要不回來。 2019年底&#xff0c;原告何某&#xff08;乙方&#xff09;與被告祁東縣某…

QSettings注冊表 json雙模式配置文件

qt QSettings 類可用來保存軟件設置&#xff0c;json文件也是保存軟件設置的很好的方式&#xff0e; 這里結合json文件和QSettings注冊表來保存軟件設置&#xff0e;區別在于json文件在軟件目錄&#xff0c;每次更新時會被覆蓋&#xff0c;注冊表中設置持久有效&#xff0c;…

14.FreeRTOS 消息緩存 Message Buffer

FreeRTOS 消息緩存&#xff08;Message Buffer&#xff09;的使用 介紹 在實時操作系統&#xff08;RTOS&#xff09;中&#xff0c;任務之間的通信是一個非常重要的方面。FreeRTOS 提供了多種機制來實現任務間通信&#xff0c;其中之一就是消息緩存&#xff08;Message Buffe…

【IC驗證】一文速通多通道數據整型器(MCDF)

目錄 01 README 02 MCDF設計結構 2.1 功能描述 2.2 設計結構 2.3 接口與時序 2.3.1 系統信號接口 2.3.2 通道從端接口 2.3.3 整形器接口 2.3.4 控制寄存器接口 2.3.4.1 接口時序圖 2.3.4.2 各數據位信息 03 驗證框圖 3.1 reg_pkg 3.1.1 reg_trans 3.1.2 reg_driv…

【一刷《劍指Offer》】面試題 27:二叉搜索樹與雙向鏈表

牛客對應題目鏈接&#xff1a;二叉搜索樹與雙向鏈表_牛客題霸_牛客網 (nowcoder.com) 力扣對應題目鏈接&#xff1a;LCR 155. 將二叉搜索樹轉化為排序的雙向鏈表 - 力扣&#xff08;LeetCode&#xff09; 一、《劍指 Offer》對應內容 二、分析題目 上面力扣上的這道題目和牛客…

AGM DAP-LINK 離線燒錄報錯信息分析

DAP-LINK 支持離線燒錄。 即&#xff1a;先把要燒錄的bin 燒錄到DAP-LINK 中&#xff1b;然后DAP-LINK 可以脫離PC&#xff0c;上電后通過按鍵對目標板進行燒錄。 CMSIS-DAP模式 跳線JGND斷開&#xff0c;狀態LED D4快閃&#xff0c;D3常亮&#xff08;串口狀態&#xff09;。…

deepin開發web前端:探索、挑戰與無限可能

deepin開發web前端&#xff1a;探索、挑戰與無限可能 在數字化浪潮洶涌的時代&#xff0c;Web前端作為連接用戶與數字世界的橋梁&#xff0c;其重要性日益凸顯。而deepin作為一款優秀的開源操作系統&#xff0c;為Web前端開發者提供了廣闊的舞臺。本文將圍繞deepin開發Web前端…

接口設計的最佳實踐-下篇

大多數程序員&#xff0c;做得最多的事&#xff0c;也不過是寫接口這件事而已。 今天繼續總結下接口設計需要注意的點。盡量每種都給出具體的場景、案例等&#xff0c;希望大家能有所收獲。 1、接口冪等 冪等性&#xff1a;是指一個操作或者一個服務&#xff0c;無論執行多少…

小程序怎樣進行本地存儲的讀、寫、刪、清?

小程序進行本地存儲的讀、寫、刪、清操作&#xff0c;可以通過微信小程序提供的API來實現。這些API分為同步和異步兩種類型&#xff0c;以滿足不同的使用場景和需求。 同步操作 同步操作會阻塞后續的代碼執行&#xff0c;直到操作完成。 寫入本地緩存&#xff08;寫&#xf…

Vue3 - Mac系統用文本編輯寫html不顯示效果的坑

平時在win系統下&#xff0c;可以直接對文本進行編輯&#xff0c;非常的舒服。 在mac系統中&#xff0c;也有類似的功能&#xff0c;就是文本編輯&#xff0c;沒想到居然還有坑。 這是我mac系統中創建的html文件&#xff0c;想著沒有幾行代碼&#xff0c;就沒有開編輯器了&am…

C語言 | Leetcode C語言題解之第125題驗證回文串

題目&#xff1a; 題解&#xff1a; bool isalumn(char c) {return (c > a && c < z) || (c > A && c < Z) || (c > 0 && c < 9); }bool isPalindrome(char* s) {for (int left 0, right strlen(s) - 1; left < right; left, …

【數據庫系統概論】事務

概述 在數據庫系統中&#xff0c;事務&#xff08;Transaction&#xff09;是指一組作為單個邏輯工作單元執行的操作。這些操作要么全部成功&#xff08;提交&#xff09;&#xff0c;要么全部失敗&#xff08;回滾&#xff09;。事務的主要目的是確保數據庫的完整性和一致性&…

AI與NLP的完美結合:揭秘ChatGPT

AI與NLP的完美結合&#xff1a;揭秘ChatGPT 一、AI大模型的發展歷程 AI大模型的發展可追溯到早期的深度學習技術。深度學習通過多層神經網絡處理復雜的數據模式&#xff0c;顯著提升了圖像識別、語音識別等領域的性能。隨后&#xff0c;研究人員將注意力轉向NLP&#xff0c;開…

【傳知代碼】多視圖3D目標檢測位置嵌入變換(論文復現)

前言&#xff1a;三維目標檢測技術正逐漸成為計算機視覺領域的重要研究方向。特別是在自動駕駛、增強現實&#xff08;AR&#xff09;、虛擬現實&#xff08;VR&#xff09;以及機器人導航等應用中&#xff0c;對三維空間內目標的精準檢測與定位顯得尤為重要。然而&#xff0c;…