(五)循環鏈表、雙向鏈表

循環鏈表

介紹

在單選鏈表基礎上,下一個節點指向前一個節點,最后一個節點指向起點

封裝循環鏈表

為了讓循環鏈表可以繼承自單向鏈表,對其進行重構

給其增加一個tail屬性(尾節點),對各方法進行重寫整理

import ILinkedList from "./ILinkedList";
// 1.創建Node節點類
class Node<T> {value:T;next:Node<T> | null = null;constructor(value:T) {this.value = value}
}// 2.創建LinkedList類
class LinkedList<T> implements ILinkedList<T> {protected  head:Node<T> | null = null;protected size:number = 0;// 新增屬性:尾結點protected tail:Node<T> | null = null;get length() {return this.size}// 封裝私有方法// 根據position獲取當前的節點protected getNode(position:number): Node<T> | null{let current = this.headlet index = 0while(index++ < position && current) {current = current.next}return current}// 判斷是否為最后一個節點private isTail(node:Node<T>): boolean {return node === this.tail}// 1.追加節點append(value:T) {// 1.根據value創建一個新節點const newNode = new Node(value)// 2.判斷this.head是否為nulif(this.head === null) {this.head = newNode}else {this.tail!.next = newNode}this.tail = newNodethis.size++}// 2.遍歷鏈表traverse() {const values:T[] = []let current = this.headwhile(current) {values.push(current.value)if(this.isTail(current)){//已經遍歷到最后一個節點current = null}else{current = current.next}}if(this.head && this.tail?.next === this.head) {values.push(this.head.value)}console.log(values.join('->'));//aaa->bbb->ccc->ddd}// 3.插入方法insert(value: T, position: number): boolean {// 1. 邊界條件判斷if (position < 0 || position > this.size) return false;// 2. 根據 value 創建新的節點const newNode = new Node(value);// 3. 判斷是否需要插入頭部if (position === 0) {newNode.next = this.head;this.head = newNode;} else {// 4.找到插入位置的前一個節點/* let current = this.head;let previous: Node<T> | null = null;let index = 0;while(current && index < position ){previous = currentcurrent = current.next;index++}previous!.next = newNode;newNode.next = current; */// 重構代碼const previous = this.getNode(position - 1);newNode.next = previous?.next ?? null;previous!.next = newNode;if(position === this.length) {this.tail = newNode;}}// 6. 更新鏈表大小this.size++;return true;}// 4.刪除方法removeAt(position:number): T | null {// 1.越界判斷if(position < 0 || position >= this.size) return null;// 2.判斷是否刪除第一個節點let current = this.head;if(position === 0) {this.head = current?.next ?? null;if(this.length === 1){this.tail = null;}}else{/* let previous: Node<T> | null = null;let index = 0;while(index++ < position && current) {previous = current;current = current.next}// 找到需要的節點previous!.next = current?.next ?? null; */// 重構為如下代碼const previous = this.getNode(position - 1)previous!.next = previous?.next?.next ?? null;current = previous!.next;if(position === this.length - 1) {this.tail = previous;}}this.size--;return current?.value  ?? null;}// 5.獲取方法get(position:number): T | null {// 5.1越界命題if(position < 0 || position >= this.size) return null;// 5.2查找元素return this.getNode(position)?.value  ?? null;}// 7.更新方法update(value:T,position:number): boolean {if(position < 0 || position >= this.size) return false;const currentNode = this.getNode(position)currentNode!.value = value;return true;}// 8.根據值獲取對應位置的索引indexOf(value:T): number {// 從第一個節點開始,向后遍歷let current = this.head;let index = 0;while(current) {if(current.value === value) {return index}if(this.isTail(current)){current = null}else{index++current = current.next}}return -1;}// 9.根據value刪除節點remove(value:T): T | null {const index = this.indexOf(value)return this.removeAt(index)}// 10.判斷鏈表是否為空isEmpty(): boolean {return this.size === 0}
}const linkedList = new LinkedList<string>()export default LinkedList

封裝CircularLinkedList

import LinkedList from "./01-實現單選LinkedList"class CircularLinkedList<T> extends LinkedList<T> {// 重新實現的方法: append方法append(value:T) {super.append(value)this.tail!.next = this.head}// traverse方法// insert方法insert(value: T, position: number): boolean {const isSuccess = super.insert(value, position)if(isSuccess && (position === this.length || position === 0)){this.tail!.next = this.head}return isSuccess}// removeAt方法removeAt(position: number): T | null {const value = super.removeAt(position)if(value && this.tail &&(position === 0 || position === this.length-1)){this.tail.next = this.head}return value}// indexOf方法
}const cLinkedList = new CircularLinkedList<string>()
cLinkedList.append('aaa')
cLinkedList.append('bbb')
cLinkedList.append('ccc')
cLinkedList.append('ddd')
cLinkedList.insert('eee', 0)
cLinkedList.insert('fff', 5)cLinkedList.removeAt(5)
cLinkedList.traverse()console.log('--------測試get----------');
console.log(cLinkedList.get(0));
console.log(cLinkedList.get(1));
console.log(cLinkedList.get(4));console.log('--------測試update----------');
cLinkedList.update('hhh', 0)
cLinkedList.update('iii', 2)
cLinkedList.traverse()

雙向鏈表

介紹

既可以從頭遍歷到尾,也可以從尾遍歷到頭

封裝雙向鏈表

import LinkedList from "./01-實現單選LinkedList"; class DoublyNode<T> extends LinkedList<T> {
}

2.append方法

情況一:當添加的是第一個節點時→讓head和tail都指向新節點

情況二:當添加的是其它節點時,需改變相關節點的指引關系

代碼實現:

  protected head: DoublyNode<T> | null = null;protected tail: DoublyNode<T> | null = null;
// append方法append(value: T): void {const newNode = new DoublyNode(value)// 情況一:鏈表為空if(!this.head) {this.head = newNodethis.tail = newNode}else{// 情況二:鏈表不為空this.tail!.next = newNode// 不能將父類的類型賦值給子類;可以將子類的類型賦值給父類newNode.prev = this.tailthis.tail = newNode}this.size++}

測試代碼:

dLinkedList.append("aaa")
dLinkedList.append("bbb")
dLinkedList.append("ccc")
dLinkedList.append("ddd")
dLinkedList.traverse()

3.prepend方法-從頭部插入

情況一:鏈表本身為空

情況二:鏈表有值

prepend(value:T):void {const newNode = new DoublyNode(value)if(!this.head) {this.head = newNodethis.tail = newNode}else{newNode.next = this.headthis.head.prev = newNodethis.head = newNode}this.size++}

4.反向遍歷-從尾到頭

postTraverse() {const values:T[] = []let current = this.tailwhile(current) {values.push(current.value)current = current.prev}console.log(values.join('->'));//ddd->ccc->bbb->aaa->zzz
}

5.insert插入節點

情況一:插入位置為0時

情況二:插入位置為末尾時

情況三:鏈表中間位置時

insert(value: T, position: number): boolean {if(position < 0 || position > this.length) return false;if(position === 0) {this.prepend(value)}else if(position === this.length){this.append(value)}else{const newNode = new DoublyNode(value)const current = this.getNode(position)! as DoublyNode<T>current!.prev!.next = newNodenewNode.next = currentnewNode.prev = current!.prevcurrent!.prev = newNodethis.size++}return true}

6.removeAt(position)

情況一:當刪除0位置時:

1.當鏈表長度為1時:

2.鏈表長度不為1時:

情況二:刪除末尾位置:

情況三:刪除中間位置:

// 索引刪除removeAt(position: number): T | null {if(position < 0 || position >= this.length) return nulllet current = this.headif(position === 0) {if(this.length === 1){this.head = nullthis.tail = null}else {this.head = this.head!.nextthis.head!.prev = null}}else if(position === this.length - 1){current = this.tailthis.tail= this.tail!.prevthis.tail!.next = null}else {current = this.getNode(position)! as DoublyNode<T>current.prev!.next = current.nextcurrent.next!.prev = current.prev}this.size--;return current?.value?? null;}

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

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

相關文章

仙劍奇俠傳98柔情版游戲秘籍

戰斗秘技&#xff1a;在戰斗中輸入 “cheat”&#xff0c;然后輸入 “v” 直接取勝&#xff1b;輸入 “y” 敵人不攻擊。另外&#xff0c;在戰斗中按 “XJPXZ123” 加 “shift” 鍵&#xff0c;攻擊力增加 1000&#xff05;。等級提升秘籍&#xff1a;當李逍遙等級到達 99 級時…

常見的歸一化(Normalization)方法

本文詳解深度學習中常見的歸一化方法。 【歸一化是將數據按比例縮放&#xff0c;使之落入一個特定的區間】目錄 1. 批量歸一化&#xff08;Batch Normalization&#xff0c;BN&#xff09;1.1 數學原理1.2 代碼示例 2. 層歸一化&#xff08;Layer Normalization&#xff0c;LN&…

行星際激波在日球層中的傳播:Propagation of Interplanetary Shocks in the Heliosphere (參考文獻部分)

行星際激波在日球層中的傳播&#xff1a;Propagation of Interplanetary Shocks in the Heliosphere &#xff08;第一部分&#xff09;-CSDN博客 行星際激波在日球層中的傳播&#xff1a;Propagation of Interplanetary Shocks in the Heliosphere &#xff08;第二部分&…

大模型可視化應用敏捷開發方案:Dify+Echarts

大模型相關目錄 大模型&#xff0c;包括部署微調prompt/Agent應用開發、知識庫增強、數據庫增強、知識圖譜增強、自然語言處理、多模態等大模型應用開發內容 從0起步&#xff0c;揚帆起航。 Moe模式&#xff1a;或將是最好的大模型應用開發路徑一文帶你了解大模型RAG詳細記錄…

23種GoF設計模式

GoF&#xff08;Gang of Four&#xff09;設計模式是由四位計算機科學家 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著的書籍《Design Patterns: Elements of Reusable Object-Oriented Software》中提出的設計模式 目錄 一、創建型模式&#xff08;Cre…

Losson 4 NFS(network file system(網絡文件系統))

網絡文件系統&#xff1a;在互聯網中共享服務器中文件資源。 使用nfs服務需要安裝:nfs-utils 以及 rpcbind nfs-utils : 提供nfs服務的程序 rpcbind &#xff1a;管理nfs所有進程端口號的程序 nfs的部署 1.客戶端和服務端都安裝nfs-utils和rpcbind #安裝nfs的軟件rpcbind和…

C++ 入門六:多態 —— 同一接口的多種實現之道

在面向對象編程中&#xff0c;多態是最具魅力的特性之一。它允許我們通過統一的接口處理不同類型的對象&#xff0c;實現 “一個接口&#xff0c;多種實現”。本章將從基礎概念到實戰案例&#xff0c;逐步解析多態的核心原理與應用場景&#xff0c;幫助新手掌握這一關鍵技術。 …

關于C使用Windows API獲取系統管理員權限和對文本屬性的操作,以及windows API的核心操作

關于windows系統的操作程序開發&#xff0c;本文介紹一部分重要的文本屬性操作&#xff0c;和運行計次器。 獲取系統管理員權限 #include <windows.h> VOID ManagerRun(LPCSTR exe, LPCSTR param, INT nShow) { //注意&#xff1a;會跳出提示。SHELLEXECUTEINFO ShExec…

Web 項目實戰:構建屬于自己的博客系統

目錄 項目效果演示 代碼 Gitee 地址 1. 準備工作 1.1 建表 1.2 引入 MyBatis-plus 依賴 1.3 配置數據庫連接 1.4 項目架構 2. 實體類準備 - pojo 包 2.1 dataobject 包 2.2 request 包 2.3 response 包 2.3.1 統一響應結果類 - Result 2.3.2 用戶登錄響應類 2.3.3…

從“被動跳閘”到“主動預警”:智慧用電系統守護老舊小區安全

安科瑞顧強 近年來&#xff0c;老舊小區電氣火災事故頻發&#xff0c;成為威脅居民生命財產安全的重要隱患。據統計&#xff0c;我國居住場所火災傷亡人數遠超其他場所&#xff0c;僅今年一季度就發生8.3萬起住宅火災&#xff0c;造成503人遇難。這些建筑多建于上世紀&#x…

【深入淺出 Git】:從入門到精通

這篇文章介紹下版本控制器。 【深入淺出 Git】&#xff1a;從入門到精通 Git是什么Git的安裝Git的基本操作建立本地倉庫配置本地倉庫認識工作區、暫存區、版本庫的概念添加文件添加文件到暫存區提交文件到版本庫提交文件演示 理解.git目錄中的文件HEAD指針與暫存區objects對象 …

Mybatis的簡單介紹

文章目錄 MyBatis 簡介 1. MyBatis 核心特點2. MyBatis 核心組件3. MyBatis 基本使用示例(1) 依賴引入&#xff08;Maven&#xff09;(2) 定義 Mapper 接口(3) 定義實體類(4) 在 Service 層調用 4. MyBatis 與 JPA/Hibernate 對比 MyBatis 簡介 MyBatis 是一款優秀的 持久層框…

Android Studio 在 Windows 上的完整安裝與使用指南

Android Studio 在 Windows 上的完整安裝與使用指南—目錄 一、Android Studio 簡介二、下載與安裝1. 下載 Android Studio2. 安裝前的依賴準備3. 安裝步驟 三、基礎使用指南1. 首次啟動配置2. 創建第一個項目3. 運行應用4. 核心功能 四、進階功能配置1. 配置 SDK 和工具2. 自定…

WPF 綁定方式舉例

WPF 綁定方式舉例 一、如果ItemsControl 控件的ItemsSource要綁定到List類型&#xff0c;可以如下&#xff1a; List<string> Names new List<string>(); Names.Add("aaa"); Names.Add("bbb");<ItemsControl ItemsSource"{Binding …

LangSmith 設置指南

什么是 LangSmith&#xff1f; LangSmith 是 LangChain 團隊開發的一個統一開發者平臺&#xff0c;用于構建、測試、評估和監控基于大型語言模型&#xff08;LLM&#xff09;的應用程序。它提供了一套工具&#xff0c;幫助開發者更好地理解、調試和改進他們的 LLM 應用。 注冊…

手撕TCP內網穿透及配置樹莓派

注意&#xff1a; 本文內容于 2025-04-13 15:09:48 創建&#xff0c;可能不會在此平臺上進行更新。如果您希望查看最新版本或更多相關內容&#xff0c;請訪問原文地址&#xff1a;手撕TCP內網穿透及配置樹莓派。感謝您的關注與支持&#xff01; 之前入手了樹莓派5&#xff0c;…

Java從入門到“放棄”(精通)之旅——程序邏輯控制④

Java從入門到“放棄”&#xff08;精通&#xff09;之旅&#x1f680;&#xff1a;程序邏輯的完美理解 一、開篇&#xff1a;程序員的"人生選擇" 曾經的我&#xff0c;生活就像一段順序執行的代碼&#xff1a; System.out.println("早上8:00起床"); Syste…

學習筆記九——Rust所有權機制

&#x1f980; Rust 所有權機制 &#x1f4da; 目錄 什么是值類型和引用類型&#xff1f;值語義和引用語義&#xff1f;什么是所有權&#xff1f;為什么 Rust 需要它&#xff1f;所有權的三大原則&#xff08;修正版&#xff09;移動語義 vs 復制語義&#xff1a;變量賦值到底…

Cocos Creator Shader入門實戰(八):Shader實現圓形、橢圓、菱形等頭像

引擎&#xff1a;3.8.5 您好&#xff0c;我是鶴九日&#xff01; 回顧 Shader的學習是一條漫長的道路。 理論知識的枯燥無味&#xff0c;讓很多人選擇了放棄。然而不得不說&#xff1a;任何新知識、新領域的學習&#xff0c;本身面臨的都是問題&#xff01; 互聯網和AI給了我…

深入理解計算機操作系統(持續更新中...)

文章目錄 一、計算機系統漫游1.1信息就是位上下文 一、計算機系統漫游 1.1信息就是位上下文 源程序實際上就是一個由值0和1組成的位&#xff08;又稱為比特&#xff09;&#xff0c;八個位被組織成一組&#xff0c;稱為字節。每個字節表示程序中的某些文本字符 大部分現代計…