数据结构与算法笔记三 - 二叉树

#include <iostream>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <sstream>

using namespace std;

struct BinaryNode {
    int data;
    BinaryNode * left;
    BinaryNode * right;
};


class BinaryTree {
public:
    static int preValue;

public:

    // 用递归和栈的方法遍历二叉树
    void preOrderUnRecur(BinaryNode *);

    static void preOrderStack(BinaryNode *);

    void inOrderUnRecur(BinaryNode *);

    static void inOrderStack(BinaryNode *);

    static void postOrderUnRecur(BinaryNode *);

    static void postOrderStack(BinaryNode *);

    // 宽度优先遍历(层序遍历):每一层由左至右遍历
    static void levelOrder(BinaryNode *);

    // 求二叉树的最大宽度
    static int maxLevelWidth(BinaryNode *);

    // 相比于上一个方法,减少了节点在两个队列之间的复制
    static int maxLevelWidth2(BinaryNode *);

    // 判断是否为搜索二叉树(中序遍历升序排列)
    static bool isSearchBT(BinaryNode *);

    // 判断是否为完全二叉树(左满)
    static bool isCompleteBT(BinaryNode *);

    // 判断是否为满二叉树(第 i 层的节点数为 2 ^ i (i = 0, 1, 2...))
    static bool isFullBT(BinaryNode *);

    // static bool isFullBTByLevel(BinaryNode *);

    // 判断是否为平衡二叉树(左右树高度差不超过1)
    static int isBalanceBT(BinaryNode *);

    // 寻找树中两个节点的最低公共祖先(lowest ancestor)
    static BinaryNode *lowestAncestor(BinaryNode *, BinaryNode *, BinaryNode *);

    static BinaryNode *lowerAncestorByHashMap(BinaryNode *, BinaryNode *, BinaryNode *);

    // 返回 node 的后继节点(中序遍历)
    static BinaryNode *getSuccessorNode(BinaryNode *, BinaryNode *);

    // 返回 node 的前驱节点,若 node 为根节点,返回空
    static BinaryNode *getPredecessorNode(BinaryNode *, BinaryNode *);

    // 二叉树的序列化及反序列化,也可以用于复制二叉树
    string serialization(BinaryNode *);

    BinaryNode *reConstruct(string &);

    BinaryNode *reConstruct(queue<string> &);

    // 纸条折叠 n 次折痕顺序:
    // 头节点为凹,左节点为凹,右节点为凸的二叉树的中序遍历
    void paperFolding(int);
    void printPaperFolding(int, int, bool);

};

int BinaryTree::preValue = INT_MIN;

void BinaryTree::preOrderUnRecur(BinaryNode * loot) {
    if (loot == nullptr) {
        return;
    }

    cout << loot->data << ' ';

    preOrderUnRecur(loot->left);
    preOrderUnRecur(loot->right);
}

void BinaryTree::inOrderUnRecur(BinaryNode * loot) {
    if (loot == nullptr) {
        return;
    }

    inOrderUnRecur(loot->left);
    cout << loot->data << ' ';
    inOrderUnRecur(loot->right);
}

void BinaryTree::postOrderUnRecur(BinaryNode * loot) {
    if (loot == nullptr) {
        return;
    }

    postOrderUnRecur(loot->left);
    postOrderUnRecur(loot->right);
    cout << loot->data << ' ';
}

void BinaryTree::preOrderStack(BinaryNode * loot) {
    if (loot == nullptr) return;

    cout << "Preorder with stack: " << endl;
    stack<BinaryNode *> binaryNodeStack;

    binaryNodeStack.push(loot);

    // 栈非空时,弹出节点的右、左孩子依次进栈进栈
    while (!binaryNodeStack.empty()) {
        loot = binaryNodeStack.top();
        binaryNodeStack.pop();

        cout << loot->data << ' ';

        if (loot->right) binaryNodeStack.push(loot->right);
        if (loot->left) binaryNodeStack.push(loot->left);
    }

    cout << endl;
}

void BinaryTree::inOrderStack(BinaryNode * loot) {
    if (loot == nullptr) return;

    cout << "Inorder with stack: " << endl;
    stack<BinaryNode *> binaryNodeStack;

    // 栈非空时,弹出节点的整个左边界依次进栈,直至为空
    while (!binaryNodeStack.empty() || loot != nullptr) {
        if (loot != nullptr) {
            binaryNodeStack.push(loot);
            loot = loot->left;
        } else {
            loot = binaryNodeStack.top();
            cout << loot->data << ' ';
            binaryNodeStack.pop();
            loot = loot->right;
        }
    }

    cout << endl;
}

void BinaryTree::postOrderStack(BinaryNode * loot) {
    if (loot == nullptr) return;

    cout << "Post-order with stack: " << endl;
    stack<BinaryNode *> binaryNodeStack1;
    stack<BinaryNode *> binaryNodeStack2;

    binaryNodeStack1.push(loot);

    // 栈非空时,弹出节点进入另一个栈中,弹出节点的右、左节点依次进本栈
    while (!binaryNodeStack1.empty()) {
        loot = binaryNodeStack1.top();
        binaryNodeStack2.push(loot);
        binaryNodeStack1.pop();

        if (loot->left != nullptr) binaryNodeStack1.push(loot->left);
        if (loot->right != nullptr) binaryNodeStack1.push(loot->right);
    }

    while (!binaryNodeStack2.empty()) {
        cout << binaryNodeStack2.top()->data << ' ';
        binaryNodeStack2.pop();
    }

    cout << endl;
}

void BinaryTree::levelOrder(BinaryNode * loot) {
    // 弹出节点的左右孩子依次放入队列中
    queue<BinaryNode *> binaryNodeQueue;
    binaryNodeQueue.push(loot);

    while(!binaryNodeQueue.empty()) {
        loot = binaryNodeQueue.front();
        binaryNodeQueue.pop();

        cout << loot->data << ' ';

        if (loot->left) binaryNodeQueue.push(loot->left);
        if (loot->right) binaryNodeQueue.push(loot->right);
    }

    cout << endl;
}

int BinaryTree::maxLevelWidth(BinaryNode * loot) {
    int max = 1;
    queue<BinaryNode *> binaryNodeQueue1;
    queue<BinaryNode *> binaryNodeQueue2;

    binaryNodeQueue1.push(loot);

    while (!binaryNodeQueue1.empty() || !binaryNodeQueue2.empty()) {
        loot = binaryNodeQueue1.front();
        binaryNodeQueue1.pop();

        if (loot->left != nullptr) binaryNodeQueue2.push(loot->left);
        if (loot->right != nullptr) binaryNodeQueue2.push(loot->right);


        if (binaryNodeQueue1.empty()) {
            int count = 0;
            while (!binaryNodeQueue2.empty()) {
                loot = binaryNodeQueue2.front();
                binaryNodeQueue2.pop();
                binaryNodeQueue1.push(loot);
                ++count;
            }
            max = max >= count ? max : count;
        }
    }

    return max;
}


int BinaryTree::maxLevelWidth2(BinaryNode * loot) {
    if (loot == nullptr) return -1;
    int max = 1;
    queue<BinaryNode *> queue1;
    queue<BinaryNode *> queue2;
    queue1.push(loot);

    while (!queue1.empty() || !queue2.empty()) {
        int count = 0;
        while (!queue1.empty()) {
            loot = queue1.front();
            queue1.pop();
            if (loot->left) queue2.push(loot->left);
            if (loot->right) queue2.push(loot->right);
            ++count;
            max = max > count ? max : count;
        }
        while (!queue2.empty()) {
            loot = queue2.front();
            queue2.pop();
            if (loot->left) queue1.push(loot->left);
            if (loot->right) queue1.push(loot->right);
            ++count;
            max = max > count ? max : count;
        }
    }
    return max;
}

bool BinaryTree::isSearchBT(BinaryNode * loot) {
    if (loot == nullptr) return true;

    bool isLeft = isSearchBT(loot->left);

    if (!isLeft) return false;
    if (loot->data < preValue) {
        return false;
    } else {
        preValue = loot->data;
    }

    bool isRight = isSearchBT(loot->right);

    return isRight;
}

bool BinaryTree::isCompleteBT(BinaryNode * loot) {
    // 层序遍历,不是完全二叉树有两种情况
    // 1、一个节点有右孩子却没有左孩子
    // 2、层序排列中前一节点是叶节点而后一节点非叶子节点
    queue<BinaryNode *> binaryNodeQueue;
    binaryNodeQueue.push(loot);
    // 同层中上一节点是否为叶子节点
    bool isLeaf = false;

    while (!binaryNodeQueue.empty()) {
        loot = binaryNodeQueue.front();
        binaryNodeQueue.pop();

        if (loot->left != nullptr) binaryNodeQueue.push(loot->left);
        if (loot->right != nullptr) binaryNodeQueue.push(loot->right);

        if ((loot->left == nullptr && loot->right != nullptr)) return false;

        if (isLeaf && (loot->left != nullptr || loot->right != nullptr)) return false;

        if (loot->left == nullptr && loot->left == nullptr) isLeaf = true;
    }

    return true;
}

bool BinaryTree::isFullBT(BinaryNode * loot) {
    // 与求最大宽度方法类似,要注意边界条件和深度递增时机
    queue<BinaryNode *> binaryNodeQueue1;
    queue<BinaryNode *> binaryNodeQueue2;

    binaryNodeQueue1.push(loot);

    int height = 0;
    bool res = true;

    while (!binaryNodeQueue1.empty() || !binaryNodeQueue2.empty()) {
        loot = binaryNodeQueue1.front();
        binaryNodeQueue1.pop();

        if (loot->left != nullptr) binaryNodeQueue2.push(loot->left);
        if (loot->right != nullptr) binaryNodeQueue2.push(loot->right);

        int leafNum = 0;
        if (binaryNodeQueue1.empty() && !binaryNodeQueue2.empty()) {
            while (!binaryNodeQueue2.empty()) {
                loot = binaryNodeQueue2.front();
                binaryNodeQueue2.pop();
                binaryNodeQueue1.push(loot);
                ++leafNum;
            }
            ++height;
            // cout << leafNum << ' ' << height << endl;
            if (leafNum != 1 << height) {
                res = false;
                break;
            }
        }
    }

    return res;
}

/*
bool BinaryTree::isFullBTByLevel(BinaryNode * loot) {
    // 层序遍历,不是满二叉树有三种情况
    // 1、一个节点有且仅有一个孩子
    // 2、层序排列中前一节点是叶节点而后一节点非叶子节点
    // 3、前一节点非叶子节点而后一节点是叶子节点
    queue<BinaryNode *> binaryNodeQueue;
    binaryNodeQueue.push(loot);
    // 该节点是否为叶子节点
    bool isLeafPrev = false, isLeafCur = false;
    bool res = true;

    while (!binaryNodeQueue.empty()) {
        loot = binaryNodeQueue.front();
        binaryNodeQueue.pop();

        if (loot->left != nullptr) binaryNodeQueue.push(loot->left);
        if (loot->right != nullptr) binaryNodeQueue.push(loot->right);

        if ((loot->left != nullptr ^ loot->right != nullptr)) {
            res = false;
            break;
        }

        if (loot->left == nullptr && loot->left == nullptr) isLeafCur = true;
        if (isLeafCur ^ isLeafPrev) {
            res = false;
            break;
        }

        isLeafPrev = isLeafCur;
    }

    return res;
}
*/

int BinaryTree::isBalanceBT(BinaryNode * loot) {
    if (loot == nullptr) return 0;

    int left = isBalanceBT(loot->left);

    int right = isBalanceBT(loot->right);

    int height = left > right ? (left + 1) : (right + 1);
    int diff = left - right;
    diff = diff > 0 ? diff : -diff;
    if (left < 0 || right < 0 || diff > 1) height = -1;
    return height;
}

BinaryNode * BinaryTree::lowestAncestor(BinaryNode * loot, BinaryNode * node1,
                                        BinaryNode * node2) {
    if (loot == nullptr || loot == node1 || loot == node2) return loot;

    BinaryNode * left = lowestAncestor(loot, node1, node2);
    BinaryNode * right = lowestAncestor(loot, node1, node2);

    if (left != nullptr && right != nullptr) return loot;

    return left != nullptr ? left : right;
}

void createFatherMap(BinaryNode * loot, map<BinaryNode *, BinaryNode *> * fatherMap) {
    // 先序遍历建立fatherMap
    if (loot == nullptr) return;

    if (loot->left != nullptr) {
        fatherMap->insert(pair<BinaryNode *, BinaryNode *>(loot->left, loot));
    }
    if (loot->right != nullptr) {
        fatherMap->insert(pair<BinaryNode *, BinaryNode *>(loot->right, loot));
    }

    createFatherMap(loot->left, fatherMap);
    createFatherMap(loot->right, fatherMap);
}

BinaryNode * BinaryTree::lowerAncestorByHashMap(BinaryNode * loot,
                                                BinaryNode * node1, BinaryNode * node2) {
    // 不加这一行也行,加了之后 node1、node2 中存在 loot 时,可减少计算量
    if (node1 == loot || node2 == loot) return loot;

    // fatherMap存储每个节点及其父节点,loot 的父节点设置为 loot
    map<BinaryNode *, BinaryNode *> fatherMap;
    fatherMap.insert(pair<BinaryNode *, BinaryNode *>(loot, loot));
    createFatherMap(loot, &fatherMap);

    // fatherSet 存储 node1 及其所有祖先节点
    set<BinaryNode *> fatherSet;
    BinaryNode * cur = node1;
    fatherSet.insert(node1);
    while (cur != fatherMap[cur]) {
        cur = fatherMap[cur];
        fatherSet.insert(cur);
    }

    // 在 fatherSet 中依次寻找 node2 及其祖先节点
    cur = node2;
    // 该边界条件会漏掉 loot,因此需要 if (cur == loot) return loot; 这一行代码
    // 这一行代码可以写的原因是在二叉树中任意两个节点都会有共同祖先
    while (cur !=  fatherMap[cur]) {
        auto index = fatherSet.find(cur);
        if (index != fatherSet.end()) {
            return *index;
        }
        cur = fatherMap[cur];
    }

    if (cur == loot) return loot;

    return nullptr;
}

BinaryNode *BinaryTree::getSuccessorNode(BinaryNode * loot, BinaryNode * node) {
    if (loot == nullptr || node == nullptr) return nullptr;

    stack<BinaryNode *> binaryNodeStack;
    queue<BinaryNode *> binaryNodeQueue;

    while (!binaryNodeStack.empty() || loot) {
        if (loot != nullptr) {
            binaryNodeStack.push(loot);
            loot = loot->left;
        } else {
            loot = binaryNodeStack.top();
            binaryNodeStack.pop();
            binaryNodeQueue.push(loot);
            loot = loot->right;
        }
    }

    while (!binaryNodeQueue.empty()) {
        loot = binaryNodeQueue.front();
        binaryNodeQueue.pop();
        if (loot == node) {
            return binaryNodeQueue.front();
        }
    }
    return nullptr;
}

BinaryNode *BinaryTree::getPredecessorNode(BinaryNode * loot, BinaryNode * node) {
    if (loot == nullptr || node == nullptr) return nullptr;

    stack<BinaryNode *> binaryNodeStack1;
    stack<BinaryNode *> binaryNodeStack2;

    while (!binaryNodeStack1.empty() || loot) {
        if (loot != nullptr) {
            binaryNodeStack1.push(loot);
            loot = loot->left;
        } else {
            loot = binaryNodeStack1.top();
            binaryNodeStack1.pop();
            binaryNodeStack2.push(loot);
            loot = loot->right;
        }
    }

    while (!binaryNodeStack2.empty()) {
        loot = binaryNodeStack2.top();
        binaryNodeStack2.pop();
        if (loot == node) {
            return binaryNodeStack2.top();
        }
    }

    return nullptr;
}

string BinaryTree::serialization(BinaryNode * loot) {
    if (loot == nullptr) return "#_";

    string res = to_string(loot->data) + '_';

    res += serialization(loot->left);
    res += serialization(loot->right);

    return res;
}

BinaryNode * BinaryTree::reConstruct(string & str) {
    queue<string> stringQueue;
    stringstream input(str);
    string temp;
    while (getline(input, temp, '_')) {
        stringQueue.push(temp);
    }

    return reConstruct(stringQueue);
}


BinaryNode * BinaryTree::reConstruct(queue<string> & stringQueue)

{
    string value = stringQueue.front();
    stringQueue.pop();
    if (value == "#") return nullptr;

    auto * loot = new BinaryNode{stoi(value), nullptr, nullptr};
    loot->left = reConstruct(stringQueue);
    loot->right = reConstruct(stringQueue);

    if (stringQueue.empty()) return loot;
    return loot;
}

void BinaryTree::paperFolding(int n) {
    int i = 1;
    bool down = true;       // 第i个节点的折痕方向,true 表示凹,false 表示凸
    printPaperFolding(i = 1, n, down);
}

void BinaryTree::printPaperFolding(int i, int n, bool down) {
    if (i > n) return;

    printPaperFolding(i + 1, n, true);
    cout << (down ? "concave" : "convex") << ' ';
    printPaperFolding(i + 1, n, false);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值