【Python 數據結構 4.單向鏈表】

目錄

一、單向鏈表的基本概念

1.單向鏈表的概念

2.單向鏈表的元素插入

元素插入的步驟

3.單向鏈表的元素刪除

元素刪除的步驟

4.單向鏈表的元素查找

元素查找的步驟

5.單向鏈表的元素索引

元素索引的步驟

6.單向鏈表的元素修改

元素修改的步驟

二、Python中的單向鏈表

?編輯

三、單向鏈表實戰

1.面試題 02.02. 返回倒數第 k 個節點

快慢指針法

思路與算法

2.83. 刪除排序鏈表中的重復元素

方法一 雙指針判斷

方法二 一次遍歷進行判斷

3.面試題 02.01. 移除重復節點

方法一、哈希表標記法

方法二、字典

四、單向鏈表的應用

MMO游戲開發 —— AOI(Area of Interest)


惟愿春日不遲,相逢終有時

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? —— 25.3.2

一、單向鏈表的基本概念

1.單向鏈表的概念

????????對于順序存儲的結構,最大的缺點就是:插入刪除 的時候需要移動大量的元素,所以基于前人的智慧,他們發明了鏈表。

????????鏈表是由一個個結點組成,每個結點之間通過鏈接關系串聯起來,每個結點都有一個后繼結點,最后一個結點的后繼結點為空結點,如圖所示:

????????由鏈接關系 A ->B 組織起來的兩個結點,B 被稱為 A的后繼結點,A 被稱為 B 的前驅結點。鏈表分為:單向鏈表、雙向鏈表、循環鏈表等等。

????????一個鏈表結點由兩部分組成:數據域指針域。數據可以是任意類型,由編碼的人自行指定。指針域 指向 后繼結點 的地址。一個結點包含的兩部分,如下圖所示:


2.單向鏈表的元素插入

????????單向鏈表的元素插入,就是指給定一個索引 i 和一個元素 data,生成一個值為 data 的結點,并且插入到第i個位置上。

元素插入的步驟

第1步:判斷插入位置是否合法,如果不合法則拋出異常(比如:原本只有5個元素,給定的索引是100,那顯然這個位置是不合法的)

第2步:對給定的元素,生成一個鏈表結點。

第3步:如果插入位置是 0,則直接把生成的結點的后繼結點,設置為當前的鏈表頭結點,并且把生成的結點設置為新的鏈表頭,

第4步:如果插入位置不是 0,則遍歷到插入位置的前一個位置,把生成的結點插入進來

第5步:更新鏈表的大小,即對鏈表的元素執行加一操作。


3.單向鏈表的元素刪除

????????單向鏈表的元素刪除,就是指給定一個索引 i,將從鏈表頭開始數到的第 i 個結點刪除。

元素刪除的步驟

第1步:判斷刪除位置是否合法,如果不合法則拋出異常。

第2步:如果刪除位置為首個結點,直接把鏈表頭更新為它的后繼結點,

第3步:如果刪除位置非首個結點,則遍歷到要刪除位置的前一個結點,并且把前一個結點的后繼結點設置為它后繼的后繼。

第4步:更新鏈表的大小,也就是將鏈表的大小執行減一操作。


4.單向鏈表的元素查找

????????單向鏈表的元素查找,是指在鏈表中查找指定元素 x 是否存在,如果存在則返回該結點,否則返回 null。由于需要遍歷整個鏈表進行元素對比,所以查找的時間復雜度為 (n)。

元素查找的步驟

第1步:遍歷整個鏈表,對鏈表中的每個元素,和指定元素進行比較,如果相等則返回當前遍歷到的結點;

第2步:如果遍歷完整個鏈表,都沒有找到相等的元素,則返回 NULL;


5.單向鏈表的元素索引

????????單向鏈表的元素索引,是指給定一個索引值 i,從鏈表頭結點開始數,數到第 i 個結點并且返回它,時間復雜度 O(n)。

元素索引的步驟

第1步:首先判斷給定的索引是否合法,不合法就拋出異常

第2步:直接通過索引訪問即可獲得對應的元素;


6.單向鏈表的元素修改

? ? ? ? 單向鏈表的元素修改是指將鏈表中指定索引的元素更新為新的值。

元素修改的步驟

第1步:直接通過索引訪問即可獲得對應的結點,修改成指定的值;


二、Python中的單向鏈表

class ListNode:def __init__(self, x):self.val = xself.next = Noneclass LinkedList:def __init__(self):self.head = Noneself.len = 0def size(self):return self.lendef insert(self, pos, val):if pos < 0 or pos > self.len:raise ValueError("index out of range")new_node = ListNode(val)if pos == 0:new_node.next = self.headself.head = new_nodeelse:prev = self.headfor _ in range(pos - 1):prev = prev.nextnew_node.next = prev.nextprev.next = new_nodeself.len += 1def delete(self, pos):if pos < 0 or pos >= self.size():raise ValueError("index out of range")if pos == 0:self.head = self.head.nextelse:prev = self.headfor _ in range(pos - 1):prev = prev.nextprev.next = prev.next.nextself.len -= 1def update(self, pos, val):if pos < 0 or pos >= self.size():raise ValueError("index out of range")curr = self.headfor _ in range(pos):curr = curr.nextcurr.val = valdef search(self, val):curr = self.headwhile curr:if curr.val == val:return currcurr = curr.nextreturn Nonedef index(self, val):index = 0curr = self.headwhile curr:if curr.val == val:return indexcurr = curr.nextindex += 1return -1def print(self):curr = self.headwhile curr:print(curr.val, end=" -> ")curr = curr.nextprint(None)def Test():list = LinkedList()list.insert(0, 1)list.print()list.insert(1, 1)list.print()list.insert(2, 4)list.print()list.insert(0, 1)list.print()list.insert(1, 1)list.print()list.insert(2, 4)list.print()list.update(2, 5)list.print()list.delete(2)list.print()list.insert(2, 4)list.print()list.update(4, 1)list.print()node = list.search(4)if node:print("Node found:", node.val)else:print("Node not found")x = list.index(4)print("Index of 4:", x)x = list.index(5)print("Index of 5:", x)Test()


三、單向鏈表實戰

1.面試題 02.02. 返回倒數第 k 個節點

實現一種算法,找出單向鏈表中倒數第 k 個節點。返回該節點的值。

注意:本題相對原題稍作改動

示例:

輸入: 1->2->3->4->5 和 k = 2
輸出: 4

說明:

給定的?k?保證是有效的。

快慢指針法

思路與算法

① 初始化兩個指針fast?和?slow,它們都指向鏈表的頭節點?head

② 移動快指針:讓?fast?指針先向前移動?k?步。

③ 同步移動快慢指針:當?fast?指針移動到鏈表的末尾時,slow?指針正好指向倒數第?k?個節點。

④ 返回結果:返回?slow?指針所指向節點的值。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def kthToLast(self, head: Optional[ListNode], k: int) -> int:fast = headslow = headwhile k > 0:fast = fast.nextk -= 1while fast:fast = fast.nextslow = slow.nextreturn slow.val


2.83. 刪除排序鏈表中的重復元素

給定一個已排序的鏈表的頭?head?,?刪除所有重復的元素,使每個元素只出現一次?。返回?已排序的鏈表?。

示例 1:

輸入:head = [1,1,2]
輸出:[1,2]

示例 2:

輸入:head = [1,1,2,3,3]
輸出:[1,2,3]

提示:

  • 鏈表中節點數目在范圍?[0, 300]?內
  • -100 <= Node.val <= 100
  • 題目數據保證鏈表已經按升序?排列?

方法一 雙指針判斷

思路與算法

① 初始化指針curr?指針從鏈表的頭節點?head?開始。prev?指針初始化為?None,用于記錄當前節點的前一個節點。

② 遍歷鏈表:外層?while?循環用于遍歷整個鏈表,直到?curr?為?None。內層?while?循環用于處理當前節點?curr?與前一個節點?prev?值相同的情況。如果發現重復,則將?prev.next?指向?curr.next,從而跳過重復的節點。

③ 更新指針:如果沒有發現重復,則更新?prev?為當前節點?curr,并將?curr?移動到下一個節點。?

④ 返回結果:最終返回處理后的鏈表頭節點?head

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:curr = headprev = Nonewhile curr:while prev != None and curr.val == prev.val:prev.next = curr.nextcurr = prev.nextif curr == None:breakif curr == None:breakprev = currcurr = curr.nextreturn head


方法二 一次遍歷進行判斷

思路與算法

① ?初始化curr指針指向鏈表的頭節點head

② 空鏈表處理:如果鏈表為空(curr == None),直接返回head

?③?遍歷鏈表:如果當前節點的值curr.val與下一個節點的值curr.next.val相同,則通過curr.next = curr.next.next刪除下一個節點。如果值不相同,則移動curr指針到下一個節點。

④ 返回結果:最終返回處理后的鏈表頭節點head

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:curr = headif curr == None:return headwhile curr.next:if curr.val == curr.next.val:curr.next = curr.next.nextelse:curr = curr.nextreturn head


3.面試題 02.01. 移除重復節點

編寫代碼,移除未排序鏈表中的重復節點。保留最開始出現的節點。

示例1:

 輸入:[1, 2, 3, 3, 2, 1]
 輸出:[1, 2, 3]

示例2:

 輸入:[1, 1, 1, 1, 2]
 輸出:[1, 2]

提示:

  1. 鏈表長度在[0, 20000]范圍內。
  2. 鏈表元素在[0, 20000]范圍內。

方法一、哈希表標記法

思路與算法

① 哈希表標記法?:利用數組模擬哈希表(大小20001),用于記錄節點值是否已存在。數組下標對應節點值,元素值為1表示該值已出現過

② 雙指針遍歷:

????????tmp指針:指向當前已去重鏈表的尾節點,用于連接新節點。

? ?curr指針:遍歷原鏈表,檢查當前節點是否重復。

③ 邊界處理:?若鏈表為空直接返回;初始化時先將頭節點加入哈希表,避免后續判空操作

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def removeDuplicateNodes(self, head: Optional[ListNode]) -> Optional[ListNode]:if head == None:return None# 哈希表hash = [0 for i in range(20001)]tmp = headcurr = head.nexthash[head.val] = 1while curr:if hash[curr.val] == 0:hash[curr.val] = 1tmp.next = currtmp = tmp.nextcurr = curr.nexttmp.next = Nonereturn head


方法二、字典

思路與算法

?初始化字典:首先,代碼創建了一個空字典?dict,用于存儲已經出現過的節點值。如果鏈表為空(head == None),則直接返回?None,因為空鏈表不需要去重。?

② 處理頭節點:將頭節點的值?head.val?存入字典,表示該值已經出現過。

③ 遍歷鏈表:使用?curr?指針遍歷鏈表,初始時?curr?指向頭節點。在遍歷過程中,檢查?curr.next?的值是否已經存在于字典中:如果?curr.next.val?不在字典中,說明該值尚未出現過,將其存入字典,并將?curr?指針移動到下一個節點。如果?curr.next.val?已經在字典中,說明該值是重復的,跳過該節點,即將?curr.next?指向?curr.next.next,從而刪除重復節點。

④ 返回結果:遍歷結束后,返回去重后的鏈表頭節點?head

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def removeDuplicateNodes(self, head: Optional[ListNode]) -> Optional[ListNode]:dict = {}if head == None:return Nonedict[head.val] = 1curr = headwhile curr.next:if curr.next.val not in dict:dict[curr.next.val] = 1curr = curr.nextelse:curr.next = curr.next.next  return head


四、單向鏈表的應用

鏈表相比于順序表的優點在于:對于給定的結點,刪除操作優于順序表

MMO游戲開發 —— AOI(Area of Interest)

簡單來說,每個玩家只關心他周圍的玩家的數據同步,而不關心整個世界的數據,有一種經典的實現方式:雙向十字鏈表

所有玩家被串聯在一個十字鏈表上,玩家移動其實就是鏈表上節點交換位置的過程,每個玩家想獲取其他玩家的數據,只需要在十字鏈表上進行遍歷即可,而服務器同步給客戶端的數據,受AOI控制,所以可以根據客戶端實際能夠承受的性能,調整AOI的半徑

通過有效的實現AOI技術,游戲開發中可以:

① 減少服務器負載 ② 降低網絡延遲 ③ 提升游戲性能 ④ 增強玩家用戶體驗

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

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

相關文章

第1章:項目概述與環境搭建

第1章&#xff1a;項目概述與環境搭建 學習目標 了解YunChangAction靈感記錄應用的整體架構和功能掌握SwiftUI開發環境的配置方法創建項目基礎結構并理解文件組織方式實現應用的啟動屏幕和基本主題設置 理論知識講解 靈感記錄應用概述 靈感記錄應用是一種專門設計用來幫助…

2025.3.3總結

周一這天&#xff0c;我約了績效教練&#xff0c;主要想了解專業類績效的考核方式以及想知道如何拿到一個更好的績效。其他的崗位并不是很清楚&#xff0c;但是專業類的崗位&#xff0c;目前采取絕對考核&#xff0c;管理層和專家崗采取相對考核&#xff0c;有末尾淘汰。 通過…

FastGPT 源碼:基于 LLM 實現 Rerank (含Prompt)

文章目錄 基于 LLM 實現 Rerank函數定義預期輸出實現說明使用建議完整 Prompt 基于 LLM 實現 Rerank 下邊通過設計 Prompt 讓 LLM 實現重排序的功能。 函數定義 class LLMReranker:def __init__(self, llm_client):self.llm llm_clientdef rerank(self, query: str, docume…

LeetCode 1745.分割回文串 IV:動態規劃(用III或II能直接秒)

【LetMeFly】1745.分割回文串 IV&#xff1a;動態規劃&#xff08;用III或II能直接秒&#xff09; 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/palindrome-partitioning-iv/ 給你一個字符串 s &#xff0c;如果可以將它分割成三個 非空 回文子字符串&#xff0c;…

25年3月5日

1.思維導圖 2.不太會 #include "head.h" int main(int argc, const char *argv[]) {int fdopen("../xiaoxin.bmp","O_RDONLY");if(fd-1)printf("open error");//大小struct stat st;if(stat("…

全球首創!微軟發布醫療AI助手,終結手寫病歷時代

今天凌晨&#xff0c;微軟發布了醫療界首個用于臨床工作流程的AI助手Microsoft Dragon Copilot。 Dragon Copilot是基于語音文本的混合架構&#xff0c;能夠將醫生的語音或臨床口述內容實時轉換為文本。例如&#xff0c;醫生可以通過語音輸入患者的病歷信息、醫囑或診斷結果&a…

[自動駕駛-傳感器融合] 多激光雷達的外參標定

文章目錄 引言外參標定原理ICP匹配示例參考文獻 引言 多激光雷達系統通常用于自動駕駛或機器人&#xff0c;每個雷達的位置和姿態不同&#xff0c;需要將它們的數據統一到同一個坐標系下。多激光雷達外參標定的核心目標是通過計算不同雷達坐標系之間的剛性變換關系&#xff08…

Blazor-路由模板(下)

路由約束 類型約束 我們這里使用{id:int}限制路由&#xff0c;id為int類型&#xff0c;并且路由參數 id 對應的 Id 屬性也必須是 int 類型。我們試試能否正常訪問 page "/demoPage/{id:int}" <h3>demoPage</h3> <h2>路由參數Id&#xff1a;Id&l…

多線程-JUC源碼

簡介 JUC的核心是AQS&#xff0c;大部分鎖都是基于AQS擴展出來的&#xff0c;這里先結合可重入鎖和AQS&#xff0c;做一個講解&#xff0c;其它的鎖的實現方式也幾乎類似 ReentrantLock和AQS AQS的基本結構 AQS&#xff0c;AbstractQueuedSynchronizer&#xff0c;抽象隊列…

通過多線程獲取RV1126的AAC碼流

目錄 一RV1126多線程獲取音頻編碼AAC碼流的流程 1.1AI模塊的初始化并使能 1.2AENC模塊的初始化 ???????1.3綁定AI模塊和AENC模塊 ???????1.4多線程獲取每一幀AAC碼流 ???????1.5每個AAC碼流添加ADTSHeader頭部 ???????1.6寫入具體每一幀AAC的…

JVM常用概念之對象初始化的成本

在JVM常用概念之新對象實例化博客中我講到了對象的實例化&#xff0c;主要包含分配&#xff08;TLAB&#xff09;、系統初始化、用戶初始化&#xff0c;而我在JVM常用概念之線程本地分配緩沖區&#xff08;ThreadLocal Allocation Buffer&#xff0c;TLAB&#xff09;博客中也講…

java后端開發day27--常用API(二)正則表達式爬蟲

&#xff08;以下內容全部來自上述課程&#xff09; 1.正則表達式&#xff08;regex&#xff09; 可以校驗字符串是否滿足一定的規則&#xff0c;并用來校驗數據格式的合法性。 1.作用 校驗字符串是否滿足規則在一段文本中查找滿足要求的內容 2.內容定義 ps&#xff1a;一…

AI---DevOps常備工具(?AI-Integrated DevOps Essential Tools)

AI---DevOps常備工具 技術領域正在迅速發展&#xff0c;隨著我們步入 2025 年&#xff0c;有一點是明確的&#xff1a;人工智能&#xff08;AI&#xff09;不再只是一個流行詞&#xff0c;它是每個 DevOps 工程師都需要掌握的工具。隨著云環境的復雜性增加、對更快部署的需求以…

Pytorch中的主要函數

目錄 一、torch.manual_seed(seed)二、torch.cuda.manual_seed(seed)三、torch.rand(*size, outNone, dtypeNone, layouttorch.strided, deviceNone, requires_gradFalse)四、給大家寫一個常用的自動選擇電腦cuda 或者cpu 的小技巧五、torch.version.cuda&#xff1b;torch.bac…

Spring Boot中對接Twilio以實現發送驗證碼和驗證短信碼

Twilio介紹 Twilio是一家提供云通信服務的公司&#xff0c;旨在幫助開發者和企業通過簡單的API實現各種通信功能。以下是Twilio的一些主要特點和服務介紹&#xff1a; 核心功能 短信服務&#xff08;SMS&#xff09;&#xff1a;允許用戶通過API發送和接收短信&#xff0c;支…

VSCode詳細安裝步驟,適用于 Windows/macOS/Linux 系統

以下是 Visual Studio Code (VSCode) 的詳細安裝步驟&#xff0c;適用于 Windows/macOS/Linux 系統&#xff1a; VSCode 的詳細安裝步驟 一、Windows 系統安裝1. 下載安裝包2. 運行安裝程序3. 驗證安裝 二、macOS 系統安裝1. 方法一&#xff1a;官網下載安裝包2. 方法二&#x…

基于PyTorch的深度學習3——基于autograd的反向傳播

反向傳播&#xff0c;可以理解為函數關系的反向傳播。

設備管理系統功能與.NET+VUE(IVIEW)技術實現

在現代工業和商業環境中&#xff0c;設備管理系統&#xff08;Equipment Management System&#xff0c;簡稱EMS&#xff09;是確保設備高效運行和維護的關鍵工具。本文采用多租戶設計的設備管理系統&#xff0c;基于.NET后端和VUE前端&#xff08;使用IVIEW UI框架&#xff09…

PHP之特性

在你有別的編程語言的基礎下&#xff0c;你想學習PHP&#xff0c;可能要了解的PHP特有的東西。 定界符 使用<<<TT(可以是任意字符&#xff0c;但是不可以在別的地方使用過)和TT&#xff0c;會解析html格式和變量&#xff0c;如果在<<<后面加上單引號就會不…

9-Agent大模型中工作流的使用方法分析

目錄 關鍵詞 摘要 速覽 配置插件進行新聞內容查找的工作流設置 自動化調用用戶輸入變量的插件配置教程 配置大模型以整理并簡要輸出新聞內容 新聞內容總結功能調試與優化 搭建與發布工作流優化布局的流程詳解 創建和配置智能體工作流程 調試頁面與工作流配置演示 思…