在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

數據結構的存儲方式及基本操作

jf_78858299 ? 來源:電子發燒友網官方 ? 作者:電子發燒友網官方 ? 2023-04-19 10:47 ? 次閱讀

這是好久之前的一篇文章 [學習數據結構的框架思維]的修訂版。之前那篇文章收到廣泛好評,沒看過也沒關系,這篇文章會涵蓋之前的所有內容,并且會舉很多代碼的實例,談談如何使用框架思維,并且給對于算法無從下手的朋友給一點具體可執行的刷題建議。

首先,這里講的都是普通的數據結構和算法,咱不是搞競賽的,野路子出生,只解決常規的問題,以面試為最終目標。另外,以下是我個人的經驗的總結,沒有哪本算法書會寫這些東西,所以請讀者試著理解我的角度,別糾結于細節問題,因為這篇文章就是對數據結構和算法建立一個框架性的認識。

從整體到細節,自頂向下,從抽象到具體的框架思維是通用的,不只是學習數據結構和算法,學習其他任何知識都是高效的。

先說數據結構,然后再說算法。

一、數據結構的存儲方式

數據結構的存儲方式只有兩種: 數組(順序存儲)和鏈表(鏈式存儲)

這句話怎么理解,不是還有散列表、棧、隊列、堆、樹、圖等等各種數據結構嗎?

我們分析問題,一定要有遞歸的思想,自頂向下,從抽象到具體。你上來就列出這么多,那些都屬于「上層建筑」,而數組和鏈表才是「結構基礎」。因為那些多樣化的數據結構,究其源頭,都是在鏈表或者數組上的特殊操作,API 不同而已。

比如說 「隊列 「棧」 這兩種數據結構既可以使用鏈表也可以使用數組實現。用數組實現,就要處理擴容縮容的問題;用鏈表實現,沒有這個問題,但需要更多的內存空間存儲節點指針。

「圖」 的兩種表示方法,鄰接表就是鏈表,鄰接矩陣就是二維數組。鄰接矩陣判斷連通性迅速,并可以進行矩陣運算解決一些問題,但是如果圖比較稀疏的話很耗費空間。鄰接表比較節省空間,但是很多操作的效率上肯定比不過鄰接矩陣。

「散列表」 就是通過散列函數把鍵映射到一個大數組里。而且對于解決散列沖突的方法,拉鏈法需要鏈表特性,操作簡單,但需要額外的空間存儲指針;線性探查法就需要數組特性,以便連續尋址,不需要指針的存儲空間,但操作稍微復雜些。

「樹」 ,用數組實現就是「堆」,因為「堆」是一個完全二叉樹,用數組存儲不需要節點指針,操作也比較簡單;用鏈表實現就是很常見的那種「樹」,因為不一定是完全二叉樹,所以不適合用數組存儲。為此,在這種鏈表「樹」結構之上,又衍生出各種巧妙的設計,比如二叉搜索樹、AVL 樹、紅黑樹、區間樹、B 樹等等,以應對不同的問題。

了解 Redis 數據庫的朋友可能也知道,Redis 提供列表、字符串、集合等等幾種常用數據結構,但是對于每種數據結構,底層的存儲方式都至少有兩種,以便于根據存儲數據的實際情況使用合適的存儲方式。

綜上,數據結構種類很多,甚至你也可以發明自己的數據結構,但是底層存儲無非數組或者鏈表, 二者的優缺點如下

數組由于是緊湊連續存儲,可以隨機訪問,通過索引快速找到對應元素,而且相對節約存儲空間。但正因為連續存儲,內存空間必須一次性分配夠,所以說數組如果要擴容,需要重新分配一塊更大的空間,再把數據全部復制過去,時間復雜度 O(N);而且你如果想在數組中間進行插入和刪除,每次必須搬移后面的所有數據以保持連續,時間復雜度 O(N)。

鏈表因為元素不連續,而是靠指針指向下一個元素的位置,所以不存在數組的擴容問題;如果知道某一元素的前驅和后驅,操作指針即可刪除該元素或者插入新元素,時間復雜度 O(1)。但是正因為存儲空間不連續,你無法根據一個索引算出對應元素的地址,所以不能隨機訪問;而且由于每個元素必須存儲指向前后元素位置的指針,會消耗相對更多的儲存空間。

二、數據結構的基本操作

對于任何數據結構,其基本操作無非遍歷 + 訪問,再具體一點就是:增刪查改。

數據結構種類很多,但它們存在的目的都是在不同的應用場景,盡可能高效地增刪查改 。話說這不就是數據結構的使命么?

如何遍歷 + 訪問?我們仍然從最高層來看,各種數據結構的遍歷 + 訪問無非兩種形式:線性的和非線性的。

線性就是 for/while 迭代為代表,非線性就是遞歸為代表。再具體一步,無非以下幾種框架:

數組遍歷框架,典型的線性迭代結構:

void traverse(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        // 迭代訪問 arr[i]
    }
}

鏈表遍歷框架,兼具迭代和遞歸結構:

/* 基本的單鏈表節點 */
class ListNode {
    int val;
    ListNode next;
}

void traverse(ListNode head) {
    for (ListNode p = head; p != null; p = p.next) {
        // 迭代訪問 p.val
    }
}

void traverse(ListNode head) {
    // 遞歸訪問 head.val
    traverse(head.next)
}

二叉樹遍歷框架,典型的非線性遞歸遍歷結構:

/* 基本的二叉樹節點 */
class TreeNode {
    int val;
    TreeNode left, right;
}

void traverse(TreeNode root) {
    traverse(root.left)
    traverse(root.right)
}

你看二叉樹的遞歸遍歷方式和鏈表的遞歸遍歷方式,相似不?再看看二叉樹結構和單鏈表結構,相似不?如果再多幾條叉,N 叉樹你會不會遍歷?

二叉樹框架可以擴展為 N 叉樹的遍歷框架:

/* 基本的 N 叉樹節點 */
class TreeNode {
    int val;
    TreeNode[] children;
}

void traverse(TreeNode root) {
    for (TreeNode child : root.children)
        traverse(child)
}

N 叉樹的遍歷又可以擴展為圖的遍歷,因為圖就是好幾 N 叉棵樹的結合體。你說圖是可能出現環的?這個很好辦,用個布爾數組 visited 做標記就行了,這里就不寫代碼了。

所謂框架,就是套路。不管增刪查改,這些代碼都是永遠無法脫離的結構,你可以把這個結構作為大綱,根據具體問題在框架上添加代碼就行了,下面會具體舉例

三、算法刷題指南

首先要明確的是, 數據結構是工具,算法是通過合適的工具解決特定問題的方法 。也就是說,學習算法之前,最起碼得了解那些常用的數據結構,了解它們的特性和缺陷。

那么該如何在 LeetCode 刷題呢?之前的文章 [算法學習之路]寫過一些,什么按標簽刷,堅持下去云云。現在距那篇文章已經過去將近一年了,我不想說那些不痛不癢的話了,直接說具體的建議:

先刷二叉樹,先刷二叉樹,先刷二叉樹

圖片

這是我這刷題的親身體會,下圖是我從 2018/10 到 2019/10 這一年的心路歷程:

圖片

公眾號文章的閱讀數據顯示,大部分人對數據結構相關的算法文章不感興趣,而是更關心動規回溯分治等等技巧。為什么要先刷二叉樹呢, 因為二叉樹是最容易培養框架思維的,而且大部分算法技巧,本質上都是樹的遍歷問題

刷二叉樹看到題目沒思路?根據很多讀者的問題,其實大家不是沒思路,只是沒有理解我們說的「框架」是什么。 不要小看這幾行破代碼,幾乎所有二叉樹的題目都是一套這個框架就出來了

void traverse(TreeNode root) {
    // 前序遍歷
    traverse(root.left)
    // 中序遍歷
    traverse(root.right)
    // 后序遍歷
}

比如說我隨便拿幾道題的解法出來,不用管具體的代碼邏輯,只要看看框架在其中是如何發揮作用的就行。

LeetCode 124 題,難度 Hard,讓你求二叉樹中最大路徑和,主要代碼如下:

圖片

看出來了嗎,這就是個后序遍歷嘛。

LeetCode 105 題,難度 Medium,讓你根據前序遍歷和中序遍歷的結果還原一棵二叉樹,很經典的問題吧,主要代碼如下:

圖片

不要看這個函數的參數很多,只是為了控制數組索引而已,本質上該算法也就是一個前序遍歷。

LeetCode 99 題,難度 Hard,恢復一棵 BST,主要代碼如下:

圖片

這不就是個中序遍歷嘛,對于一棵 BST 中序遍歷意味著什么,應該不需要解釋了吧。

你看,Hard 難度的題目不過如此,而且還這么有規律可循,只要把框架寫出來,然后往相應的位置加東西就行了,這不就是思路嗎。

剛開始刷二叉樹的題目,前 10 道也許有點難受;結合框架再做 20 道,也許你就有點自己的理解了;刷完整個專題,再去做什么回溯動規分治專題,你就會發現只要涉及遞 歸的問題,都是樹的問題

直接舉例吧,說幾道我們之前文章寫過的問題。

[動態規劃詳解]說過湊零錢問題,暴力解法就是遍歷一棵 N 叉樹:

def coinChange(coins: List[int], amount: int):

    def dp(n):
        if n == 0: return 0
        if n < 0: return -1

        res = float('INF')
        for coin in coins:
            subproblem = dp(n - coin)
            # 子問題無解,跳過
            if subproblem == -1: continue
            res = min(res, 1 + subproblem)
        return res if res != float('INF') else -1

    return dp(amount)

這么多代碼看不懂咋辦?直接提取出框架,就能看出核心思路了:

# 不過是一個 N 叉樹的遍歷問題而已
def dp(n):
    for coin in coins:
        dp(n - coin)

圖片

其實很多動態規劃問題就是在遍歷一棵樹,你如果對樹的遍歷操作爛熟于心,起碼知道怎么把思路轉化成代碼,也知道如何提取別人解法的核心思路。

再看看回溯算法,前文 [回溯算法詳解]干脆直接說了,回溯算法就是個 N 叉樹的前后序遍歷問題,沒有例外。

比如 N 皇后問題吧,主要代碼如下:

void backtrack(int[] nums, LinkedList) {
    if (track.size() == nums.length) {
        res.add(new LinkedList(track));
        return;
    }

    for (int i = 0; i < nums.length; i++) {
        if (track.contains(nums[i]))
            continue;
        track.add(nums[i]);
        // 進入下一層決策樹
        backtrack(nums, track);
        track.removeLast();
    }

/* 提取出 N 叉樹遍歷框架 */
void backtrack(int[] nums, LinkedList) {
    for (int i = 0; i < nums.length; i++) {
        backtrack(nums, track);
}

N 叉樹的遍歷框架,找出來了吧。你說,樹這種結構重不重要?

綜上,對于算法無從下手的朋友來說,可以先刷樹的相關題目,試著從框架上看問題,而不要糾結于細節問題

糾結細節問題,就比如糾結 i 到底應該加到 n 還是加到 n - 1,這個數組的大小到底應該開 n 還是 n + 1 ?

從框架上看問題,就是像我們這樣基于框架進行抽取和擴展,既可以在看別人解法時快速理解核心邏輯,也有助于找到我們自己寫解法時的思路方向。

當然,如果細節出錯,你得不到正確的答案,但是只要有框架,你再錯也錯不到哪去,因為你的方向是對的。

但是,你要是心中沒有框架,那么你根本無法解題,給了你答案,你也不會發現這就是個樹的遍歷問題。

這種思維是很重要的,[動態規劃詳解] 中總結的找狀態轉移方程的幾步流程,有時候按照流程寫出解法,說實話我自己都不知道為啥是對的,反正它就是對了。。。

這就是框架的力量,能夠保證你在快睡著的時候,依然能寫出正確的程序; 就算你啥都不會,都能比別人高一個級別。

四、最后總結

數據結構的基本存儲方式就是鏈式和順序兩種,基本操作就是增刪查改,遍歷方式無非迭代和遞歸。

刷算法題建議從「樹」分類開始刷,結合框架思維,把這幾十道題刷完,對于樹結構的理解應該就到位了。這時候去看回溯、動規、分治等算法專題,對思路的理解可能會更加深刻一些。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 算法
    +關注

    關注

    23

    文章

    4625

    瀏覽量

    93129
  • 數據結構
    +關注

    關注

    3

    文章

    573

    瀏覽量

    40176
  • 數組
    +關注

    關注

    1

    文章

    417

    瀏覽量

    25993
收藏 人收藏

    評論

    相關推薦

    快速介紹8種常用數據結構

    數據結構是一種特殊的組織和存儲數據方式,可以使我們可以更高效地對存儲數據執行
    發表于 06-21 09:27 ?774次閱讀
    快速介紹8種常用<b class='flag-5'>數據結構</b>

    數據結構

    結構,是指數據在計算機中存放的方式,包括數據元素的存儲和關系的存儲。通常,一種
    發表于 03-04 14:13

    常見的數據結構

    `數據結構在實際應用中非常常見,現在各種算法基本都牽涉到數據結構,因此,掌握數據結構算是軟件工程師的必備技能。一、什么是數據結構數據結構,直
    發表于 05-10 07:58

    數據結構鏈表的基本操作

    嵌入式學習基礎-數據結構鏈表的基本操作鏈表節點采用結構體的方式進行定義,下面是最基礎的定義只有一個數據data,*pNext用于指向下一個節
    發表于 12-22 08:05

    FlashDB如何解決存儲數據后擴展數據結構的問題

    1.假定數據A的大小為10個字節,使用FlashDB存儲在外部flash中;2.擴充A的數據結構大小為20個字節,不更改key值,那么在讀取時是否會讀取越界?3.重新存儲擴展后的
    發表于 11-14 14:41

    GPIB命令的數據結構

    針對GPIB命令的結構,提出一種存儲GPIB命令的數據結構。根據GPIB命令的層次關系的特點,選擇數據結構中“樹”的概念來存儲GPIB命令結
    發表于 02-10 16:20 ?70次下載

    GPIB命令的數據結構

    針對GPIB命令的結構,提出一種存儲GPIB命令的數據結構。根據GPIB命令的層次關系的特點,選擇數據結構中“樹”的概念來存儲GPIB命令結
    發表于 01-04 10:13 ?0次下載

    數據結構_嚴蔚敏

    數據結構是計算機存儲、組織數據方式數據結構是指相互之間存在一種或多種特定關系的數據元素的集合
    發表于 10-28 17:25 ?0次下載
    <b class='flag-5'>數據結構</b>_嚴蔚敏

    數據結構是什么_數據結構有什么用

    數據結構是計算機存儲、組織數據方式數據結構是指相互之間存在一種或多種特定關系的數據元素的集合
    發表于 11-17 14:45 ?1.6w次閱讀
    <b class='flag-5'>數據結構</b>是什么_<b class='flag-5'>數據結構</b>有什么用

    什么是數據結構?為什么要學習數據結構數據結構的應用實例分析

    本文檔的主要內容詳細介紹的是什么是數據結構?為什么要學習數據結構數據結構的應用實例分析包括了:數據結構在串口通信當中的應用,數據結構在按鍵
    發表于 09-26 15:45 ?14次下載
    什么是<b class='flag-5'>數據結構</b>?為什么要學習<b class='flag-5'>數據結構</b>?<b class='flag-5'>數據結構</b>的應用實例分析

    這些程序員必須知道的數據結構你知道多少

    數據結構是一種特殊的組織和存儲數據方式,可以使我們可以更高效地對存儲數據執行
    的頭像 發表于 04-06 12:09 ?2313次閱讀
    這些程序員必須知道的<b class='flag-5'>數據結構</b>你知道多少

    常見的數據結構有哪些

    數據結構是計算機存儲、組織數據方式,是指相互之間存在一種或多種特定關系的數據元素的集合
    的頭像 發表于 04-06 17:26 ?3237次閱讀
    常見的<b class='flag-5'>數據結構</b>有哪些

    嵌入式軟件常見的8種數據結構

    數據結構是一種特殊的組織和存儲數據方式,可以使我們可以更高效地對存儲數據執行
    的頭像 發表于 05-04 10:28 ?951次閱讀
    嵌入式軟件常見的8種<b class='flag-5'>數據結構</b>

    epoll的基礎數據結構

    一、epoll的基礎數據結構 在開始研究源代碼之前,我們先看一下 epoll 中使用的數據結構,分別是 eventpoll、epitem 和 eppoll_entry。 1、eventpoll 我們
    的頭像 發表于 11-10 10:20 ?831次閱讀
    epoll的基礎<b class='flag-5'>數據結構</b>

    redis數據結構的底層實現

    ,包括字符串、列表、哈希表、集合和有序集合。每種數據結構都有不同的底層實現,以滿足對于不同操作的高效支持。 首先,我們來看Redis中最基本的數據結構——字符串。Redis的字符串是二進制安全的,可以
    的頭像 發表于 12-05 10:14 ?643次閱讀
    主站蜘蛛池模板: 免费黄色网址网站| 国产精品va在线观看不| h视频免费观看| 丁香六月婷婷七月激情| 天天色资料| 在线看片成人| 寡妇影院首页亚洲图片| 国内真实下药迷j在线观看| 国产成人精品高清免费| 亚洲欧洲第一页| 一日本道加勒比高清一二三| 97影院午夜午夜伦不卡| 69日本xxxxxxxx59| 日本免费一区二区老鸭窝| 丁香五月缴情在线| 二区三区在线| 色秀视频免费高清网站| 亚洲国产丝袜精品一区杨幂 | 免费国产黄网站在线观看视频| 免费能直接在线观看黄的视频| 国产色丁香久久综合| 午夜免费片| 国产亚洲papapa| 亚洲人成一区| 五月婷婷精品| 就要爱综合| 亚洲精品午夜视频| 国产毛片哪里有| 欧美人成一本免费观看视频| 色爱区综合五月激情| 亚洲一级免费视频| 一卡二卡卡四卡无人区中文| 日本媚薬痉挛在线观看免费| 国产特黄一级毛片特黄| 天天干天天爽| 免费人成网站线观看合集| 天堂网www中文天堂在线| 天天干天天噜| 视频在线观看免费网址| 一级毛片a| 久久国产精品免费网站|