持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
基础知识
- 二叉树
- 定义:二叉树(Binary tree)是树形结构的一个重要类型。是指树中节点的度不大于2的有序树。
- 递归定义:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。
- 实现:顺序存储(数组实现)和链式存储(链表实现)
- 相关术语:节点、节点的度、叶子节点、分支节点、树的度、节点的层次、树的深度、有序树、无序树、森林
- 应用:数据的索引与查找(二叉排序树)、堆、...
- 常见的操作:树的创建、树的遍历、查找结点、...
题目
- 二叉树的基本操作算法实现
- (1)利用二叉树字符串“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建二叉树的二叉链式存储结构;
- (2)输出该二叉树;
- (3)输出‘H’节点的左、右孩子结点值;
- (4)输出该二叉树的结点个数、叶子结点个数、二叉树的度和高度;
思路
- ① 创建二叉树
- ② 遍历统计结点数量、树的高度、查找结点
代码
#include <iostream>
#include<ctime>
#include<stack>
#include <cstdlib>
using namespace std;
void printstring(char* ch)
{
for (int i = 0; i < 37; ++i)
{
cout << ch[i] << ' ';
}
cout << endl;
}
class treeNode
{
public:
treeNode() :ch(NULL), lChild(NULL), rChild(NULL) {}
treeNode(char m_ch, treeNode* m_lChild = NULL, treeNode* m_rChild = NULL) :ch(m_ch), lChild(m_lChild), rChild(m_rChild) {}
~treeNode() { lChild = NULL; rChild = NULL; }
public:
treeNode* lChild;
treeNode* rChild;
char ch;
};
class treeList
{
public:
treeList() :root(new treeNode()) {}
treeList(treeNode* m_root) :root(m_root) {}
~treeList() { destroyTree(root); delete root; }
void buildTree(treeNode* node, char* ch, int ch_index);
void buildTree_update(treeNode* node, char* ch, int index);
void createTree(treeNode* node, char* ch, int index);
void findChild(char ch, treeNode* node);
void printTree(treeNode* node);
void destroyTree(treeNode* node); //销毁二叉树
int getTreeDepth(treeNode* node); //二叉树的高度
int getTreeNodeNum(treeNode* node); //二叉树结点个数
int getTreeLevesNum(treeNode* node); //二叉树叶子数
int getTreeDegree(treeNode* node); //二叉树的度(最大出度,不超过2)
public:
treeNode* root;
};
// A(B(D, E(H(J, K(L, M(, N))))), C(F, G(, I)))/*
①建立根节点,(index == 0时)赋值
②寻找左孩子:遇到'('时,判断下一个符号是字母还是',':字母:创建左孩子,之后执行③;否则,无左孩子,之后执行④;
③判断当前字母是否有左孩子,有左孩子时,递归调用,否则执行下一步
④寻找右孩子:遇到','时,判断下一个符号是字母还是')':字母:创建右孩子,之后执行⑤;否则,无左孩子,return;
判断无右孩子的条件:找到左孩子后,下一个符号为')',此时return,解决结点E无',用于识别的问题'
⑤判断当前字母是否有左孩子('即下一个符号是否为'('),有左孩子时,递归调用
注:前面遍历完的符号要设为空或者其他符号,避免递归是与后面的判断条件重复,导致找不到逻辑混乱(多次创建结点,找不到右括号)
*/
void treeList::buildTree_update(treeNode* node, char* ch, int index)
{
if (ch[index] == NULL) return;
if (index == 0)
{
node->ch = ch[index];
index++;
}
if (ch[index] == '(') //寻找左孩子
{
//cout << index << " " << ch[index] << endl;
//cout <<"寻找" << node->ch << "的左孩子!" << endl;
bool flag = 0;
while (ch[index] != ','&&ch[index] != ')')
{
ch[index] = '\0'; //复制完后要把字母置空,避免递归时发生错误!!!
index++;
//cout << index << " " << ch[index] << endl;
if (ch[index] >= 'A'&&ch[index] <= 'Z') //存在左孩子
{
node->lChild = new treeNode(ch[index]);
cout << node->ch << " 创建左孩子 " << ch[index] << endl;
ch[index] = '\0'; //把字母置空,避免递归时发生错误!!!
flag = 1;
index++;
//cout << index << " " << ch[index] << endl;
if (ch[index] == '(') buildTree_update(node->lChild, ch, index); //注意此条件!!!
else break;
//cout << "当前结点" << node->ch << endl;
}
}
if (flag == 0) //不存在左孩子
{
node->lChild = NULL;
cout << node->ch << " 没有左孩子" << endl;
}
}
if (ch[index] == ',' || ch[index] == ')') //寻找右孩子 ,增加条件: || ch[index] == ')'
{
if (ch[index] == ',')
{
ch[index] = '\0';
index++;
//cout << index << " " << ch[index] << endl;
//cout << "寻找" << node->ch << "的右孩子!" << endl;
bool flag = 0;
while (ch[index] != ')')
{
//cout << index << " " << ch[index] << endl;
if (ch[index] >= 'A'&&ch[index] <= 'Z') //存在右孩子
{
node->rChild = new treeNode(ch[index]);
cout << node->ch << " 创建右孩子 " << ch[index] << endl;
ch[index] = '\0'; //字母置空,避免递归时发生错误!!!
flag = 1;
index++;
//cout << index << " " << ch[index] << endl;
if (ch[index] == '(')buildTree_update(node->rChild, ch, index);
else if (ch[index] == ')')
{
ch[index] = '\0';
return;
}
index++;
}
index++;
}
if (flag == 0) //不存在右孩子
{
node->rChild = NULL;
cout << node->ch << " 没有右孩子" << endl;
}
}
else if (ch[index] == ')') //增加条件:解决结点E没有右孩子,但没有','用于识别的情况
{
ch[index] = '\0';
node->rChild = NULL;
cout << node->ch << " 没有右孩子" << endl;
return;
}
if (ch[index] == ')')
{
ch[index] = '\0';
return;
}
}
cout << "!!!" << ch[index] << endl;
cout << "bug!!!" << endl;
}
void treeList::destroyTree(treeNode* node)
{
if (node != NULL)
{
if (node->lChild != NULL)
{
destroyTree(node->lChild);
cout << "删除" << node->ch << "的左孩子:" << node->lChild->ch << endl;
delete node->lChild;
}
if (node->rChild != NULL)
{
destroyTree(node->rChild);
cout << "删除" << node->ch << "的右孩子:" << node->rChild->ch << endl;
delete node->rChild;
}
}
}
void treeList::findChild(char ch, treeNode* node)
{
if (node != NULL)
{
if (node->lChild != NULL)
{
if (node->lChild->ch == ch)
{
if (node->lChild->lChild != NULL) cout << ch << "的左孩子:" << node->lChild->lChild->ch << endl;
else cout << ch << "无左孩子:" << endl;
if (node->lChild->rChild != NULL) cout << ch << "的右孩子:" << node->lChild->rChild->ch << endl;
else cout << ch << "无右孩子:" << endl;
return;
}
else
{
findChild(ch, node->lChild);
}
}
if (node->rChild != NULL)
{
if (node->rChild->ch == ch)
{
if (node->rChild->lChild != NULL) cout << ch << "的左孩子:" << node->rChild->lChild->ch << endl;
else cout << ch << "无左孩子!" << endl;
if (node->rChild->rChild != NULL) cout << ch << "的右孩子:" << node->rChild->rChild->ch << endl;
else cout << ch << "无右孩子!" << endl;
return;
}
else
{
findChild(ch, node->rChild);
}
}
}
}
void treeList::printTree(treeNode* node) //中序遍历
{
if (node != NULL)
{
cout << node->ch;
if (node->lChild != NULL || node->rChild != NULL)
{
cout << '(';
printTree(node->lChild);
if (node->rChild != NULL) cout << ',';
printTree(node->rChild);
cout << ')';
}
}
}
int treeList::getTreeDepth(treeNode* node) //二叉树的高度,初始化为0
{
if (node == NULL) return 0;
else
{
int lDepht = getTreeDepth(node->lChild);
int rDepht = getTreeDepth(node->rChild);
if (lDepht > rDepht) return lDepht + 1;
else return rDepht + 1;
}
}
int treeList::getTreeNodeNum(treeNode* node) //二叉树结点个数,初始化为0
{
if (node == NULL) return 0;
else
{
return getTreeNodeNum(node->lChild) + getTreeNodeNum(node->rChild) + 1; //左子树结点数+右子树结点数
}
}
int treeList::getTreeLevesNum(treeNode* node) //二叉树叶子数,初始化为0
{
if (node == NULL) return 0;
if (node->lChild == NULL && node->rChild == NULL)
{
return 1;
}
else return getTreeLevesNum(node->lChild) + getTreeLevesNum(node->rChild);
}
int treeList::getTreeDegree(treeNode* node) //二叉树的度(最大出度,不超过2),初始化为0,达到2即可return
{
if (node == NULL || (node->lChild == NULL && node->rChild == NULL)) return 0;
else if ((node->lChild == NULL && node->rChild != NULL) || (node->lChild != NULL && node->rChild == NULL))
{
int max1 = getTreeDegree(node->lChild) > 1 ? getTreeDegree(node->lChild) : 1;
int max2 = getTreeDegree(node->rChild) > 1 ? getTreeDegree(node->rChild) : 1;
return max1 > max2 ? max1 : max2;
}
else if (node->lChild != NULL && node->rChild != NULL) return 2;
}
int main()
{
char *cc = nullptr;
const char*string = { "A(B(D,E(H(J,K(L,M(,N))),)),C(F,G(,I)))" };
cc = new char[strlen(string) + 1];
for (int i = 0; i < strlen(string); ++i)
{
cc[i] = string[i];
}
cc[strlen(string)] = '\0';
int len = strlen(string);
int iter = 0;
int letter_num = 0;
treeList* tree = new treeList(); //创建一棵空树
while (true)
{
int flag = 1;
cout << "\n选择1:利用二叉树字符串“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建二叉树的二叉链式存储结构:\n";
cout << "选择2:输出该二叉树:\n";
cout << "选择3:输出‘H’节点的左、右孩子结点值:\n";
cout << "选择4:输出该二叉树的结点个数、叶子结点个数、二叉树的度和高度:\n";
cout << "选择5:执行各种遍历操作:\n";
cout << "选择6:构建中序二叉线索树及遍历二叉搜索树:\n";
cout << "选择0:退出!\n";
cout << "请输入要执行的操作:";
cin >> flag;
if (flag == 1)
{
cout << "===========test1===========\n(1)利用二叉树字符串“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建二叉树的二叉链式存储结构:" << endl;
tree->buildTree_update(tree->root, cc, 0);
cout << "二叉树创建成功!" << endl;
}
else if (flag == 2)
{
cout << "===========test2===========\n(2)输出该二叉树:" << endl;
tree->printTree(tree->root);
cout << endl;
}
else if (flag == 3)
{
cout << "===========test3===========\n(3)输出‘H’节点的左、右孩子结点值:" << endl;
tree->findChild('H', tree->root);
}
else if (flag == 4)
{
cout << "===========test4===========\n(4)输出该二叉树的结点个数、叶子结点个数、二叉树的度和高度:" << endl;
cout << "1.二叉树的结点个数:";
cout << tree->getTreeNodeNum(tree->root) << endl;
cout << "2.二叉树的叶子数:";
cout << tree->getTreeLevesNum(tree->root) << endl;
cout << "3.二叉树的度:";
//tree->root->lChild = NULL; //用于测试计算二叉树的度函数是否有效
cout << tree->getTreeDegree(tree->root) << endl;
cout << "4.二叉树的高度:";
cout << tree->getTreeDepth(tree->root) << endl;
}
}
结果