成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript 數(shù)據(jù)結(jié)構(gòu)與算法之美 - 非線性表中的樹、堆是干嘛用的 ?其數(shù)據(jù)結(jié)構(gòu)是怎樣的 ?

singerye / 1798人閱讀

摘要:筆者寫的數(shù)據(jù)結(jié)構(gòu)與算法之美系列用的語言是,旨在入門數(shù)據(jù)結(jié)構(gòu)與算法和方便以后復(fù)習(xí)。非線性表中的樹堆是干嘛用的其數(shù)據(jù)結(jié)構(gòu)是怎樣的希望大家?guī)е@兩個(gè)問題閱讀下文。其中,前中后序,表示的是節(jié)點(diǎn)與它的左右子樹節(jié)點(diǎn)遍歷訪問的先后順序。

1. 前言
想學(xué)好前端,先練好內(nèi)功,內(nèi)功不行,就算招式練的再花哨,終究成不了高手。

非線性表(樹、堆),可以說是前端程序員的內(nèi)功,要知其然,知其所以然。

筆者寫的 JavaScript 數(shù)據(jù)結(jié)構(gòu)與算法之美 系列用的語言是 JavaScript ,旨在入門數(shù)據(jù)結(jié)構(gòu)與算法和方便以后復(fù)習(xí)。

非線性表中的樹、堆是干嘛用的 ?其數(shù)據(jù)結(jié)構(gòu)是怎樣的 ?

希望大家?guī)е@兩個(gè)問題閱讀下文。

2. 樹

的數(shù)據(jù)結(jié)構(gòu)就像我們生活中的真實(shí)的樹,只不過是倒過來的形狀。

術(shù)語定義

節(jié)點(diǎn):樹中的每個(gè)元素稱為節(jié)點(diǎn),如 A、B、C、D、E、F、G、H、I、J。

父節(jié)點(diǎn):指向子節(jié)點(diǎn)的節(jié)點(diǎn),如 A。

子節(jié)點(diǎn):被父節(jié)點(diǎn)指向的節(jié)點(diǎn),如 A 的孩子 B、C、D。

父子關(guān)系:相鄰兩節(jié)點(diǎn)的連線,稱為父子關(guān)系,如 A 與 B,C 與 H,D 與 J。

根節(jié)點(diǎn):沒有父節(jié)點(diǎn)的節(jié)點(diǎn),如 A。

葉子節(jié)點(diǎn):沒有子節(jié)點(diǎn)的節(jié)點(diǎn),如 E、F、G、H、I、J。

兄弟節(jié)點(diǎn):具有相同父節(jié)點(diǎn)的多個(gè)節(jié)點(diǎn)稱為兄弟節(jié)點(diǎn),如 B、C、D。

節(jié)點(diǎn)的高度:節(jié)點(diǎn)到葉子節(jié)點(diǎn)的最長路徑所包含的邊數(shù)。

節(jié)點(diǎn)的深度:根節(jié)點(diǎn)到節(jié)點(diǎn)的路徑所包含的邊數(shù)。

節(jié)點(diǎn)層數(shù):節(jié)點(diǎn)的深度 +1(根節(jié)點(diǎn)的層數(shù)是 1 )。

樹的高度:等于根節(jié)點(diǎn)的高度。

森林: n 棵互不相交的樹的集合。

高度是從下往上度量,比如一個(gè)人的身高 180cm ,起點(diǎn)就是從 0 開始的。
深度是從上往下度量,比如泳池的深度 180cm ,起點(diǎn)也是從 0 開始的。
高度和深度是帶有字的,都是從 0 開始計(jì)數(shù)的。
而層數(shù)的計(jì)算,是和我們平時(shí)的樓層的計(jì)算是一樣的,最底下那層是第 1 層,是從 1 開始計(jì)數(shù)的,所以根節(jié)點(diǎn)位于第 1 層,其他子節(jié)點(diǎn)依次加 1。

二叉樹分類

二叉樹

每個(gè)節(jié)點(diǎn)最多只有 2 個(gè)子節(jié)點(diǎn)的樹,這兩個(gè)節(jié)點(diǎn)分別是左子節(jié)點(diǎn)和右子節(jié)點(diǎn)。如上圖中的 1、 2、3。

不過,二叉樹并不要求每個(gè)節(jié)點(diǎn)都有兩個(gè)子節(jié)點(diǎn),有的節(jié)點(diǎn)只有左子節(jié)點(diǎn),有的節(jié)點(diǎn)只有右子節(jié)點(diǎn)。以此類推,自己想四叉樹、八叉樹的結(jié)構(gòu)圖。

滿二叉樹

一種特殊的二叉樹,除了葉子節(jié)點(diǎn)外,每個(gè)節(jié)點(diǎn)都有左右兩個(gè)子節(jié)點(diǎn),這種二叉樹叫做滿二叉樹。如上圖中的 2。

完全二叉樹

一種特殊的二叉樹,葉子節(jié)點(diǎn)都在最底下兩層,最后一層葉子節(jié)都靠排列,并且除了最后一層,其他層的節(jié)點(diǎn)個(gè)數(shù)都要達(dá)到最大,這種二叉樹叫做完全二叉樹。如上圖的 3。

完全二叉樹與不是完全二叉樹的區(qū)分比較難,所以對比下圖看看。

之前的文章 棧內(nèi)存與堆內(nèi)存 、淺拷貝與深拷貝 中有說到:JavaScript 中的引用類型(如對象、數(shù)組、函數(shù)等)是保存在堆內(nèi)存中的對象,值大小不固定,棧內(nèi)存中存放的該對象的訪問地址指向堆內(nèi)存中的對象,JavaScript 不允許直接訪問堆內(nèi)存中的位置,因此操作對象時(shí),實(shí)際操作對象的引用。

那么到底是什么呢 ?其數(shù)據(jù)結(jié)構(gòu)又是怎樣的呢 ?

堆其實(shí)是一種特殊的樹。只要滿足這兩點(diǎn),它就是一個(gè)堆。

堆是一個(gè)完全二叉樹。

完全二叉樹:除了最后一層,其他層的節(jié)點(diǎn)個(gè)數(shù)都是滿的,最后一層的節(jié)點(diǎn)都靠左排列。

堆中每一個(gè)節(jié)點(diǎn)的值都必須大于等于(或小于等于)其子樹中每個(gè)節(jié)點(diǎn)的值。

也可以說:堆中每個(gè)節(jié)點(diǎn)的值都大于等于(或者小于等于)其左右子節(jié)點(diǎn)的值。這兩種表述是等價(jià)的。

對于每個(gè)節(jié)點(diǎn)的值都大于等于子樹中每個(gè)節(jié)點(diǎn)值的堆,我們叫作大頂堆。對于每個(gè)節(jié)點(diǎn)的值都小于等于子樹中每個(gè)節(jié)點(diǎn)值的堆,我們叫作小頂堆。

其中圖 1 和 圖 2 是大頂堆,圖 3 是小頂堆,圖 4 不是堆。除此之外,從圖中還可以看出來,對于同一組數(shù)據(jù),我們可以構(gòu)建多種不同形態(tài)的堆。

二叉查找樹(Binary Search Tree)

一種特殊的二叉樹,相對較小的值保存在左節(jié)點(diǎn)中,較大的值保存在右節(jié)點(diǎn)中,叫二叉查找樹,也叫二叉搜索樹。

二叉查找樹是一種有序的樹,所以支持快速查找、快速插入、刪除一個(gè)數(shù)據(jù)。
下圖中, 3 個(gè)都是二叉查找樹,

平衡二叉查找樹

平衡二叉查找樹:二叉樹中任意一個(gè)節(jié)點(diǎn)的左右子樹的高度相差不能大于 1

從這個(gè)定義來看,完全二叉樹、滿二叉樹其實(shí)都是平衡二叉樹,但是非完全二叉樹也有可能是平衡二叉樹。
平衡二叉查找樹中平衡的意思,其實(shí)就是讓整棵樹左右看起來比較對稱、比較平衡,不要出現(xiàn)左子樹很高、右子樹很矮的情況。這樣就能讓整棵樹的高度相對來說低一些,相應(yīng)的插入、刪除、查找等操作的效率高一些。
平衡二叉查找樹其實(shí)有很多,比如,Splay Tree(伸展樹)、Treap(樹堆)等,但是我們提到平衡二叉查找樹,聽到的基本都是紅黑樹。

紅黑樹(Red-Black Tree)

紅黑樹中的節(jié)點(diǎn),一類被標(biāo)記為黑色,一類被標(biāo)記為紅色。除此之外,一棵紅黑樹還需要滿足這樣幾個(gè)要求:

根節(jié)點(diǎn)是黑色的。

每個(gè)葉子節(jié)點(diǎn)都是黑色的空節(jié)點(diǎn)(NIL),也就是說,葉子節(jié)點(diǎn)不存儲(chǔ)數(shù)據(jù)。

任何相鄰的節(jié)點(diǎn)都不能同時(shí)為紅色,也就是說,紅色節(jié)點(diǎn)是被黑色節(jié)點(diǎn)隔開的。

每個(gè)節(jié)點(diǎn),從該節(jié)點(diǎn)到達(dá)其可達(dá)葉子節(jié)點(diǎn)的所有路徑,都包含相同數(shù)目的黑色節(jié)點(diǎn)。

下面兩個(gè)都是紅黑樹。

存儲(chǔ)

完全二叉樹的存儲(chǔ)

鏈?zhǔn)酱鎯?chǔ)

每個(gè)節(jié)點(diǎn)由 3 個(gè)字段,其中一個(gè)存儲(chǔ)數(shù)據(jù),另外兩個(gè)是指向左右子節(jié)點(diǎn)的指針。
我們只要拎住根節(jié)點(diǎn),就可以通過左右子節(jié)點(diǎn)的指針,把整棵樹都串起來。
這種存儲(chǔ)方式比較常用,大部分二叉樹代碼都是通過這種方式實(shí)現(xiàn)的。

順序存儲(chǔ)

用數(shù)組來存儲(chǔ),對于完全二叉樹,如果節(jié)點(diǎn) X 存儲(chǔ)在數(shù)組中的下標(biāo)為 i ,那么它的左子節(jié)點(diǎn)的存儲(chǔ)下標(biāo)為 2 i ,右子節(jié)點(diǎn)的下標(biāo)為 2 i + 1,反過來,下標(biāo) i / 2 位置存儲(chǔ)的就是該節(jié)點(diǎn)的父節(jié)點(diǎn)。
注意,根節(jié)點(diǎn)存儲(chǔ)在下標(biāo)為 1 的位置。完全二叉樹用數(shù)組來存儲(chǔ)是最省內(nèi)存的方式。

二叉樹的遍歷

經(jīng)典的方法有三種:前序遍歷、中序遍歷、后序遍歷。其中,前、中、后序,表示的是節(jié)點(diǎn)與它的左右子樹節(jié)點(diǎn)遍歷訪問的先后順序。

前序遍歷(根 => 左 => 右)

對于樹中的任意節(jié)點(diǎn)來說,先訪問這個(gè)節(jié)點(diǎn),然后再訪問它的左子樹,最后訪問它的右子樹。

中序遍歷(左 => 根 => 右)

對于樹中的任意節(jié)點(diǎn)來說,先訪問它的左子樹,然后再訪問它的本身,最后訪問它的右子樹。

后序遍歷(左 => 右 => 根)

對于樹中的任意節(jié)點(diǎn)來說,先訪問它的左子樹,然后再訪問它的右子樹,最后訪問它本身。

實(shí)際上,二叉樹的前、中、后序遍歷就是一個(gè)遞歸的過程。

時(shí)間復(fù)雜度:3 種遍歷方式中,每個(gè)節(jié)點(diǎn)最多會(huì)被訪問 2 次,跟節(jié)點(diǎn)的個(gè)數(shù) n 成正比,所以時(shí)間復(fù)雜度是 O(n)。

實(shí)現(xiàn)二叉查找樹

二叉查找樹的特點(diǎn)是:相對較小的值保存在左節(jié)點(diǎn)中,較大的值保存在右節(jié)點(diǎn)中。

代碼實(shí)現(xiàn)二叉查找樹,方法有以下這些。

方法

insert(key):向樹中插入一個(gè)新的鍵。

search(key):在樹中查找一個(gè)鍵,如果節(jié)點(diǎn)存在,則返回 true;如果不存在,則返回 false。

min:返回樹中最小的值/鍵。

max:返回樹中最大的值/鍵。

remove(key):從樹中移除某個(gè)鍵。

遍歷

preOrderTraverse:通過先序遍歷方式遍歷所有節(jié)點(diǎn)。

inOrderTraverse:通過中序遍歷方式遍歷所有節(jié)點(diǎn)。

postOrderTraverse:通過后序遍歷方式遍歷所有節(jié)點(diǎn)。

具體代碼

首先實(shí)現(xiàn)二叉查找樹類的類

// 二叉查找樹類
function BinarySearchTree() {
    // 用于實(shí)例化節(jié)點(diǎn)的類
    var Node = function(key){
        this.key = key; // 節(jié)點(diǎn)的健值
        this.left = null; // 指向左節(jié)點(diǎn)的指針
        this.right = null; // 指向右節(jié)點(diǎn)的指針
    };
    var root = null; // 將根節(jié)點(diǎn)置為null
}

insert 方法,向樹中插入一個(gè)新的鍵。

遍歷樹,將插入節(jié)點(diǎn)的鍵值與遍歷到的節(jié)點(diǎn)鍵值比較,如果前者大于后者,繼續(xù)遞歸遍歷右子節(jié)點(diǎn),反之,繼續(xù)遍歷左子節(jié)點(diǎn),直到找到一個(gè)空的節(jié)點(diǎn),在該位置插入。

this.insert = function(key){
    var newNode = new Node(key); // 實(shí)例化一個(gè)節(jié)點(diǎn)
    if (root === null){
        root = newNode; // 如果樹為空,直接將該節(jié)點(diǎn)作為根節(jié)點(diǎn)
    } else {
        insertNode(root,newNode); // 插入節(jié)點(diǎn)(傳入根節(jié)點(diǎn)作為參數(shù))
    }
};
// 插入節(jié)點(diǎn)的函數(shù)
var insertNode = function(node, newNode){
    // 如果插入節(jié)點(diǎn)的鍵值小于當(dāng)前節(jié)點(diǎn)的鍵值
    // (第一次執(zhí)行insertNode函數(shù)時(shí),當(dāng)前節(jié)點(diǎn)就是根節(jié)點(diǎn))
    if (newNode.key < node.key){
        if (node.left === null){
            // 如果當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)為空,就直接在該左子節(jié)點(diǎn)處插入
            node.left = newNode;
        } else {
            // 如果左子節(jié)點(diǎn)不為空,需要繼續(xù)執(zhí)行insertNode函數(shù),
            // 將要插入的節(jié)點(diǎn)與左子節(jié)點(diǎn)的后代繼續(xù)比較,直到找到能夠插入的位置
            insertNode(node.left, newNode);
        }
    } else {
        // 如果插入節(jié)點(diǎn)的鍵值大于當(dāng)前節(jié)點(diǎn)的鍵值
        // 處理過程類似,只是insertNode函數(shù)繼續(xù)比較的是右子節(jié)點(diǎn)
        if (node.right === null){
            node.right = newNode;
        } else {
            insertNode(node.right, newNode);
        }
    }
}

在下圖的樹中插入健值為 6 的節(jié)點(diǎn),過程如下:

搜索最小值

在二叉搜索樹里,不管是整個(gè)樹還是其子樹,最小值一定在樹最左側(cè)的最底層。
因此給定一顆樹或其子樹,只需要一直向左節(jié)點(diǎn)遍歷到底就行了。

this.min = function(node) {
    // min方法允許傳入子樹
    node = node || root;
    // 一直遍歷左側(cè)子節(jié)點(diǎn),直到底部
    while (node && node.left !== null) {
        node = node.left;
    }
    return node;
};

搜索最大值

搜索最大值與搜索最小值類似,只是沿著樹的右側(cè)遍歷。

this.max = function(node) {
    // min方法允許傳入子樹
    node = node || root;
    // 一直遍歷左側(cè)子節(jié)點(diǎn),直到底部
    while (node && node.right !== null) {
        node = node.right;
    }
    return node;
};

搜索特定值

搜索特定值的處理與插入值的處理類似。遍歷樹,將要搜索的值與遍歷到的節(jié)點(diǎn)比較,如果前者大于后者,則遞歸遍歷右側(cè)子節(jié)點(diǎn),反之,則遞歸遍歷左側(cè)子節(jié)點(diǎn)。

this.search = function(key, node){
    // 同樣的,search方法允許在子樹中查找值
    node = node || root;
    return searchNode(key, node);
};
var searchNode = function(key, node){
    // 如果node是null,說明樹中沒有要查找的值,返回false
    if (node === null){
        return false;
    }
    if (key < node.key){
        // 如果要查找的值小于該節(jié)點(diǎn),繼續(xù)遞歸遍歷其左側(cè)節(jié)點(diǎn)
        return searchNode(node.left, key);
    } else if (key > node.key){
        // 如果要查找的值大于該節(jié)點(diǎn),繼續(xù)遞歸遍歷其右側(cè)節(jié)點(diǎn)
        return searchNode(node.right, key);
    } else {
        // 如果要查找的值等于該節(jié)點(diǎn),說明查找成功,返回改節(jié)點(diǎn)
        return node;
    }
};

移除節(jié)點(diǎn)

移除節(jié)點(diǎn),首先要在樹中查找到要移除的節(jié)點(diǎn),再判斷該節(jié)點(diǎn)是否有子節(jié)點(diǎn)、有一個(gè)子節(jié)點(diǎn)或者有兩個(gè)子節(jié)點(diǎn),最后分別處理。

this.remove = function(key, node) {
    // 同樣的,允許僅在子樹中刪除節(jié)點(diǎn)
    node = node || root;
    return removeNode(key, node);
};
var self = this;
var removeNode = function(key, node) {
    // 如果 node 不存在,直接返回
    if (node === false) {
        return null;
    }

    // 找到要?jiǎng)h除的節(jié)點(diǎn)
    node = self.search(key, node);

    // 第一種情況,該節(jié)點(diǎn)沒有子節(jié)點(diǎn)
    if (node.left === null && node.right === null) {
        node = null;
        return node;
    }
    // 第二種情況,該節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn)的節(jié)點(diǎn)
    if (node.left === null) {
        // 只有右節(jié)點(diǎn)
        node = node.right;
        return node;
    } else if (node.right === null) {
        // 只有左節(jié)點(diǎn)
        node = node.left;
        return node;
    }
    // 第三種情況,有有兩個(gè)子節(jié)點(diǎn)的節(jié)點(diǎn)
    // 將右側(cè)子樹中的最小值,替換到要?jiǎng)h除的位置
    // 找到最小值
    var aux = self.min(node.right);
    // 替換
    node.key = aux.key;
    // 刪除最小值
    node.right = removeNode(aux.key, node.right);
    return node;
};

第三種情況的處理過程,如下圖所示。
當(dāng)要?jiǎng)h除的節(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn)時(shí),為了不破壞樹的結(jié)構(gòu),刪除后要替補(bǔ)上來的節(jié)點(diǎn)的鍵值大小必須在已刪除節(jié)點(diǎn)的左、右子節(jié)點(diǎn)的鍵值之間,且替補(bǔ)上來的節(jié)點(diǎn)不應(yīng)該有子節(jié)點(diǎn),否則會(huì)產(chǎn)生一個(gè)節(jié)點(diǎn)有多個(gè)字節(jié)點(diǎn)的情況,因此,找右側(cè)子樹的最小值替換上來。
同理,找左側(cè)子樹的最大值替換上來也可以。

先序遍歷

this.preOrderTraverse = function(callback){
    // 同樣的,callback用于對遍歷到的節(jié)點(diǎn)做操作
    preOrderTraverseNode(root, callback);
};
var preOrderTraverseNode = function (node, callback) {
    // 遍歷到node為null為止
    if (node !== null) {
        callback(node.key); // 先處理當(dāng)前節(jié)點(diǎn)
        preOrderTraverseNode(node.left, callback); // 再繼續(xù)遍歷左子節(jié)點(diǎn)
        preOrderTraverseNode(node.right, callback); // 最后遍歷右子節(jié)點(diǎn)
    }
};

用先序遍歷遍歷下圖所示的樹,并打印節(jié)點(diǎn)鍵值。
輸出結(jié)果:11 7 5 3 6 9 8 10 15 13 12 14 20 18 25。
遍歷過程如圖:

中序遍歷

this.inOrderTraverse = function(callback){
    // callback用于對遍歷到的節(jié)點(diǎn)做操作
    inOrderTraverseNode(root, callback);
};
var inOrderTraverseNode = function (node, callback) {
    // 遍歷到node為null為止
    if (node !== null) {
        // 優(yōu)先遍歷左邊節(jié)點(diǎn),保證從小到大遍歷
        inOrderTraverseNode(node.left, callback);
        // 處理當(dāng)前的節(jié)點(diǎn)
        callback(node.key);
        // 遍歷右側(cè)節(jié)點(diǎn)
        inOrderTraverseNode(node.right, callback);
    }
};

對下圖的樹做中序遍歷,并輸出各個(gè)節(jié)點(diǎn)的鍵值。
依次輸出:3 5 6 7 8 9 10 11 12 13 14 15 18 20 25。
遍歷過程如圖:

后序遍歷

this.postOrderTraverse = function(callback){
    postOrderTraverseNode(root, callback);
};
var postOrderTraverseNode = function (node, callback) {
    if (node !== null) {
        postOrderTraverseNode(node.left, callback); //{1}
        postOrderTraverseNode(node.right, callback); //{2}
        callback(node.key); //{3}
    }
};

可以看到,中序、先序、后序遍歷的實(shí)現(xiàn)方式幾乎一模一樣,只是 {1}、{2}、{3} 行代碼的執(zhí)行順序不同。
對下圖的樹進(jìn)行后序遍歷,并打印鍵值:3 6 5 8 10 9 7 12 14 13 18 25 20 15 11。
遍歷過程如圖:

添加打印的方法 print。

this.print = function() {
  console.log("root :", root);
  return root;
};

完整代碼請看文件 binary-search-tree.html

測試過程:

// 測試
var binarySearchTree = new BinarySearchTree();
var arr = [11, 7, 5, 3, 6, 9, 8, 10, 15, 13, 12, 14, 20, 18, 25];
for (var i = 0; i < arr.length; i++) {
    var value = arr[i];
    binarySearchTree.insert(value);
}

console.log("先序遍歷:");
var arr = [];
binarySearchTree.preOrderTraverse(function(value) {
    // console.log(value);
    arr.push(value);
});
console.log("arr :", arr); // [11, 7, 5, 3, 6, 9, 8, 10, 15, 13, 12, 14, 20, 18, 25]

var min = binarySearchTree.min();
console.log("min:", min); // 3
var max = binarySearchTree.max();
console.log("max:", max); // 25
var search = binarySearchTree.search(10);
console.log("search:", search); // 10
var remove = binarySearchTree.remove(13);
console.log("remove:", remove); // 13

console.log("先序遍歷:");
var arr1 = [];
binarySearchTree.preOrderTraverse(function(value) {
    // console.log(value);
    arr1.push(value);
});
console.log("arr1 :", arr1); // ?[11, 7, 5, 3, 6, 9, 8, 10, 15, 14, 12, 20, 18, 25]

console.log("中序遍歷:");
var arr2 = [];
binarySearchTree.inOrderTraverse(function(value) {
    // console.log(value);
    arr2.push(value);
}); 
console.log("arr2 :", arr2); //?[3, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 20, 25]

console.log("后序遍歷:");
var arr3 = [];
binarySearchTree.postOrderTraverse(function(value) {
    // console.log(value);
    arr3.push(value);
});
console.log("arr3 :", arr3); // ?[3, 6, 5, 8, 10, 9, 7, 12, 14, 18, 25, 20, 15, 11]

binarySearchTree.print(); // 看控制臺(tái)

結(jié)果如下:

看到這里,你能解答文章的題目 非線性表中的樹、堆是干嘛用的 ?其數(shù)據(jù)結(jié)構(gòu)是怎樣的 ?

如果不能,建議再回頭仔細(xì)看看哦。

3. 文章輸出計(jì)劃

JavaScript 數(shù)據(jù)結(jié)構(gòu)與算法之美 的系列文章,堅(jiān)持 3 - 7 天左右更新一篇,暫定計(jì)劃如下表。

| 標(biāo)題 | 鏈接 |
| :------ | :------ |
| 時(shí)間和空間復(fù)雜度 | https://github.com/biaochenxu... |
| 線性表(數(shù)組、鏈表、棧、隊(duì)列) | https://github.com/biaochenxu... |
| 實(shí)現(xiàn)一個(gè)前端路由,如何實(shí)現(xiàn)瀏覽器的前進(jìn)與后退 ?| https://github.com/biaochenxu... |
| 棧內(nèi)存與堆內(nèi)存 、淺拷貝與深拷貝 | https://github.com/biaochenxu... |
| 遞歸 | https://github.com/biaochenxu... |
| 非線性表(樹、堆) | https://github.com/biaochenxu... |
| 冒泡排序 | 精彩待續(xù) |
| 插入排序 | 精彩待續(xù) |
| 選擇排序 | 精彩待續(xù) |
| 歸并排序 | 精彩待續(xù) |
| 快速排序 | 精彩待續(xù) |
| 計(jì)數(shù)排序 | 精彩待續(xù) |
| 基數(shù)排序 | 精彩待續(xù) |
| 桶排序 | 精彩待續(xù) |
| 希爾排序 | 精彩待續(xù) |
| 堆排序 | 精彩待續(xù) |
| 十大經(jīng)典排序匯總 | 精彩待續(xù) |

如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤?,請?wù)必給予指正,十分感謝。
4. 最后

上個(gè)周六日,不小心看了盜墓筆記電視劇,沒忍住,還連看了兩部

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105695.html

相關(guān)文章

  • JavaScript 數(shù)據(jù)結(jié)構(gòu)算法之美 - 歸并排序、快速排序、希爾排序、堆排序

    摘要:之所以把歸并排序快速排序希爾排序堆排序放在一起比較,是因?yàn)樗鼈兊钠骄鶗r(shí)間復(fù)雜度都為。歸并排序是一種穩(wěn)定的排序方法。因此,快速排序并不穩(wěn)定。希爾排序思想先將整個(gè)待排序的記錄序列分割成為若干子序列。 showImg(https://segmentfault.com/img/bVbvpYZ?w=900&h=250); 1. 前言 算法為王。 想學(xué)好前端,先練好內(nèi)功,只有內(nèi)功深厚者,前端之路才...

    haitiancoder 評論0 收藏0
  • 阿里云服務(wù)器什么/阿里云服務(wù)器干嘛

    摘要:今天來一堂阿里云服務(wù)器的普及課程,和新手說一下阿里云服務(wù)器是什么。大型云服務(wù)器商家有專人維護(hù)服務(wù)器,運(yùn)行穩(wěn)定不易出錯(cuò)。今天來一堂阿里云服務(wù)器的普及課程,和新手說一下阿里云服務(wù)器是什么。 打個(gè)比方云服務(wù)器機(jī)房就是一座大樓,里面用隔斷分離出了很多小空間,每個(gè)小空間就是你租用的云服務(wù)器?,F(xiàn)在這個(gè)隔斷可以根據(jù)需要調(diào)整大小,比如你剛?cè)腭v的時(shí)候使用資源較少,后來隨著發(fā)展越來越大就可以付費(fèi)增加隔斷的面積。...

    roland_reed 評論0 收藏0
  • 主機(jī)下面那個(gè)鍵有什么用-主機(jī)上電源鍵下面那個(gè)鍵干嘛啊?

    摘要:主機(jī)上電源鍵下面那個(gè)鍵是干嘛用的啊電源按鈕又稱開關(guān)機(jī)鍵,另一個(gè)按鈕是復(fù)位鍵。系統(tǒng)失去反應(yīng)可按電源鍵幾秒后強(qiáng)制關(guān)機(jī)。主機(jī)上電源鍵下面那個(gè)鍵是干嘛用的啊?電源按鈕又稱開關(guān)機(jī)鍵,另一個(gè)按鈕是復(fù)位鍵。主機(jī)開機(jī)必須按一下電源開關(guān),關(guān)機(jī)可程序關(guān)機(jī)或點(diǎn)一下電源按鈕,也會(huì)關(guān)機(jī)。系統(tǒng)失去反應(yīng)可按電源鍵幾秒后強(qiáng)制關(guān)機(jī)。復(fù)位按鈕即電腦重啟鍵,按一下后電腦會(huì)由開機(jī)狀態(tài)直接重開機(jī),跳過關(guān)機(jī)過程。電腦主機(jī)下面一個(gè)小按鈕...

    firim 評論0 收藏0
  • JavaScript 數(shù)據(jù)結(jié)構(gòu)算法之美 - 棧內(nèi)存堆內(nèi)存 、淺拷貝深拷貝

    摘要:棧內(nèi)存與堆內(nèi)存淺拷貝與深拷貝,可以說是前端程序員的內(nèi)功,要知其然,知其所以然。棧內(nèi)存與堆內(nèi)存中的變量分為基本類型和引用類型。 showImg(https://segmentfault.com/img/bVbuvnj?w=900&h=250); 前言 想寫好前端,先練好內(nèi)功。 棧內(nèi)存與堆內(nèi)存 、淺拷貝與深拷貝,可以說是前端程序員的內(nèi)功,要知其然,知其所以然。 筆者寫的 JavaScrip...

    dailybird 評論0 收藏0
  • JavaScript 數(shù)據(jù)結(jié)構(gòu)算法之美 - 線性表(數(shù)組、棧、隊(duì)列、鏈表)

    摘要:每個(gè)線性表上的數(shù)據(jù)最多只有前和后兩個(gè)方向。數(shù)組鏈表隊(duì)列棧等就是線性表結(jié)構(gòu)。非線性表數(shù)據(jù)之間并不是簡單的前后關(guān)系。不包含任何元素的棧稱為空棧。移除棧頂?shù)脑?,同時(shí)返回被移除的元素。 showImg(https://segmentfault.com/img/bVbuvnj?w=900&h=250); 前言 基礎(chǔ)知識(shí)就像是一座大樓的地基,它決定了我們的技術(shù)高度。 我們應(yīng)該多掌握一些可移值的...

    kaka 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<