持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情
基础知识
- 二叉树
- 递归定义:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。
- 实现:顺序存储(数组实现)和链式存储(链表实现)
- 基本操作:树的创建、树的遍历、查找结点、...
- 二叉树的遍历算法:先序遍历(根左右)、中序遍历(左根右)、后序遍历(左右根)
题目
- 1、二叉树的创建
- 利用二叉树字符串“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建二叉树的二叉链式存储结构;
- 2、二叉树的各种遍历算法实现
- 实现上述二叉树的先序、中序和后序遍历的递归和非递归算法;
- 3、线索二叉树的遍历
- 中序线索化上述二叉树并找出根结点的前驱和后继。
思路
- ①创建二叉树
- ②依照不同遍历算法的原理,依次遍历节点
- ③在遍历算法的基础上实现中序线索化
代码
#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 firstOrderTraversal_1(treeNode* node); //先序遍历(递归)
void firstOrderTraversal_2(); //先序遍历(非递归,栈实现)
void InOrderTraversal_1(treeNode* node); //中序遍历(递归)
void InOrderTraversal_2(); //中序遍历(非递归,栈实现)
void postOrderTraversal_1(treeNode* node); //后序遍历(递归)
void postOrderTraversal_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::firstOrderTraversal_1(treeNode* node) //先序遍历(递归)
{
if (node == NULL) return;
cout << node->ch;
if (node->lChild != NULL)
{
firstOrderTraversal_1(node->lChild);
}
if (node->rChild != NULL)
{
firstOrderTraversal_1(node->rChild);
}
}
void treeList::InOrderTraversal_1(treeNode* node) //中序遍历(递归)
{
if (node == NULL) return;
if (node->lChild != NULL)
{
InOrderTraversal_1(node->lChild);
}
cout << node->ch;
if (node->rChild != NULL)
{
InOrderTraversal_1(node->rChild);
}
}
void treeList::postOrderTraversal_1(treeNode* node) //后序遍历(递归)
{
if (node == NULL) return;
if (node->lChild != NULL)
{
postOrderTraversal_1(node->lChild);
}
if (node->rChild != NULL)
{
postOrderTraversal_1(node->rChild);
}
cout << node->ch;
}
void treeList::firstOrderTraversal_2() //先序遍历(非递归)
{
stack<treeNode*> st;
treeNode* node = root;
while (node != NULL || !st.empty())
{
if (node != NULL)
{
cout << node->ch;
st.push(node);
node = node->lChild;
}
else
{
node = st.top();
node = node->rChild;
st.pop();
}
}
}
void treeList::InOrderTraversal_2() //中序遍历(非递归)
{
stack<treeNode*> st;
treeNode* node = root;
while (node != NULL || !st.empty())
{
if (node != NULL)
{
st.push(node);
node = node->lChild;
}
else
{
node = st.top();
cout << node->ch;
node = node->rChild;
st.pop();
}
}
}
void treeList::postOrderTraversal_2() //后序遍历(非递归)
{
stack<treeNode*> st;
treeNode* node = root;
treeNode* sign = NULL;
while (node != NULL || !st.empty())
{
if (node != NULL)
{
st.push(node);
node = node->lChild;
}
else
{
node = st.top();
if (node->rChild != NULL && node->rChild != sign)
{
node = node->rChild;
st.push(node);
node = node->lChild;
}
else
{
cout << node->ch;
sign = node; //根节点
st.pop();
node = NULL;
}
}
}
}
class BiThrNode //线索二叉树结点
{
public:
BiThrNode() :ch(NULL), LTag(0), RTag(0), lchild(NULL), rchild(NULL) {}
BiThrNode(char m_ch) :ch(m_ch), LTag(0), RTag(0), lchild(NULL), rchild(NULL) {}
~BiThrNode() { lchild = NULL; rchild = NULL; }
public:
char ch;
BiThrNode* lchild;
BiThrNode* rchild;
int LTag; //0:左孩子,1:前驱结点
int RTag; //0:右孩子,1:后继结点
};
class BiThrTree
{
public:
BiThrTree() :root(new BiThrNode()) {}
~BiThrTree() { /*DestroyTree();*/ }
void BiTreeCopy(BiThrNode* &thrNode, treeNode* node);
//void DestroyTree();
void InThreading(BiThrNode* pre_node, BiThrNode* &node); //中序线索化二叉树
void InOrderTraverse();
void printTree(BiThrNode* node);
void Inpre(BiThrNode* p);
void InNext(BiThrNode* p);
public:
BiThrNode* root;
};
void BiThrTree::BiTreeCopy(BiThrNode* &thrNode, treeNode* node) //二叉树复制到线索二叉树
{
if (node == NULL)
{
//thrNode = NULL;
return;
}
else
{
//cout<<"复制结点"<<node->ch<<endl;
thrNode = new BiThrNode(node->ch);
//cout << thrNode->ch << "复制成功!" << endl;
BiTreeCopy(thrNode->lchild, node->lChild);
BiTreeCopy(thrNode->rchild, node->rChild);
}
}
void BiThrTree::printTree(BiThrNode* node) //中序遍历
{
if (node != NULL)
{
cout << node->ch;
if (node->lchild != NULL || node->rchild != NULL)
{
cout << '(';
printTree(node->lchild);
if (node->lchild != NULL && node->rchild != NULL) cout << ',';
printTree(node->rchild);
cout << ')';
}
}
}
void BiThrTree::InThreading(BiThrNode* pre_node, BiThrNode* &node)
if (node == NULL) return;
InThreading(pre_node,node->lchild);
if (node->lchild== NULL)
{
node->LTag = 1;
node->lchild = pre_node;
}
else
{
node->LTag = 0;
}
cout << node->ch;
if (pre_node->rchild == NULL)
{
pre_node->RTag = 1;
pre_node->rchild = node;
}
InThreading(pre_node,node->rchild);
}
void BiThrTree::InOrderTraverse()
{
BiThrNode* p = root->lchild;
while (p !=root)
{
while (p->LTag == 0) p = p->lchild;
cout << p->ch;
while (p->RTag == 1 && p->rchild != root)
{
p = p->rchild;
cout << p->ch;
}
p = p->rchild;
}
}
void BiThrTree::Inpre(BiThrNode* p)
{
BiThrNode* q;
if (p->LTag == 1)
{
q = p->lchild;
}
else
{
q = p->lchild;
while (q->RTag == 0)
q = q->rchild;
}
cout << q->ch;
}
void BiThrTree::InNext(BiThrNode* p)
{
if (p->RTag == 0)
Inpre(p->rchild);
else cout<<p->rchild->ch;
}
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;
else if (flag == 5)
{
cout << "===========test5===========\n" << endl;
cout << "2.二叉树的各种遍历算法实现:实现上述二叉树的先序、中序和后序遍历的递归和非递归算法;" << endl;
cout << "先序遍历( 递归 ):";
tree->firstOrderTraversal_1(tree->root);
cout << endl;
cout << "中序遍历( 递归 ):";
tree->InOrderTraversal_1(tree->root);
cout << endl;
cout << "后序遍历( 递归 ):";
tree->postOrderTraversal_1(tree->root);
cout << endl;
cout << "先序遍历(非递归):";
tree->firstOrderTraversal_2();
cout << endl;
cout << "中序遍历(非递归):";
tree->InOrderTraversal_2();
cout << endl;
cout << "后序遍历(非递归):";
tree->postOrderTraversal_2();
cout << endl;
}
else if (flag == 6)
{
cout << "===========test6===========\n" << endl;
cout << "//3. 线索二叉树的遍历:中序线索化上述二叉树并找出根结点的前驱和后继。\n";
cout << "二叉树中序线索化:\n";
BiThrTree* ThreadTree = new BiThrTree();
cout << "二叉线索树复制:\n";
ThreadTree->BiTreeCopy(ThreadTree->root, tree->root); //tree复制到ThreadTree
ThreadTree->printTree(ThreadTree->root);
cout << "\n\n进行中序线索化:\n";
ThreadTree->InThreading(ThreadTree->root, ThreadTree->root);
cout << "\n二叉中序线索树遍历:\n";
ThreadTree->InOrderTraverse();
cout << "查找根节点的前驱与后继:\n";
cout << "根结点的前驱结点为:";
ThreadTree->Inpre(ThreadTree->root);
cout << "根结点的后继结点为:";
ThreadTree->InNext(ThreadTree->root);
}
else if (flag == 0) break;
else cout << "\nError:输入有误,请重新输入!\n";
}
}
结果