基於廣義表二叉樹字符串遞歸生成二叉樹,各種遞歸非遞歸遍歷二叉樹,查找二叉樹操作,求二叉樹高度,深度,結點度數,葉子結點度數集合

基本思路都在代碼註釋裏

#include <string>
#include <iostream>
#include <algorithm>
#include <stack>

using namespace std;

struct treeNode {
    string data;

    treeNode *leftChild{};
    treeNode *rightChild{};

    int leftTag;
    int rightTag;
};

//返回的是中點逗號的位置
//1.當inputData爲“C(D,E),F”時,返回“6”,
//2.當inputData爲“C,D”時,返回“1”
//3.當inputData爲“,A(B,C)”時,返回“0”
//4.當inputData爲“C(D,E)”時,返回“-1”
int findMiddlePosition(string inputData) {
    int result = -1;

    int leftK = 0;
    int rightK = 0;
    int position = 0;
    while (inputData[position]) {
        if (inputData[position] == '(') {
            ++leftK;
        } else if (inputData[position] == ')') {
            ++rightK;
        } else if (leftK == rightK && inputData[position] == ',') {
            result = position;
            break;
        }
        ++position;
    }

    return result;
}

//提取出數據
//1.當left爲true時,提取的是左邊的值
//  1.當inputData爲“C(D,E),F”時,返回“C(D,E)”,
//  2.當inputData爲“,A(B,C)”時,返回空字符串
//  3.當inputData爲“C(D,E)”時,返回“C(D,E)”

//2.當left爲false時,提取的是右邊的值
//  1.當inputData爲“C(D,E),F”時,返回“F”
//  2.當inputData爲“C(D,E)”時,返回空字符串
string getString(const string &inputData, bool left) {
    string result;

    int middlePosition = findMiddlePosition(inputData);
    if (left) {
        if (middlePosition == -1) {
            result = inputData;
        } else if (middlePosition != 0) {
            result = inputData.substr(0, middlePosition);
        }
    } else {
        if (middlePosition != -1) {
            result = inputData.substr(middlePosition + 1, inputData.length() - middlePosition - 1);
        }
    }

    return result;
}

//對字符串進行處理
//inputData會有兩種輸入情況
//  1.輸入的只是一個字符,此時直接返回空字符串
//  2.輸入的是一個形如A(B(C,D),E)的形式,去掉第一,第二,最後一個字符,將返回B(C,D),E字符串
string eraseString(const string &inputData) {
    string result;

    if (inputData.length() != 1) {
        result = inputData.substr(2, inputData.length() - 2 - 1);
    }

    return result;
}

//返回第一個字符
string getData(const string &inputData) {
    return inputData.substr(0, 1);
}

//函數返回的是根節點
treeNode *buildTree(const string &inputData) {
    auto *node = new treeNode;
    node->data = getData(inputData);

    string newInputData = eraseString(inputData);

    if (newInputData.empty()) {
        node->leftChild = nullptr;
        node->rightChild = nullptr;
    } else if (getString(newInputData, true).empty()) {
        node->leftChild = nullptr;
        node->rightChild = buildTree(getString(newInputData, false));
    } else if (getString(newInputData, false).empty()) {
        node->leftChild = buildTree(getString(newInputData, true));
        node->rightChild = nullptr;
    } else {
        node->leftChild = buildTree(getString(newInputData, true));
        node->rightChild = buildTree(getString(newInputData, false));
    }

    return node;
}

//使用遞歸進行遍歷二叉樹
void firstTravelTree(treeNode *treeNode) {
    if (!treeNode) {
        return;
    }

    cout << treeNode->data << " -> ";
    firstTravelTree(treeNode->leftChild);
    firstTravelTree(treeNode->rightChild);
}

//使用遞歸進行遍歷二叉樹
void middleTravelTree(treeNode *treeNode) {
    if (!treeNode) {
        return;
    }

    middleTravelTree(treeNode->leftChild);
    cout << treeNode->data << " -> ";
    middleTravelTree(treeNode->rightChild);
}

//使用遞歸進行遍歷二叉樹
void lastTravelTree(treeNode *treeNode) {
    if (!treeNode) {
        return;
    }

    lastTravelTree(treeNode->leftChild);
    lastTravelTree(treeNode->rightChild);
    cout << treeNode->data << " -> ";
}

//非遞歸先序遍歷二叉樹
void specialFirstTravelTree(treeNode *node) {
    stack<treeNode *> s;

    treeNode *p = node;
    treeNode *q;
    while (p || !s.empty()) {
        if (p) {
            cout << p->data;
            cout << " - ";
            s.push(p);
            p = p->leftChild;
        } else {
            q = s.top();
            s.pop();
            p = q->rightChild;
        }
    }
}

//非遞歸中序遍歷二叉樹
void specialMiddleTravelTree(treeNode *node) {
    stack<treeNode *> s;

    treeNode *p = node;
    treeNode *q;
    while (p || !s.empty()) {
        if (p) {
            s.push(p);
            p = p->leftChild;
        } else {
            q = s.top();
            s.pop();
            cout << q->data;
            cout << " - ";
            p = q->rightChild;
        }
    }
}

//非遞歸後序遍歷二叉樹
//1、申請一個棧s1,然後將頭節點壓入棧s1中。
//2、從s1中彈出的節點記爲cur,然後依次將cur的左孩子節點和右孩子節點壓入s1中。
//3、在整個過程中,每一個從s1中彈出的節點都放進s2中。
//4、不斷重複步驟2和步驟3,直到s1爲空,過程停止。
//5、從s2中依次彈出節點並打印,打印的順序就是後序遍歷的順序。
void specialLastTravelTree(treeNode *node) {
    stack<treeNode *> s1;
    stack<treeNode *> s2;

    s1.push(node);
    while (!s1.empty()) {
        treeNode *cur = s1.top();
        s2.push(cur);
        s1.pop();
        if (cur->leftChild) {
            s1.push(cur->leftChild);
        }
        if (cur->rightChild) {
            s1.push(cur->rightChild);
        }
    }

    //顯示s2
    while (!s2.empty()) {
        cout << s2.top()->data;
        cout << " - ";
        s2.pop();
    }
}

//尋找二叉樹,輸出左右節點的值,採用遞歸的方法
void searchNode(treeNode *treeNode, const string &nodeData) {
    if (!treeNode) {
        return;
    }
    if (treeNode->data == nodeData) {
        if (treeNode->leftChild) {
            cout << "   左子節點的值爲:" << treeNode->leftChild->data << endl;
        } else {
            cout << "   無左子節點!" << endl;
        }

        if (treeNode->rightChild) {
            cout << "   右子節點的值爲:" << treeNode->rightChild->data << endl;
        } else {
            cout << "   無右子節點!" << endl;
        }
        return;
    }

    searchNode(treeNode->leftChild, nodeData);
    searchNode(treeNode->rightChild, nodeData);

}

//輸出二叉樹的節點個數
int countNode(treeNode *treeNode) {
    static int countNum = 0;
    if (!treeNode) {
        return 0;
    }

    ++countNum;
    countNode(treeNode->leftChild);
    countNode(treeNode->rightChild);

    return countNum;
}

//輸出二叉樹的葉子數
int countLeaf(treeNode *treeNode) {
    static int countNum = 0;
    if (!treeNode) {
        return 0;
    }

    if (!treeNode->rightChild && !treeNode->leftChild) {
        ++countNum;
    }

    countLeaf(treeNode->leftChild);
    countLeaf(treeNode->rightChild);

    return countNum;
}

//輸出二叉樹的度
int countDegree(treeNode *treeNode) {
    static int countNum = 0;
    if (!treeNode) {
        return 0;
    }

    if (treeNode->rightChild && treeNode->leftChild) {
        countNum = 2;
    } else if (treeNode->rightChild || treeNode->leftChild) {
        countNum = countNum == 2 ? 2 : 1;
    }

    countDegree(treeNode->leftChild);
    countDegree(treeNode->rightChild);

    return countNum;
}

//輸出二叉樹的高度
//思路,找出左括號和右括號差值的最大值
int countHeight(const string &inputData) {
    static int height = 0;

    int *heightData = new int[200];
    height = {0};
    int leftK = 0;
    int rightK = 0;
    int heightDataCount = 0;
    int i = 0;
    while (inputData[i]) {
        if (inputData[i] == '(') {
            ++leftK;
            heightData[heightDataCount] = leftK - rightK;
            ++heightDataCount;
        } else if (inputData[i] == ')') {
            ++rightK;
        }

        ++i;
    }

    height = *max_element(heightData, heightData + 200);
    ++height;
    return height;
}

//中序遍歷線索化二叉樹
treeNode *pre = new treeNode;

void treatingTree(treeNode *node) {
    if (node) {
        treatingTree(node->leftChild);
        if (!node->leftChild) {
            node->leftTag = 1;
            node->leftChild = pre;
        } else {
            node->leftTag = 0;
        }

        if (!pre->rightChild) {
            pre->rightTag = 1;
            pre->rightChild = node;
        } else {
            node->rightTag = 0;
        }
        pre = node;
        treatingTree(node->rightChild);
    }
}

//中序遍歷轉換爲字符串
string data;

string toString(treeNode *treeNode) {
    if (!treeNode) {
        return data;
    }

    toString(treeNode->leftChild);
    data = data + treeNode->data;
    toString(treeNode->rightChild);

    return data;
}

void showFrontAndNext(string data, string target) {
    int position = data.find(target);
    if (!position) {
        return;
    }

    cout << data[position - 1];
    cout << " 、 ";
    cout << data[position + 1];
}

int main() {
    treeNode *tree1 = nullptr;

    cout << "(1)請輸入要構造的二叉樹廣義表:";
    string inputData;
    cin >> inputData;

    tree1 = buildTree(inputData);
    string data = toString(tree1);

    cout << "(2)輸出二叉樹" << endl;
    cout << "   先序遍歷得到的二叉樹字符串爲:";
    firstTravelTree(tree1);
    cout << endl;
    cout << "   中序遍歷得到的二叉樹字符串爲:";
    middleTravelTree(tree1);
    cout << endl;
    cout << "   後序遍歷得到的二叉樹字符串爲:";
    lastTravelTree(tree1);
    cout << endl;

    cout << "(3)輸出‘H’節點的左、右孩子結點值" << endl;
    searchNode(tree1, "H");

    int nodeNum = countNode(tree1);
    int leafNum = countLeaf(tree1);
    int treeDegree = countDegree(tree1);
    int height = countHeight(inputData);
    cout << "(4)輸出該二叉樹的結點個數、葉子結點個數、二叉樹的度和高度" << endl;
    cout << "   結點數:" << nodeNum << endl;
    cout << "   葉子結點數:" << leafNum << endl;
    cout << "   二叉樹的度:" << treeDegree << endl;
    cout << "   二叉樹的高度:" << height << endl;
    cout << endl;

    cout << "(5)非遞歸先序遍歷二叉樹:";
    specialFirstTravelTree(tree1);
    cout << endl;
    cout << "   非遞歸中序遍歷二叉樹:";
    specialMiddleTravelTree(tree1);
    cout << endl;
    cout << "   非遞歸後序遍歷二叉樹:";
    specialLastTravelTree(tree1);
    cout << endl;

    cout << "(6)進行線索化二叉樹..." << endl;
    treatingTree(tree1);
    cout << "   線索化完成..." << endl;
    cout << "   根據線索化二叉樹找到的根節點的前驅:";
    if (tree1->leftTag == 1) {
        cout << tree1->leftChild->data;
    } else {
        cout << "沒有前驅!";
    }
    cout << endl;
    cout << "   根據線索化二叉樹找到的根節點的後繼:";
    if (tree1->rightTag == 1) {
        cout << tree1->rightChild->data;
    } else {
        cout << "沒有後繼!";
    }
    cout << endl;

    cout << "(7)查找到根節點的前驅後繼分別爲:";
    showFrontAndNext(data, tree1->data);
    cout << endl;

    return 0;
}

輸入和輸出如下:

(1)請輸入要構造的二叉樹廣義表:A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))
(2)輸出二叉樹
   先序遍歷得到的二叉樹字符串爲:A -> B -> D -> E -> H -> J -> K -> L -> M -> N -> C -> F -> G -> I ->
   中序遍歷得到的二叉樹字符串爲:D -> B -> J -> H -> L -> K -> M -> N -> E -> A -> F -> C -> G -> I ->
   後序遍歷得到的二叉樹字符串爲:D -> J -> L -> N -> M -> K -> H -> E -> B -> F -> I -> G -> C -> A ->
(3)輸出‘H’節點的左、右孩子結點值
   左子節點的值爲:J
   右子節點的值爲:K
(4)輸出該二叉樹的結點個數、葉子結點個數、二叉樹的度和高度
   結點數:14
   葉子結點數:6
   二叉樹的度:2
   二叉樹的高度:7

(5)非遞歸先序遍歷二叉樹:A - B - D - E - H - J - K - L - M - N - C - F - G - I -
   非遞歸中序遍歷二叉樹:D - B - J - H - L - K - M - N - E - A - F - C - G - I -
   非遞歸後序遍歷二叉樹:D - J - L - N - M - K - H - E - B - F - I - G - C - A -
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章