基本思路都在代碼註釋裏
#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 -