【數據結構】快慢指針

一、快慢指針的原理

定義:
????????快指針:每次移動兩步
? ? ? ? 慢指針:每次移動一步
終止條件:
? ? ? ? 當快指針到達鏈表末尾時停止
事件復雜度:
? ? ? ? 始終為O(n),僅需依次遍歷
空間復雜度:
? ? ? ? 僅需兩個指針變量

二、快慢指針的典型應用場景

1、首先制作一個鏈表的節點
?

#include <iostream>
#include <vector>struct ListNode {int val;ListNode* next;ListNode(int x) :val(x), next(nullptr){}ListNode(int x, ListNode *_next):val(x),next(_next){}
};//傳入列表生成list鏈
ListNode* makeNodeList(std::vector<int> vec)
{ListNode* outNode = nullptr;for (int i = vec.size() - 1; i >= 0 ; i--){outNode = new ListNode(vec[i],outNode);}return outNode;}//遍歷輸出鏈表
void traverseNodeList(ListNode* node)
{while (node){std::cout << node->val << " ";node = node->next;}std::cout << std::endl;
}//回收資源
void reclaim(ListNode* node)
{if (node->next){reclaim(node->next);}delete node;
}int main()
{std::vector<int> vec{ 1,2,3,4,5 };ListNode *node = makeNodeList(vec);traverseNodeList(node);reclaim(node);return 0;
}

2、檢測鏈表是否有環


代碼如下:

bool haveLoop(ListNode* node)
{ListNode* fast = node;ListNode* slow = node;while (fast != nullptr && fast->next != nullptr){fast = fast->next->next;slow = slow->next;if (fast == slow){return true;		//快指針追上了滿指針,有環}}return false;
}int main()
{ListNode* node5 = new ListNode(5);ListNode* node4 = new ListNode(4, node5);ListNode* node3 = new ListNode(3, node4);ListNode* node2 = new ListNode(2, node3);ListNode* node1 = new ListNode(1, node2);node5->next = node2;if (haveLoop(node1)){std::cout << "有環" << std::endl;}else {std::cout << "沒環" << std::endl;}return 0;
}

3、找到鏈表的中間節點

ListNode* middileNode(ListNode* node)
{ListNode *fast = node, *slow = node;while (fast && fast->next) {		//如果fast的next為nullptr,則下面的next->next就找不第二個next了fast = fast->next->next;slow = slow->next;}return slow;
}int main()
{std::vector<int> vec{ 1,2,3,4,5 };ListNode *node = makeNodeList(vec);ListNode *midNode = middileNode(node);std::cout << "奇數個中間節點是" << midNode->val << std::endl;std::vector<int> vec2{ 1,2,3,4,5,6 };ListNode* node2 = makeNodeList(vec2);ListNode* midNode2 = middileNode(node2);std::cout << "偶數個中間節點是" << midNode->val << std::endl;return 0;
}

4、尋找鏈表的環入口

代碼如下:
(因為用到了前面判斷是否時環的函數,所以代碼都放這里了)

#include <iostream>
#include <vector>struct ListNode {int val;ListNode* next;ListNode(int x) :val(x), next(nullptr){}ListNode(int x, ListNode *_next):val(x),next(_next){}
};//傳入列表生成list鏈
ListNode* makeNodeList(std::vector<int> vec)
{ListNode* outNode = nullptr;for (int i = vec.size() - 1; i >= 0 ; i--){outNode = new ListNode(vec[i],outNode);}return outNode;}//遍歷輸出鏈表
void traverseNodeList(ListNode* node)
{while (node){std::cout << node->val << " ";node = node->next;}std::cout << std::endl;
}//回收資源
void reclaim(ListNode* node)
{if (node->next){reclaim(node->next);}delete node;
}bool haveLoop(ListNode* node)
{ListNode* fast = node;ListNode* slow = node;while (fast != nullptr && fast->next != nullptr){fast = fast->next->next;slow = slow->next;if (fast == slow){return true;		//快指針追上了滿指針,有環}}return false;
}ListNode* middileNode(ListNode* node)
{ListNode *fast = node, *slow = node;while (fast && fast->next) {		//如果fast的next為nullptr,則下面的next->next就找不第二個next了fast = fast->next->next;slow = slow->next;}return slow;
}ListNode* entranceNode(ListNode* node)
{if (!haveLoop(node)){return nullptr;				//如果不含有環路,返回空指針}ListNode* fast = node, * slow = node;while (fast && fast->next){fast = fast->next->next;slow = slow->next;if (fast == slow){break;}}slow = node;while (fast != slow){fast = fast->next;slow = slow->next;}return slow;
}int main()
{ListNode* node5 = new ListNode(5);ListNode* node4 = new ListNode(4, node5);ListNode* node3 = new ListNode(3, node4);ListNode* node2 = new ListNode(2, node3);ListNode* node1 = new ListNode(1, node2);node5->next = node3;ListNode* node = entranceNode(node1);	//Node節點std::cout << "入口節點值為" << node->val << std::endl;return 0;
}

5、判斷回文鏈表
?
代碼如下:

#include <iostream>
#include <vector>struct ListNode {int val;ListNode* next;ListNode(int x) :val(x), next(nullptr){}ListNode(int x, ListNode *_next):val(x),next(_next){}
};//傳入列表生成list鏈
ListNode* makeNodeList(std::vector<int> vec)
{ListNode* outNode = nullptr;for (int i = vec.size() - 1; i >= 0 ; i--){outNode = new ListNode(vec[i],outNode);}return outNode;}//遍歷輸出鏈表
void traverseNodeList(ListNode* node)
{while (node){std::cout << node->val << " ";node = node->next;}std::cout << std::endl;
}//回收資源
void reclaim(ListNode* node)
{if (node->next){reclaim(node->next);}delete node;
}bool haveLoop(ListNode* node)
{ListNode* fast = node;ListNode* slow = node;while (fast != nullptr && fast->next != nullptr){fast = fast->next->next;slow = slow->next;if (fast == slow){return true;		//快指針追上了滿指針,有環}}return false;
}ListNode* middileNode(ListNode* node)
{ListNode *fast = node, *slow = node;while (fast && fast->next) {		//如果fast的next為nullptr,則下面的next->next就找不第二個next了fast = fast->next->next;slow = slow->next;}return slow;
}ListNode* entranceNode(ListNode* node)
{if (!haveLoop(node)){return nullptr;				//如果不含有環路,返回空指針}ListNode* fast = node, * slow = node;while (fast && fast->next){fast = fast->next->next;slow = slow->next;if (fast == slow){break;}}slow = node;while (fast != slow){fast = fast->next;slow = slow->next;}return slow;
}bool isSymmeNode(ListNode* node)
{//用前面的函數找到中間節點ListNode* midNode = middileNode(node);//反轉中間節點后面的節點// 321 -> 123// 3 2 1// 3		21// 2 3		1// 1 2 3ListNode* temp;ListNode* Lnode = midNode;ListNode* Rnode = nullptr;while (Lnode){temp = Lnode->next;Lnode->next = Rnode;		//讓先放進來的值朝著后面排Rnode = Lnode;Lnode = temp;}//第三步、比較前后的值是否相同while(Rnode){if (node->val != Rnode->val){return false;}else {node = node->next;Rnode = Rnode->next;}}return true;
}int main()
{std::vector<int> vec = { 1,2,3,3,2,1 };ListNode* Node = makeNodeList(vec);if (isSymmeNode(Node)){std::cout << "是回文鏈" << std::endl;}else {std::cout << "不是回文鏈" << std::endl;}return 0;
}

6、找到鏈表的倒數第K個節點

ListNode* getKthFromEnd(ListNode* node, int k)
{ListNode* fast = node, * slow = node;for (int i = 0; i < k; i++){if (fast && fast->next){fast = fast->next;}else {return nullptr;}}while (fast){fast = fast->next;slow = slow->next;}return slow;
}int main()
{std::vector<int> vec = { 1,2,3,4,5,6 };ListNode* Node = makeNodeList(vec);std::cout << "倒數第3節點的值是" << getKthFromEnd(Node, 3)->val << std::endl;return 0;
}

三、快慢指針在實際開發中的應用
????????下面是DeepseeK給出的,個人認為是從判斷環,找中點,業務需求速率不同這三個角度演化。還沒實踐過。后面有實踐應該會貼鏈接在這里。

????????PS:夜已深,學生時期聽的歌真有品味啊,當世界年輕時

1.?資源管理與循環檢測

  • 場景:在內存管理、文件系統或網絡協議中,需要檢測資源引用是否形成循環依賴。

    • 示例

      • 垃圾回收(GC):某些垃圾回收算法需要檢測對象之間的循環引用(如標記-清除算法)。通過快慢指針可以高效判斷對象引用鏈中是否存在環,避免內存泄漏。

      • 文件系統的符號鏈接:檢測符號鏈接是否形成環(如?ln -s file1 file2; ln -s file2 file1),避免程序陷入死循環遍歷。


2.?數據結構的維護與優化

  • 場景:在自定義鏈表結構或緩存系統中,需要高效操作鏈表。

    • 示例

      • 緩存淘汰策略:在實現類似 LRU(最近最少使用)緩存時,若需手動管理鏈表(而非使用現成庫),快慢指針可用于快速定位中間節點或批量調整緩存順序。

      • 鏈表合并與分割:在分布式系統中合并多個有序鏈表(如日志合并),通過快慢指針找到中點后分治處理(類似歸并排序)。


3.?網絡與協議處理

  • 場景:處理網絡數據包的順序或超時檢測。

    • 示例

      • 心跳檢測:在長連接中,若用鏈表維護心跳包的時間戳,快指針(高頻檢測)和慢指針(低頻統計)可協同判斷連接健康狀態。

      • 數據包亂序重組:通過快慢指針分離已確認和待確認的數據包鏈表。


4.?并發與多線程編程

  • 場景:在無鎖數據結構或任務調度中,檢測潛在的死鎖或競態條件。

    • 示例

      • 任務隊列管理:在生產者-消費者模型中,快指針快速推進任務處理,慢指針統計未處理任務量,動態調整隊列負載。

      • 死鎖檢測:若線程等待關系形成鏈表式依賴,快慢指針可輔助檢測循環等待(需結合線程調度器的元數據)。


5.?系統性能分析與調試

  • 場景:在性能分析工具或調試器中,追蹤程序執行路徑。

    • 示例

      • 調用鏈分析:在分布式追蹤系統(如 OpenTelemetry)中,若調用鏈因異常形成環(如 A→B→A),快慢指針可快速定位問題節點。

      • 棧溢出檢測:通過快慢指針監控遞歸調用的深度(慢指針記錄常規檢查點,快指針快速探測棧增長)。


6.?游戲與圖形處理

  • 場景:處理動態更新鏈表結構的數據(如動畫幀、物理引擎中的剛體鏈表)。

    • 示例

      • 動畫幀同步:快指針快速遍歷待渲染幀,慢指針標記已確認同步的幀節點,避免丟幀或重復渲染。

      • 碰撞檢測優化:將物體按空間分組成鏈表,快慢指針協助快速篩選待檢測的物體集合。


7.?數據庫與存儲引擎

  • 場景:在存儲引擎的索引結構(如跳表、B+樹葉子節點鏈表)中優化查詢。

    • 示例

      • 跳表(Skip List)維護:快指針快速跨越高層索引,慢指針在底層鏈表同步移動,平衡查詢與更新效率。

      • 范圍查詢優化:通過快慢指針快速定位查詢范圍的起點和終點。

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

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

相關文章

畢業論文 | 基于STM32的自動煙霧報警系統設計

基于STM32的煙霧報警系統 一、系統設計原理1. **系統架構**2. **工作原理**二、核心公式與算法1. **MQ-2傳感器濃度計算**2. **溫度傳感器數據處理**3. **校準與濾波**三、關鍵代碼實現1. **ADC初始化與數據讀取(以MQ-2為例)**2. **報警邏輯與閾值設置**3. **EEPROM存儲閾值*…

Android Gradle插件開發

文章目錄 1. Gradle插件是什么2. 為什么需要插件3. 編寫插件位置4. 編寫插件5. 自定義插件擴展5.1 訂閱擴展對象5.2 把擴展添加給Plugin并使用5.3 配置參數5.4 嵌套擴展5.4.1 定義擴展5.4.2 獲取擴展屬性5.4.3 使用5.4.4 執行5.4.5 輸出 6. 編寫在單獨項目里6.1 新建Module6.2 …

PPIO X OWL:一鍵開啟任務自動化的高效革命

2024年&#xff0c;僅憑一PPIO X OWL&#xff1a;一鍵開啟任務自動化的高效革命篇技術論文&#xff0c;OWL的Github倉庫便在24小時斬獲了15k Star&#xff0c;成為2024年增速最快的多智能體協作框架&#xff0c;重新定義了任務自動化的效率邊界。Camel AI團隊開源全棧方案&…

分布式事務,事務失效,TC事務協調者

1. 概述 本方案書旨在解決分布式系統中事務一致性問題&#xff0c;重點闡述全局事務標識&#xff08;XID&#xff09;的傳遞與存儲機制、事務協調者&#xff08;TC&#xff09;的設計與部署&#xff0c;以及分布式事務失效場景的應對策略。基于業界成熟框架&#xff08;如Seat…

2025年“深圳杯”數學建模挑戰賽D題-法醫物證多人身份鑒定問題

法醫物證多人身份鑒定問題 小驢數模 犯罪現場法醫物證鑒定是關系到國家安全、公共安全、人民生命財產安全和社會穩定的重大問題。目前法醫物證鑒定依賴DNA分析技術不斷提升。DNA檢驗的核心是STR&#xff08;Short Tandem Repeat&#xff0c;短串聯重復序列&#xff09;分析技術…

Mysql查詢異常【Truncated incorrect INTEGER value】

文章目錄 異常原因分析1、數據類型不一致2、數據長度超長3、數據格式要正確 處理方案模擬案例創建表數據查詢 異常 在執行MySQL的語句時&#xff0c;在控制臺報錯如下所示。 Data truncation: Truncated incorrect INTEGER value 原因分析 1、數據類型不一致 必須要保證數據…

WPF性能優化舉例

WPF性能優化集錦 一、UI渲染性能優化 1. 虛擬化技術 ??ListView/GridView虛擬化??: <ListView VirtualizingStackPanel.IsVirtualizing="True"VirtualizingStackPanel.VirtualizationMode="Recycling"ScrollViewer.IsDeferredScrollingEnabled=…

C# 面向對象實例演示

C# 面向對象編程實例演示 一、基礎概念回顧 面向對象編程(OOP)的四大基本特性&#xff1a; ??封裝?? - 將數據和操作數據的方法綁定在一起??繼承?? - 創建新類時重用現有類的屬性和方法??多態?? - 同一操作作用于不同對象產生不同結果??抽象?? - 簡化復雜系…

大連理工大學選修課——機器學習筆記(3):KNN原理及應用

KNN原理及應用 機器學習方法的分類 基于概率統計的方法 K-近鄰&#xff08;KNN&#xff09;貝葉斯模型最小均值距離最大熵模型條件隨機場&#xff08;CRF&#xff09;隱馬爾可夫模型&#xff08;HMM&#xff09; 基于判別式的方法 決策樹&#xff08;DT&#xff09;感知機…

蔣新松:中國機器人之父

名人說:路漫漫其修遠兮,吾將上下而求索。—— 屈原《離騷》 創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder??) 蔣新松:中國機器人之父 一、生平簡介 1. 早年經歷與求學道路 蔣新松出生于1931年8月3日,江蘇省江陰澄北鎮一個靠近長江的小鎮。他的名字來源于杜…

表征(Representations)、嵌入(Embeddings)及潛空間(Latent space)

文章目錄 1. 表征 (Representations)2. 嵌入 (Embeddings)3. 潛空間 (Latent Space)4. 關系總結5. 學習思考 1. 表征 (Representations) 定義: 表征是指數據的一種編碼或描述形式。在機器學習和深度學習中&#xff0c;它特指模型在處理數據時&#xff0c;將原始輸入數據轉換成…

【STM32實物】基于STM32的RFID多卡識別語音播報系統設計

演示視頻: 基于STM32的RFID多卡識別語音播報系統設計 前言:本項目可實現多個電子標簽IC卡RFID識別,刷卡識別后進行中文語音播報反饋,同時進行控制對應的燈光開關。以此也可擴展開發更多功能。 本項目所需主要硬件包括:STM32F103C8T6最小系統板、RFID-RC522模塊、五個IC電…

全面了解CSS語法 ! ! !

CSS&#xff08;層疊樣式表&#xff09;是網頁設計的靈魂之一&#xff0c;它賦予了網頁活力與美感。無論是為一個簡單的個人博客增添色彩&#xff0c;還是為復雜的企業網站設計布局&#xff0c;CSS都是不可或缺的工具。那么&#xff0c;CSS語法到底是什么樣的呢&#xff1f;它背…

青少年抑郁癥患者亞群結構和功能連接耦合的重構

目錄 1 研究背景及目的 2 研究方法 2.1 數據來源與參與者 2.1.1 MDD患者&#xff1a; 2.1.2 健康對照組&#xff1a; 2.2 神經影像分析流程 2.2.1 圖像采集與預處理&#xff1a; 2.2.2 網絡構建&#xff1a; 2.2.3 區域結構-功能耦合&#xff08;SC-FC耦合&#xff09…

【QT】編寫第一個 QT 程序 對象樹 Qt 編程事項 內存泄露問題

目錄 1. 編寫第一個 QT 程序 1.1 使用 標簽 實現 1.2 純代碼形式實現 1.3 使用 按鈕 實現 1.3.1 圖形化界面實現 1.3.2 純代碼形式實現 1.4 使用 編輯框 實現 1.4.1 圖形化界面實現 1.4.2 純代碼形式實現 1.4.3 內存泄露 2. 認識對象模型&#xff08;對象樹&…

在pycharm中創建Django項目并啟動

Django介紹 Django 是一個基于 Python 的開源 Web 應用框架&#xff0c;采用了 MTV&#xff08;Model - Template - View&#xff09;軟件設計模式 &#xff0c;由許多功能強大的組件組成&#xff0c;能夠幫助開發者快速、高效地創建復雜的數據庫驅動的 Web 應用程序。它具有以…

在Carla中構建自動駕駛:使用PID控制和ROS2進行路徑跟蹤

機器人軟件開發什么是 P、PI 和 PID 控制器&#xff1f;比例 &#xff08;P&#xff09; 控制器比例積分 &#xff08;PI&#xff09; 控制器比例-積分-微分 &#xff08;PID&#xff09; 控制器橫向控制簡介CARLA ROS2 集成縱向控制橫向控制關鍵要點結論引用 機器人軟件開發 …

【KWDB 創作者計劃】_深度解析KWDB存儲引擎

文章目錄 每日一句正能量引言一、存儲引擎核心模塊結構二、寫前日志 WAL&#xff08;Write-Ahead Log&#xff09;三、列式壓縮存儲&#xff08;Columnar Compression&#xff09;四、索引機制與混合查詢調度五、分布式核心功能&#xff1a;租約管理實戰六、時間序列數據處理&a…

Apache Tomcat 漏洞(CVE-2025-24813)導致服務器面臨 RCE 風險

CVE-2025-24813Apache Tomcat 中發現了一個嚴重安全漏洞,標識為,該漏洞可能導致服務器面臨遠程代碼執行 (RCE)、信息泄露和數據損壞的風險。 此缺陷影響以下版本: Apache Tomcat11.0.0-M1通過11.0.2Apache Tomcat10.1.0-M1通過10.1.34Apache Tomcat9.0.0-M1通過9.0.98了解 …

全面解析SimHash算法:原理、對比與Spring Boot實踐指南

一、SimHash算法概述 SimHash是一種局部敏感哈希算法&#xff0c;由Google工程師Moses Charikar提出&#xff0c;主要用于海量文本的快速去重與相似度檢測。其核心思想是將高維特征向量映射為固定長度的二進制指紋&#xff08;如64位&#xff09;&#xff0c;通過計算指紋間的…