数据结构5:二叉树(2)——二叉树的遍历算法

248 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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";

	}
}

结果

在这里插入图片描述 在这里插入图片描述