二叉樹總結(jié)

什么是二叉樹枣接?

引用自百度百科
在計(jì)算機(jī)科學(xué)中,二叉樹是每個(gè)節(jié)點(diǎn)最多有兩個(gè)子樹的樹結(jié)構(gòu)。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree),同樣的左右子樹也都是二叉樹.

前言

本文代碼實(shí)現(xiàn)為 C/C++彭沼,因?yàn)椴皇且粋€(gè)完整的講解文章,只是個(gè)人思路备埃,所以說思路講解可能有不足之處姓惑,有錯(cuò)誤請指出.

節(jié)點(diǎn)定義

使用單向鏈表的形式,只保存當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)和權(quán)值按脚,不保存父節(jié)點(diǎn).

typedef struct Node{
    int value;//權(quán)值于毙,根據(jù)實(shí)際情況而定,這里用數(shù)字
    Node *lChild;//左兒子節(jié)點(diǎn)
    Node *rChild;//右兒子節(jié)點(diǎn)
}BNode;

二叉樹的遍歷

二叉樹的遍歷分為三種:

  • 前序遍歷
    先遍歷當(dāng)前節(jié)點(diǎn)(根節(jié)點(diǎn))辅搬,然后遍歷左兒子節(jié)點(diǎn)唯沮,再遍歷右兒子節(jié)點(diǎn)
  • 中序遍歷
    先遍歷左兒子節(jié)點(diǎn),然后遍歷當(dāng)前節(jié)點(diǎn)(根節(jié)點(diǎn))堪遂,再遍歷右兒子節(jié)點(diǎn)
  • 后序遍歷
    先遍歷左兒子節(jié)點(diǎn)介蛉,然后遍歷右兒子節(jié)點(diǎn),再遍歷當(dāng)前節(jié)點(diǎn)(根節(jié)點(diǎn))

我們創(chuàng)建二叉樹的時(shí)候一般用的是遞歸的方法溶褪,但是二叉樹的遍歷可以有遞歸和非遞歸兩種方式.下面會(huì)分別給出二叉樹遍歷遞歸和非遞歸的思路和代碼.

PS:建議看懂思路后再看代碼實(shí)現(xiàn)币旧,然后手動(dòng)模擬一下,效果更佳.

前序遍歷

遞歸版:
先遍歷根節(jié)點(diǎn)猿妈,然后遍歷左子樹吹菱,再遍歷右子樹
非常經(jīng)典的遞歸思想,理解二叉樹的性質(zhì)和遞歸思想即可得出.

void preorderTraversal(BNode *rootNode) {
    if(rootNode != NULL) {
        printf("%d ", rootNode->value);
        preorderTraversal(rootNode->lChild);
        preorderTraversal(rootNode->rChild);
    }
}

非遞歸版:

使用棧來實(shí)現(xiàn)于游,因?yàn)?C++ 中有現(xiàn)成的庫,所以說就不手動(dòng)模擬棧了垫言,當(dāng)遍歷到一個(gè)節(jié)點(diǎn)的時(shí)候贰剥,先將此節(jié)點(diǎn)輸出,然后一直遍歷其左兒子筷频,依次循環(huán)蚌成,直到碰到葉子節(jié)點(diǎn),然后開始彈凛捏,也就是遞歸過程中的回溯担忧。

對于任一結(jié)點(diǎn)node:

  • 訪問結(jié)點(diǎn)node,并將結(jié)點(diǎn)node入棧;
  • 判斷結(jié)點(diǎn)node的左孩子是否為空
  • 若為空坯癣,則取棧頂結(jié)點(diǎn)并進(jìn)行出棧操作瓶盛,并將棧頂結(jié)點(diǎn)的右孩子置為當(dāng)前的結(jié)點(diǎn)node,循環(huán)至1
  • 若不為空,則將node的左孩子置為當(dāng)前的結(jié)點(diǎn)node;
  • 直到node為NULL并且棧為空惩猫,則遍歷結(jié)束芝硬。
void preorderTraversalNonrecursive(BNode *rootNode) {
    stack<BNode *>s;
    if (rootNode == NULL ) {
        return ;
    }
    BNode *tempNode = rootNode;
    while(!s.empty() || tempNode != NULL) {
        while(tempNode != NULL) {
            printf("%d ", tempNode->value);
            s.push(tempNode);
            tempNode = tempNode->lChild;
        }
        if (!s.empty()) {
            tempNode = s.top();
            s.pop();
            tempNode = tempNode->rChild;
        }
    }
}

中序遍歷

遞歸版:
先遍歷左子樹,然后遍歷根節(jié)點(diǎn)轧房,再遍歷右子樹

void inorderTraversal(BNode *rootNode) {
    if(rootNode != NULL) {
        inorderTraversal(rootNode->lChild);
        printf("%d ", rootNode->value);
        inorderTraversal(rootNode->rChild);
    }
}

非遞歸版:
和先序遍歷一樣的思想拌阴,因?yàn)橐仍L問左子樹,然后再訪問根節(jié)點(diǎn)(當(dāng)前節(jié)點(diǎn))奶镶,那么在棧彈出的時(shí)候進(jìn)行輸出即為所求.

對于任一結(jié)點(diǎn)node:

  • 若其左孩子不為空迟赃,則將node入棧并將node的左孩子置為當(dāng)前的node,然后對當(dāng)前結(jié)點(diǎn)P再進(jìn)行相同的處理纤壁;
  • 若其左孩子為空,則取棧頂元素并進(jìn)行出棧操作摄乒,訪問該棧頂結(jié)點(diǎn),然后將當(dāng)前的node置為棧頂結(jié)點(diǎn)的右孩子馍佑;
  • 直到node為NULL并且棧為空則遍歷結(jié)束
void inorderTraversalNonrecursive(BNode *rootNode) {
    stack<BNode *>s;
    if (rootNode == NULL ) {
        return ;
    }
    BNode *tempNode = rootNode;
    while(!s.empty() || tempNode != NULL) {
        while(tempNode != NULL) {
            s.push(tempNode);
            tempNode = tempNode->lChild;
        }
        if (!s.empty()) {
            tempNode = s.top();
            s.pop();
            printf("%d ", tempNode->value);
            tempNode = tempNode->rChild;
        }
    }
}

后序遍歷

遞歸版:
先遍歷左子樹梨水,然后遍歷右子樹,再遍歷根節(jié)點(diǎn)

void postorderTraversal(BNode *rootNode) {
    if(rootNode != NULL) {
        postorderTraversal(rootNode->lChild);
        postorderTraversal(rootNode->rChild);
        printf("%d ", rootNode->value);
    }
}

非遞歸版:
后序遍歷的非遞歸版和先序遍歷疫诽、中序遍歷不一樣,這里我用兩個(gè)棧來實(shí)現(xiàn)奇徒,一個(gè)棧來保存遍歷節(jié)點(diǎn)并不斷的進(jìn)行彈出雏亚,一個(gè)棧來保存節(jié)點(diǎn)的遍歷順序,最后遍歷第二個(gè)棧.

void postorderTraversalNonrecursive(BNode *rootNode) {
    stack<BNode *>s1;
    stack<BNode *>s2;
    if (rootNode == NULL ) {
        return ;
    }
    s1.push(rootNode);
    while(!s1.empty()) {
        BNode *tempNode = s1.top();
        s1.pop();
        s2.push(tempNode);
        if (tempNode->lChild) {
            s1.push(tempNode->lChild);
        }
        if (tempNode->rChild) {
            s1.push(tempNode->rChild);
        }
    }
    while(!s2.empty()) {
        printf("%d ", s2.top()->value);
        s2.pop();
    }
}

分層遍歷二叉樹

即每次輸出二叉樹的一層摩钙,例如:

實(shí)現(xiàn)思路:廣度優(yōu)先遍歷(BFS)罢低,使用隊(duì)列來實(shí)現(xiàn),每次遍歷當(dāng)前節(jié)點(diǎn)的左右兒子節(jié)點(diǎn)胖笛,并將其加入隊(duì)列中网持,然后進(jìn)行隊(duì)列的彈出直到隊(duì)列為空.

void levelTraversal(BNode *rootNode) {
    queue<BNode *>q;
    q.push(rootNode);
    while(!q.empty()) {
        BNode *tempNode = q.front();
        q.pop();
        printf("%d ", tempNode->value);
        if (tempNode->lChild) {
            q.push(tempNode->lChild);
        }
        if (tempNode->rChild) {
            q.push(tempNode->rChild);
        }
    }
}

S型打印二叉樹

這里我使用的是隊(duì)列 + 棧來實(shí)現(xiàn)的,隊(duì)列存儲(chǔ)當(dāng)前遍歷的節(jié)點(diǎn)的序列长踊,棧中存儲(chǔ)下一層遍歷的節(jié)點(diǎn)順序功舀,使用一個(gè) level 來判斷遍歷方向

void STraversal(BNode *rootNode) {
    queue<BNode *>q;
    stack<BNode *>s;
    int level = 1;//根節(jié)點(diǎn)為第一層
    q.push(rootNode);
    while(!q.empty()){
        BNode *temp;
        while(!q.empty()){
            temp = q.front();
            printf("%d ", temp->value);
            if (level % 2) {//下一層要從左到右遍歷
                if (temp->rChild != NULL) {
                    s.push(temp->rChild);
                }
                if (temp->lChild != NULL) {
                    s.push(temp->lChild);
                }
            } else {//下一層要從右到左遍歷
                if (temp->lChild != NULL) {
                    s.push(temp->lChild);
                }
                if (temp->rChild != NULL) {
                    s.push(temp->rChild);
                }
            }
            q.pop();
        }
        while(!s.empty()){
            temp = s.top();
            //將下一層節(jié)點(diǎn)的按照遍歷順序加入隊(duì)列中
            q.push(temp);
            s.pop();
        }
        level++;
    }
}

二叉樹深度

一棵空樹的深度為0,只有根節(jié)點(diǎn)的數(shù)的深度為1身弊,所以說一個(gè)數(shù)的深度 = max(左子樹的深度辟汰,右子樹的深度) + 1(當(dāng)前節(jié)點(diǎn))列敲,使用遞歸來求.

int findDeepOfTree(BNode *rootNode){
    if(rootNode == NULL){
        return 0;
    }
    return max(findDeepOfTree(rootNode->lChild), findDeepOfTree(rootNode->rChild)) + 1;
}

樹的寬度

樹的寬度即是節(jié)點(diǎn)最多的一層的節(jié)點(diǎn)數(shù),根據(jù)前面分層遍歷二叉樹的原理莉擒,每次從隊(duì)列中取出一層的節(jié)點(diǎn)酿炸,將其子節(jié)點(diǎn)加入隊(duì)列,然后查看節(jié)點(diǎn)數(shù)涨冀,即隊(duì)列的大小.

int findWidthOfTree(BNode *rootNode){
    queue<BNode *>q;
    q.push(rootNode);
    int ansWidth = 1;
    while(!q.empty()) {
        for(int i = 0; i < q.size(); i++) {
            BNode *tempNode = q.front();
            q.pop();
            if (tempNode->lChild) {
                q.push(tempNode->lChild);
            }
            if (tempNode->rChild) {
                q.push(tempNode->rChild);
            }
        }
        ansWidth = max(ansWidth, (int)q.size());
    }
    return ansWidth;
}

求葉子節(jié)點(diǎn)數(shù)

葉子節(jié)點(diǎn)填硕,即不含子節(jié)點(diǎn)的節(jié)點(diǎn),當(dāng)一個(gè)節(jié)點(diǎn)的左右兒子皆為空的時(shí)候鹿鳖,此節(jié)點(diǎn)為葉子節(jié)點(diǎn)扁眯,所以可以得出:樹的葉子節(jié)點(diǎn)數(shù) = 左子樹的葉子節(jié)點(diǎn)數(shù) + 右子樹的葉子節(jié)點(diǎn)數(shù).

int findNumOfLeafNode(BNode *rootNode){
    if(rootNode == NULL) {
        return 0;
    }
    if(rootNode->lChild == NULL && rootNode->rChild == NULL) {
        return 1;
    }
    return findNumOfLeafNode(rootNode->lChild) + findNumOfLeafNode(rootNode->rChild);
}

求樹的一層有多少節(jié)點(diǎn)

根節(jié)點(diǎn)某層的節(jié)點(diǎn)數(shù) = 左子樹中某層的節(jié)點(diǎn)數(shù) + 右子樹中某層的節(jié)點(diǎn)數(shù)

設(shè)置一個(gè)層數(shù)變量 level,在遞歸過程中翅帜,通過 level 的減小模擬下降的過程姻檀,當(dāng)level = 1的時(shí)候說明到達(dá)了我們要找的那一層,那么返回當(dāng)前節(jié)點(diǎn)數(shù)涝滴,也就是1.

int findNumOfNodeOnLevel(BNode *rootNode, int level) {
    if (level == 0 || rootNode == NULL) {
        return 0;
    }
    if(level == 1){
        return 1;
    }
    return findNumOfNodeOnLevel(rootNode->lChild, level - 1) + findNumOfNodeOnLevel(rootNode->rChild, level - 1);
}

求樹的直徑(樹上兩個(gè)節(jié)點(diǎn)間的最大距離)

這里有兩種方案:

方案一:

直接遍歷每個(gè)點(diǎn)绣版,模擬當(dāng)前點(diǎn)為兩個(gè)節(jié)點(diǎn)路徑的轉(zhuǎn)折點(diǎn)時(shí)的最大距離,那么也就是當(dāng)前節(jié)點(diǎn)的左子樹深度 + 右子樹深度歼疮,然后取最大值

時(shí)間復(fù)雜度: O(n^2)

int findDiameterOfTree1(BNode *rootNode) {
    if(rootNode == NULL) {
        return 0;
    }
    return max(max(findDiameterOfTree1(rootNode->lChild), findDiameterOfTree1(rootNode->rChild)), findDeepOfTree(rootNode->lChild) + findDeepOfTree(rootNode->rChild));
}

方案二:

在求子樹深度的時(shí)候就將最長距離求出

int findMaxDeep(BNode *rootNode, int &ans) {
    if (rootNode == NULL) {
        return 0;
    }
    int leftDeep = findMaxDeep(rootNode->lChild, ans);
    int rightDeep = findMaxDeep(rootNode->rChild, ans);
    ans = max(ans, leftDeep + rightDeep);
    return max(leftDeep, rightDeep) + 1;
}
int findDiameterOfTree2(BNode *rootNode) {
    int ans = 0;
    findMaxDeep(rootNode, ans);
    return ans;
}

求一個(gè)節(jié)點(diǎn)到根節(jié)點(diǎn)的路徑

定義一個(gè)從某節(jié)點(diǎn)到根節(jié)點(diǎn)的棧韩脏,這里使用 vector 來實(shí)現(xiàn),具體步驟:

  • 將當(dāng)前節(jié)點(diǎn)壓入棧中
  • 尋找當(dāng)前節(jié)點(diǎn)左子樹是否含有要尋找節(jié)點(diǎn)(遞歸進(jìn)行)
    • 如果有杭朱,棧中存放的就是路徑
    • 如果沒有弧械,再尋找右子樹是否含有要尋找節(jié)點(diǎn)
      • 如果有刃唐,棧中存放的就是路徑
      • 如果都沒有唁桩,彈出當(dāng)前節(jié)點(diǎn)耸棒,在遍歷棧中的上一個(gè)節(jié)點(diǎn)
bool findPathFromNodetoRoot(BNode *rootNode, BNode *node, vector<BNode *> &path) {
    if (rootNode == NULL || node == NULL) {
        return false;
    }
    path.push_back(rootNode);
    if (rootNode == node) {
        return true;
    }
    bool isFind = findPathFromNodetoRoot(rootNode->lChild, node, path);
    if (isFind == false) {
        isFind = findPathFromNodetoRoot(rootNode->rChild, node, path);
    }
    if (isFind == false) {
        path.pop_back();
    }
    return isFind;
}

求兩個(gè)節(jié)點(diǎn)的最近公共祖先

如果當(dāng)前遍歷到了一個(gè)根節(jié)點(diǎn)单山,那么檢查我們要查找的兩個(gè)節(jié)點(diǎn)在當(dāng)前節(jié)點(diǎn)的哪個(gè)子樹中米奸,會(huì)有三種情況:

  • 都在左子樹
  • 都在右子樹
  • 一個(gè)在左子樹悴晰,一個(gè)在右子樹

情況一和情況二的時(shí)候我們需要返回節(jié)點(diǎn)所在子樹的遍歷結(jié)果铡溪,情況三的時(shí)候說明我們已經(jīng)找到了最近公共祖先(不明白的最好手動(dòng)模擬一下)泪喊。

BNode * findCommonNodeOfTwoNode(BNode *rootNode, BNode *node1, BNode *node2) {
    if (rootNode == NULL || node1 == NULL || node2 == NULL) {
        return NULL;
    }
    if (node1 == rootNode || node2 == rootNode) {
        return rootNode;
    }
    BNode *leftLCANode = findCommonNodeOfTwoNode(rootNode->lChild, node1, node2);//檢查左子樹
    BNode *rightLCANode = findCommonNodeOfTwoNode(rootNode->rChild, node1, node2);//檢查右子樹
    if (leftLCANode != NULL && rightLCANode != NULL) {//一個(gè)在左一個(gè)在右袒啼,找到目標(biāo)
        return rootNode;
    }
    if (leftLCANode == NULL) {//全在右子樹
        return rightLCANode;
    } else {//全在左子樹
        return leftLCANode;
    }
}

還有一種方案就是將兩個(gè)節(jié)點(diǎn)到根節(jié)點(diǎn)的路徑都求出蚓再,然后開始對比,如果遇到第一個(gè)相同的節(jié)點(diǎn)即為所求赦邻,這個(gè)留給讀者自己實(shí)現(xiàn)吧.

求兩個(gè)節(jié)點(diǎn)間的路徑

分別將兩個(gè)節(jié)點(diǎn)到根節(jié)點(diǎn)的路徑求出惶洲,然后對根節(jié)點(diǎn)到兩個(gè)節(jié)點(diǎn)的最近公共祖先節(jié)點(diǎn)的路徑進(jìn)行去重即可.

void findPathBetweenTwoNode(BNode *rootNode, BNode *node1, BNode *node2, vector<BNode *> &path){
    vector<BNode *>path1;
    findPathFromNodetoRoot(rootNode, node1, path1);
    vector<BNode *>path2;
    findPathFromNodetoRoot(rootNode, node2, path2);

    vector<BNode *>::iterator it1 = path1.begin();
    vector<BNode *>::iterator it2 = path2.begin();
    BNode *LCANode;
    int cnt = 0;
    //去重
    while(it1 != path1.end() && it2 != path2.end()) {
        if (*it1 == *it2) {
            LCANode = *it1;
            cnt++;
        }
        it1++;
        it2++;
    }
    for(int i = cnt - 1; i < path1.size(); i++) {
        path.push_back(path1[i]);
    }
    reverse(path.begin(), path.end());
    for(int i = cnt; i < path2.size(); i++) {
        path.push_back(path2[i]);
    }
}

翻轉(zhuǎn)二叉樹

這里穿插一個(gè)小故事恬吕,2015 年 6 月 10 日铐料,Homebrew 的作者 Max Howell 在 twitter 上發(fā)表了如下一內(nèi)容:

Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.

大概意思就是:他在應(yīng)聘谷歌的時(shí)候被面試官說:雖然有90%的人在用你寫的軟件钠惩,但是你不會(huì)翻轉(zhuǎn)二叉樹篓跛,所以說我們不會(huì)錄用你.
因?yàn)?Max Howell 的影響力坦刀,所以這件事情一下子廣為流傳.

回到正題:翻轉(zhuǎn)二叉樹,即是二叉樹的鏡像林艘,也就是將二叉樹的左右子樹對調(diào)狐援,這里有兩種方案;

遞歸版:

void swapTree(BNode *&root){
    BNode *tmp = root->lChild;
    root->lChild = root->rChild;
    root->rChild = tmp;
}
void turnBTree(BNode *rootNode) {
    if (rootNode == NULL) {
        return ;
    }
    turnBTree(rootNode->lChild);
    turnBTree(rootNode->rChild);
    swapTree(rootNode);
}

非遞歸版:

void invertBinaryTreeNonrecursive2(BNode *root) {
    if(root == NULL){
        return ;
    }
    stack<BNode *>s;
    s.push(root);
    while(!s.empty())
    {
        BNode *tmp = s.top();
        s.pop();
        swapTree(tmp);
        if(tmp->lChild){
            s.push(tmp->lChild);
        }
        if(tmp->rChild){
            s.push(tmp->rChild);
        }
    }
}

判斷完全二叉樹

完全二叉樹即葉節(jié)點(diǎn)只能出現(xiàn)在最下層和次下層咕村,并且最下面一層的結(jié)點(diǎn)都集中在該層最左邊的若干位置的二叉樹

所以可得出判斷的兩個(gè)條件:

  • 如果某個(gè)節(jié)點(diǎn)的右子樹不為空懈涛,則它的左子樹必須不為空
  • 如果某個(gè)節(jié)點(diǎn)的右子樹為空批钠,則排在它后面的節(jié)點(diǎn)必須沒有孩子節(jié)點(diǎn)

所以我們可以設(shè)置一個(gè)標(biāo)志位flag得封,當(dāng)子樹滿足完全二叉樹時(shí)忙上,設(shè)置flag=YES疫粥。當(dāng)flag=YES而節(jié)點(diǎn)又破壞了完全二叉樹的條件,那么它就不是完全二叉樹项秉。

bool checkIsCompleteBTree(BNode *rootNode) {
    if (rootNode == NULL) {
        return true;
    }
    queue<BNode *>q;
    q.push(rootNode);
    bool flag = false;
    while(!q.empty()){
        BNode *tempNode = q.front();
        q.pop();
        if (tempNode->lChild == NULL && tempNode->rChild != NULL) {
            return false;
        }
        if (tempNode->lChild == NULL && tempNode->rChild == NULL) {
            flag = true;
        }
        if (flag == true && tempNode->lChild != NULL && tempNode->rChild != NULL) {
            return false;
        }
        if (tempNode->lChild != NULL) {
            q.push(tempNode->lChild);
        }
        if (tempNode->rChild != NULL) {
            q.push(tempNode->rChild);
        }
    }
    return flag;
}

判斷平衡二叉樹

又被稱為AVL樹(有別于AVL算法),且具有以下性質(zhì):它是一 棵空樹或它的左右兩個(gè)子樹的高度差的絕對值不超過1岁诉,并且左右兩個(gè)子樹都是一棵平衡二叉樹.
遞歸檢查每個(gè)節(jié)點(diǎn)的左右子樹的高度之差是否符合要求跋选,返回即可.

bool checkLR(BNode *rootNode, int &height) {
    if (rootNode == NULL) {
        return true;
    }
    if (rootNode->value > rootNode->rChild->value || rootNode->value < rootNode->lChild->value) {
        return false;
    }
    bool lAns = checkLR(rootNode->lChild, height);
    int lHeight = height;
    bool rAns = checkLR(rootNode->rChild, height);
    int rHeight = height;
    height = max(lHeight, rHeight) + 1;
    if (lAns == true && rAns == true && abs(lHeight - rHeight) <= 1) {
        return true;
    } else {
        return false;
    }
}
bool checkBalanceBTree(BNode *rootNode) {
    int height = 0;
    return checkLR(rootNode, height);
}

參考文章

二叉樹-你必須要懂属划!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末同眯,一起剝皮案震驚了整個(gè)濱河市须蜗,隨后出現(xiàn)的幾起案子目溉,更是在濱河造成了極大的恐慌,老刑警劉巖柿估,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秫舌,死亡現(xiàn)場離奇詭異足陨,居然都是意外死亡墨缘,警方通過查閱死者的電腦和手機(jī)镊讼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門狠毯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來褥芒,“玉大人锰扶,你說我怎么就攤上這事坷牛。” “怎么了颜及?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵讯蒲,是天一觀的道長墨林。 經(jīng)常有香客問我旭等,道長搔耕,這世上最難降的妖魔是什么痰娱? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任惭墓,我火速辦了婚禮而姐,結(jié)果婚禮上拴念,老公的妹妹穿的比我還像新娘政鼠。我一直安慰自己,他們只是感情好万搔,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酗捌,像睡著了一般胖缤。 火紅的嫁衣襯著肌膚如雪狗唉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天综膀,我揣著相機(jī)與錄音剧劝,去河邊找鬼讥此。 笑死谣妻,一個(gè)胖子當(dāng)著我的面吹牛萄喳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹋半,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼他巨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了减江?” 一聲冷哼從身側(cè)響起染突,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辈灼,沒想到半個(gè)月后份企,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡司志,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年吧史,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡阎毅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碳柱,到底是詐尸還是另有隱情剥悟,我是刑警寧澤毁枯,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布娱节,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏带饱。R本人自食惡果不足惜捏鱼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一问潭、第九天 我趴在偏房一處隱蔽的房頂上張望址芯。 院中可真熱鬧,春花似錦拓颓、人聲如沸场航。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春隙券,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓侥衬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親共耍。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 樹的概述 樹是一種非常常用的數(shù)據(jù)結(jié)構(gòu),樹與前面介紹的線性表归露,棧疆液,隊(duì)列等線性結(jié)構(gòu)不同堕油,樹是一種非線性結(jié)構(gòu) 1.樹的定...
    Jack921閱讀 4,442評(píng)論 1 31
  • 四、樹與二叉樹 1. 二叉樹的順序存儲(chǔ)結(jié)構(gòu) 二叉樹的順序存儲(chǔ)就是用數(shù)組存儲(chǔ)二叉樹被廓。二叉樹的每個(gè)結(jié)點(diǎn)在順序存儲(chǔ)中都有...
    MinoyJet閱讀 1,512評(píng)論 0 7
  • 數(shù)據(jù)結(jié)構(gòu)和算法--二叉樹的實(shí)現(xiàn) 幾種二叉樹 1、二叉樹 和普通的樹相比豆拨,二叉樹有如下特點(diǎn): 每個(gè)結(jié)點(diǎn)最多只有兩棵子...
    sunhaiyu閱讀 6,433評(píng)論 0 14
  • 一直以來直奋,我都很少使用也避免使用到樹和圖,總覺得它們神秘而又復(fù)雜,但是樹在一些運(yùn)算和查找中也不可避免的要使用到施禾,那...
    24K男閱讀 6,737評(píng)論 5 14
  • 基于樹實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)脚线,具有兩個(gè)核心特征: 邏輯結(jié)構(gòu):數(shù)據(jù)元素之間具有層次關(guān)系; 數(shù)據(jù)運(yùn)算:操作方法具有Log級(jí)的平...
    yhthu閱讀 4,255評(píng)論 1 5