【TypeScript】常見數據結構與算法(二):鏈表

文章目錄

    • 鏈表結構(LinkedList)
      • 鏈表以及數組的缺點
        • 數組
        • 鏈表的優勢
      • 什么是鏈表?
      • 封裝鏈表相關方法
      • 源碼
        • 鏈表常見面試題
          • 237-刪除鏈表中的節點
          • 206 - 反轉鏈表
      • 數組和鏈表的復雜度對比

鏈表結構(LinkedList)

鏈表以及數組的缺點

  • 鏈表和數組一樣,可以用于存儲一系列的元素,但是鏈表和數組的實現機制完全不同。
  • 這一章中,我們就來學習一下另外一種非常常見的用于存儲數據的線性結構:鏈表。
數組
  • 要存儲多個元素,數組(或稱為鏈表)可能是最常用的數據結構。
  • 我們之前說過,幾乎每一種編程語言都有默認實現數組結構。

但是數組也有很多缺點

  • 數組的創建通常需要申請一段連續的內存空間(一整塊的內存),并且大小是固定的(大多數編程語言數組都是固定的),所以當當前數組不能滿足容量需求時,需要擴容。(一般情況下是申請一個更大的數組,比如2倍。然后將原數組中的元素復制過去
  • 而且在數組開頭或中間位置插入數據的成本很高,需要進行大量元素的位移。
  • 盡管JavaScript的Array底層可以幫我們做這些事,但背后的原理依然是這樣。
鏈表的優勢

要存儲多個元素,另外一個選擇就是鏈表

但不同于數組,鏈表中的元素在內存中不必是連續的空間。

  • 鏈表的每個元素有一個存儲元素本身的節點和一個指向下一個元素的引用(有些語言稱為指針或者鏈接)組成。

相對于數組,鏈表的優勢:

  • 內存空間不是必須連續的。

    √可以充分利用計算機的內存,實現靈活的內存動態管理。

  • 鏈表不必再創建時就確定大小,并且大小可以無限的延伸下去。

  • 鏈表在插入和刪除數據時,時間復雜度可以達到O(1)

    √相對數組效率高很多

相對數組,鏈表的缺點:

  • 鏈表訪問任何一個位置的元素時,都要從頭開始訪問。(無法跳過第一個元素訪問任何一個元素)。
  • 無法通過下標直接訪問元素,需要從頭一個個訪問,直到找到對應元素。

什么是鏈表?

  • 其實上面我們已經簡單的提過了鏈表的結構,我們這里更加詳細的分析一下。
  • 鏈表類似于火車:有一個火車頭,火車頭會連接一個節點,節點上有乘客(類似于數據),并且這個節點會連接下一個節點,以此類推。

image.png

image.png

封裝鏈表相關方法

我們先來認識一下,鏈表中應該有哪些常見的操作
append(element):向鏈表尾部添加一個新的項
insert(position,element):向鏈表的特定位置插入一個新的項。
image.png
get(position):獲取對應位置的元素
image.png
indexOf(element):返回元素在鏈表中的索引。如果鏈表中沒有該元素則返回-1。
update(position,element):修改某個位置的元素
removeAt(position):從鏈表的特定位置移除一項。
image.png
remove(element):從鏈表中移除一項。
isEmpty():如果鏈表中不包含任何元素,返回true,如果鏈表長度大于0則返回false。
size():返回鏈表包含的元素個數。與數組的length屬性類似。

源碼

// 1.創建Node節點類
class Node<T> {value: T;next: Node<T> | null = null;constructor(value: T) {this.value = value;}
}// 2.創建LinkedList的類
class LinkedList<T> {private head: Node<T> | null = null;private size: number = 0;get length() {return this.size;}// 封裝私有方法// 根絕positon獲取當前的節點(不是節點的value,而是獲取節點)private getNode(position: number): Node<T> | null {let index = 0;let current = this.head;while (index++ < position && current) {current = current.next;}return current;}// 追加節點append(value: T) {// 1.根據value新建一個Node節點const newNode = new Node(value);// 2.if (!this.head) {this.head = newNode;} else {let current = this.head;while (current.next) {current = current.next;}// current肯定指向最后一個節點current.next = newNode;}// 3.size++this.size++;}// 遍歷鏈表的方法traverse() {const values: T[] = [];let current = this.head;while (current) {values.push(current.value);current = current.next;}console.log(values.join(" -> "));}//鏈表插入元素的方法insert(value: T, position: number): boolean {// 1.越界判斷if (position < 0 || position > this.size) return false;// 2.根據value創建新的節點const newNode = new Node(value);/* 3.判斷* 是否插入頭部* 否則就找到需要插入的位置,然后記錄前一個節點和當前節點,在前一個節點的next等于newNode,newNode的next等于后一個節點*/if (position === 0) {newNode.next = this.head;this.head = newNode;} else {const previous = this.getNode(position - 1);newNode.next = previous!.next;previous!.next = newNode;}this.size++;return true;}//鏈表插入元素的方法removeAt(position: number): T | null {// 1.越界判斷if (position < 0 || position >= this.size) return null;let current = this.head;if (position === 0) {this.head = current?.next ?? null;} else {const previous = this.getNode(position - 1);previous!.next = previous?.next?.next ?? null;}this.size--;return current?.value ?? null;}// 獲取方法get(position: number): T | null {if (position < 0 || position >= this.size) return null;return this.getNode(position)?.value ?? null;}// 更新方法update(value: T, position: number): boolean {if (position < 0 || position >= this.size) return false;const currentNode = this.getNode(position);currentNode!.value = value;return true;}// 根據值獲取該值位置索引indexOf(value: T): number {let current = this.head;let index = 0;while (current) {if (current.value === value) {return index;}index++;current = current.next;}return -1;}// 刪除方法,根據value刪除remove(value: T): T | null {const index = this.indexOf(value);return this.removeAt(index);}// 判斷單鏈表是否為空的方法isEmpty() {return this.size === 0;}
}export {};
鏈表常見面試題
237-刪除鏈表中的節點
  • https://leetcode.cn/problems/delete-node-in-a-linked-list/

image.png
解題

// Definition for singly-linked list.
class ListNode {val: number;next: ListNode | null;constructor(val?: number, next?: ListNode | null) {this.val = val === undefined ? 0 : val;this.next = next === undefined ? null : next;}
}/**Do not return anything, modify it in-place instead.*/
function deleteNode(node: ListNode | null): void {node!.val = node!.next!.valnode!.next = node!.next!.next
}
206 - 反轉鏈表
  • https://leetcode.cn/problems/reverse-linked-list/

image.png

  • 用棧結構解決
function reverseList(head: ListNode | null): ListNode | null {if(head === null) return nullif(head.next === null) return headconst stack:ListNode[] = []let current:ListNode | null = headwhile(current) {stack.push(current)current = current.next}const newHead:ListNode = stack.pop()!let newHeadCurrent = newHeadwhile(stack.length) {const node = stack.pop()!newHeadCurrent.next = nodenewHeadCurrent = newHeadCurrent.next}newHeadCurrent.next = nullreturn newHead
};
  • 用非遞歸解題
function reverseList(head: ListNode | null): ListNode | null {if (head === null || head.next === null) return head;let newHead: ListNode | null = null;// 1.next = 2, 2.next = 3, 3.next = 4while (head) {// 讓current指向下一個節點// 目的:保留下個節點的引用,可以拿到,并且不會銷毀(current = 2)const current= head.next;// 改變head當前指向的節點,指向newHead// 這里反轉鏈表對于第一節點來說,指向newHead就是null(1.next = null)head.next = newHead;// 讓newhead指向head節點// 這里開始準備反轉新的節點,目的是下一次遍歷時,可以讓下一個節點指向第一個節點(newHead = 1)newHead = head;// 讓head指向下個節點也就是current(head = 2)head = current;}return newHead;
}

image.png

  • 用遞歸方案解題
function reverseList(head: ListNode | null): ListNode | null {// 遞歸停止條件,當遞歸到最后一個節點時停止if (head === null || head.next === null) return head;// 一直遞歸循環直到符合head === null 時停止遞歸// 那么拿到的就是鏈表倒數第二個節點const newHead = reverseList(head.next ?? null)// 反轉鏈表,讓最后一個節點指向head開始正式反轉head.next.next = head// 讓倒數第二個節點的next指向nullhead.next = null// 最后遞歸完了就是反轉后的鏈表了return newHead
}

數組和鏈表的復雜度對比

接下來,我們使用大O表示法來對比一下數組和鏈表的時間復雜度:

image.png

  • 數組是一種連續的存儲結構,通過下標可以直接訪問數組中的任意元素。

  • 時間復雜度:對于數組,隨機訪問時間復雜度為o(1),插入和刪除操作時間復雜度為o(n)。

  • 空間復雜度:數組需要連續的存儲空間,空間復雜度為o(n)。

  • 鏈表是一種鏈式存儲結構,通過指針鏈接起來的節點組成,訪問鏈表中元素需要從頭結點開始遍歷。

  • 時間復雜度:對于鏈表,隨機訪問時間復雜度為o(n),插入和刪除操作時間復雜度為o(1)。

  • 空間復雜度:鏈表需要為每個節點分配存儲空間,空間復雜度為O(n)。

  • 在實際開發中,選擇使用數組還是鏈表需要根據具體應用場景來決定。

  • 如果數據量不大,且需要頻繁隨機訪問元素,使用數組可能會更好。

  • 如果數據量大,或者需要頻繁插入和刪除元素,使用鏈表可能會更好。

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

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

相關文章

AcWing103.電影——離散化

題目 莫斯科正在舉辦一個大型國際會議&#xff0c;有 n n n 個來自不同國家的科學家參會。 每個科學家都只懂得一種語言。 為了方便起見&#xff0c;我們把世界上的所有語言用 1 到 109 之間的整數編號。 在會議結束后&#xff0c;所有的科學家決定一起去看場電影放松一下。…

Interactive Visual Data Analysis

Words&Contents Home | Interactive Visual Data Analysis Book Outline 這本書對視覺、互動和分析方法進行了系統而全面的概述&#xff0c;作為數據可視化方面比較好的讀物&#xff1b; 目錄 Words&Contents Book Outline &#xff08;一&#xff09;Introduct…

AIGC 3D即將爆發,混合顯示成為產業數字化的生產力平臺

2023年&#xff0c;大語言模型與生成式AI浪潮席卷全球&#xff0c;以文字和2D圖像生成為代表的AIGC正在全面刷新產業數字化。而容易為市場所忽略的是&#xff0c;3D圖像生成正在成為下一個AIGC風口&#xff0c;AIGC 3D宇宙即將爆發。所謂AIGC 3D宇宙&#xff0c;即由文本生成3D…

VBA_MF系列技術資料1-227

MF系列VBA技術資料 為了讓廣大學員在VBA編程中有切實可行的思路及有效的提高自己的編程技巧&#xff0c;我參考大量的資料&#xff0c;并結合自己的經驗總結了這份MF系列VBA技術綜合資料&#xff0c;而且開放源碼&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04屬于定…

安裝compiler version 5

這個compiler version5 在我的資源里面可以免費下載&#xff1b; 另外這個東西還需要安裝&#xff0c;安裝教程在這里&#xff1a;Keil最新版保姆教程&#xff08;解決缺少V5編譯器問題&#xff09; - 嗶哩嗶哩 (bilibili.com) 看吧安裝好了year

C語言鏈表使用

目錄 雙鏈表增刪改查鏈表帶功能函數 雙鏈表增刪改查 #include <stdio.h> #include <stdlib.h>// 雙鏈表結點的定義 typedef struct DNode{int data;struct DNode *prev;struct DNode *next; } DNode;// 創建雙鏈表 DNode *createDoublyLinkedList() {int n, i;pri…

【C語言】qsort的秘密

一&#xff0c;本文目標 qsort函數可以對任意類型數據甚至是結構體內部的數據按照你想要的規則排序&#xff0c;它的功能很強大&#xff0c;可是為什么呢&#xff1f; 我將通過模擬實現qsort函數來讓你對這整個過程有一個清晰的深刻的理解。 二&#xff0c;qsort函數原型 v…

leetcode刷題詳解一

算法題常用API std::accumulate 函數原型&#xff1a; template< class InputIt, class T > T accumulate( InputIt first, InputIt last, T init );一般求和的&#xff0c;代碼如下&#xff1a; int sum accumulate(vec.begin() , vec.end() , 0);詳細用法參考 lo…

【python海洋專題四十七】風速的風羽圖

【python海洋專題四十七】風速的風羽圖 圖片 往期推薦 圖片 【python海洋專題一】查看數據nc文件的屬性并輸出屬性到txt文件 【python海洋專題二】讀取水深nc文件并水深地形圖 【python海洋專題三】圖像修飾之畫布和坐標軸 【Python海洋專題四】之水深地圖圖像修飾 【Pyth…

記一次linux操作系統實驗

前言 最近完成了一個需要修改和編譯linux內核源碼的操作系統實驗&#xff0c;個人感覺這個實驗還是比較有意思的。這次實驗總共耗時4天&#xff0c;從對linux實現零基礎&#xff0c;通過查閱資料和不斷嘗試&#xff0c;直到完成實驗目標&#xff0c;在這過程中確實也收獲頗豐&…

pytorch模型優化簡介,未完結版

如有幫助&#xff0c;點贊收藏關注&#xff01; 如需轉載&#xff0c;請注明出處&#xff01; 今天來介紹torch模型中的優化器 優化是指在每個訓練步驟中調整模型參數以減少模型誤差的過程。 優化算法定義如何執行這個過程 所有優化邏輯都封裝在優化器對象中。在這里&#xf…

【黑馬甄選離線數倉day04_維度域開發】

1. 維度主題表數據導出 1.1 PostgreSQL介紹 PostgreSQL 是一個功能強大的開源對象關系數據庫系統&#xff0c;它使用和擴展了 SQL 語言&#xff0c;并結合了許多安全存儲和擴展最復雜數據工作負載的功能。 官方網址&#xff1a;PostgreSQL: The worlds most advanced open s…

音視頻項目——RTSP服務器解析(1)

介紹 利用線程池&#xff0c;實現 RTSP 服務器的高并發請求處理。 RTSP 是音視頻的控制視頻的協議&#xff0c;如果您還不了解&#xff0c;可以看看之前我解析 RTSP 協議的文章。音視頻協議解析(RTP/RTCP/RTSP/RTMP)——RTSP解析-CSDN博客 解析 我們先來看 RTP 的實現。RTP 是音…

Django框架之auth模塊

目錄 一、Auth模塊引入 二、創建超級用戶(管理員) 三、依賴于auth_user表完成登錄注冊功能 【1】基礎登陸 【2】保存用戶狀態 【3】登錄后跳轉 (1) 登錄后才能訪問頁面 -- 局部配置 (2) 登錄后才能訪問頁面 -- 全局配置 (3) 小結 三、修改密碼 四、注銷 五、注冊…

Springboot將多個圖片導出成zip壓縮包

Springboot將多個圖片導出成zip壓縮包 將多個圖片導出成zip壓縮包 /*** 判斷時間差是否超過6小時* param startTime 開始時間* param endTime 結束時間* return*/public static boolean isWithin6Hours(String startTime, String endTime) {// 定義日期時間格式DateTimeFormatt…

【數據結構】—搜索二叉樹(C++實現,超詳細!)

&#x1f3ac;慕斯主頁&#xff1a;修仙—別有洞天 ??今日夜電波&#xff1a;消えてしまいそうです—真夜中 1:15━━━━━━?&#x1f49f;──────── 4:18 &#x1f504; ?? ? ??…

函數計算的新征程:使用 Laf 構建 AI 知識庫

Laf 已成功上架 Sealos 模板市場&#xff0c;可通過 Laf 應用模板來一鍵部署&#xff01; 這意味著 Laf 在私有化部署上的擴展性得到了極大的提升。 Sealos 作為一個功能強大的云操作系統&#xff0c;能夠秒級創建多種高可用數據庫&#xff0c;如 MySQL、PostgreSQL、MongoDB …

js實現獲取原生form表單的數據序列化表單以及將數組轉化為一個對象obj,將數組中的內容作為對象的key轉化為對象,對應的值轉換為對象對應的值

1.需求場景 哈嘍 大家好啊&#xff0c;今天遇到一個場景&#xff0c; js實現獲取原生form表單的數據序列化表單以及將數組轉化為一個對象obj&#xff0c;將數組中的內容作為對象的key轉化為對象&#xff0c;對應的值轉換為對象對應的值 數組對象中某個屬性的值&#xff0c;轉…

元宇宙現已開放!

在 2023 年 11 月 3 日 The Sandbox 首個全球創作者日上&#xff0c;The Sandbox 聯合創始人 Arthur Madrid 和 Sebastien Borget 宣布元宇宙已開放&#xff0c;已創作完整體驗的 LAND 持有者可以自行將體驗發布至 The Sandbox 地圖上。 精選速覽 LAND 持有者&#xff1a;如果…

在JVM中 判定哪些對象是垃圾?

目錄 垃圾的條件 1、引用計數法 2、可達性分析 3、強引用 4、軟引用 5、弱引用 6、虛引用 判斷垃圾的條件 在Java虛擬機&#xff08;JVM&#xff09;中&#xff0c;垃圾收集器負責管理內存&#xff0c;其中的垃圾收集算法用于確定哪些對象是垃圾&#xff0c;可以被回收…