二叉树的各种操作------2021年11月24日

1.二叉树的创建

*可以建立一颗不完全的二叉树
 //创建
	//广义表的方式  A(B(D,E),Q)#
	void CreatBinTree( BinTreeNode<T>*& bt)
	{
		Refvalue = '#';
		Stack<BinTreeNode<char>*> s;
		bt = NULL;   //把树置空
		BinTreeNode<T>* p=bt, * t; int k;
		char ch;
		cin >> ch;
		while (ch != Refvalue)
		{
			switch (ch)
			{
			case '(': s.Push(p); k = 1; break; //把左括号进栈,k=1,标志下一次创建左结点
			case')':  s.Pop(t); break;
			case',': k = 2; break;  //建立右子树
			default:
				p = new BinTreeNode<T>(ch);
				if (bt == NULL) bt = p;  //建立根结点
				else if (k == 1) {
					s.getTop(t); t->leftchild = p;
				}
				else
				{
					s.getTop(t), t->rightchild = p;
				}
			}
			cin >> ch;
		}
	}
**前序遍历的创建(递归)

根左右的形式创建

BinTreeNode<T>* Creat(BinTreeNode<T>* bt)
	{
		char ch;
		cin >> ch;
		if (ch == '#')
		{
			bt = 0;
		}
		else {
			bt = new BinTreeNode<T>;
			bt->data = ch;
			bt->leftchild = Creat(bt->leftchild);
			bt->rightchild = Creat(bt->rightchild);
		}
		return bt;
	}
用层次遍历的方式建立树(非递归)
//返回值:无
//函数功能:新建通讯录信息
//使用方法,层次遍历建立二叉树(这里是完全二叉树)
void studentDataBase::createTree()
{
	queue<student*>stu;
	root = new student;
	cin >> *root;
	stu.push(root);//根结点入队
	while (!stu.empty())
	{
		student* temp = stu.front();//队首元素出队
		stu.pop();
		student* p = new student;//左子树
		cin >> *p;
		if (p->number[0]=='#')break;
		temp->leftChild= p;
		stu.push(p);
		p = new student;//右子树
		cin >> *p;
		if (p->number[0] == '#')break;
		temp->rightChild = p;
		stu.push(p);
	}
}

遍历二叉树

前,中,后序遍历
前序遍历(递归)
void preorder(BinTreeNode<T>* r)
	{
		if (r == NULL)
			return;
		else
		{
			cout << r->data<<" ";
			preorder(r->leftchild);
			preorder(r->rightchild);
			
		}
	}
前序遍历(非递归)
//非递归遍历,递归就是运行栈,所以现在人工实现栈
	void preorder2()  //传入根结点进入
	{
		Stack <BinTreeNode<T>*> s;
		BinTreeNode<T>* t = root;
		while (!s.Isempty() || t != 0)
		{
			while (t != 0) //先往左边,然后转到右边。
			{
				cout << t->data;
				s.Push(t);
				t = t->leftchild;
			}
			if(!s.Isempty())
			{
				s.Pop(t); t = t->rightchild;
			}
		}
	}
中序遍历(非递归)
void inorder2()  
	{
		Stack <BinTreeNode<T>*> s;
		BinTreeNode<T>* t = root;
		while (!s.Isempty() || t != 0)
		{
			while (t != 0) //先往左边,然后转到右边。
			{
				s.Push(t);
				t = t->leftchild;
			}
			if (!s.Isempty())
			{
				s.Pop(t);
				cout << t->data<<" ";
				t = t->rightchild;
			}
		}
	}
后序遍历非递归

这里考虑是后序,
根会经过两次
需要标记是第一次还是第二次

第一次则转向右结点(把根保存住)
第二次则直接输出,根已经弹出

void postorder2()
	{   //左右根
		Stack<stknode<T>> s;  //存入栈中的元素,是树节点带左右返回标志
		stknode<T> w;
		BinTreeNode<T>* p = root;
		do
		{
			while (p != 0)
			{
				w.ptr = p;
				w.tag = 'L';
				s.Push(w);  //在第一次把根存入,后面存左节点
				p = p->leftchild;
			}
			int continue1 = 1;
			while (continue1 && !s.Isempty())
			{
				s.Pop(w); p = w.ptr;
				switch (w.tag)
				{
				case 'L': w.tag = 'R'; s.Push(w);
					continue1 = 0;
					p = p->rightchild;
					break;
				case 'R':  cout << p->data; break;
				}

			}
		} while (!s.Isempty());

	}
层次遍历
void levelorder(){
		SeqQueue< BinTreeNode<T>*> s;
		BinTreeNode<T>* p = root;
		if(p!=0)  s.EnQueue(p);
		while (!s.IsEmpty())
		{
			s.DeQueue(p);
			cout << p->data;
			if (p->leftchild != 0 )
			{
				s.EnQueue(p->leftchild);
			}
			if (p->rightchild != 0)
			{
				s.EnQueue(p->rightchild);
			}
		}
		cout << endl;
	}

析构函数

void destroy(BinTreeNode<T>*& bt)
	{
		if (bt->leftchild != NULL&&bt->rightchild!=NULL)
		{
			destroy(bt->leftchild);
			destroy(bt->rightchild);
			delete bt;
		}
	};

以下是完整代码

#pragma once
#include"queue.h"
#include"stack.h"
#include <iostream>
using namespace std;
//创建树结点
template <class T>
struct BinTreeNode
{
	T data;
	BinTreeNode<T>* leftchild, *rightchild;
	BinTreeNode(){};
	BinTreeNode(T x, BinTreeNode<T>* l = NULL, BinTreeNode<T>* r = NULL)
	{
		data = x; leftchild = l; rightchild = r;
	}
};

//用于后序遍历的非递归算法
template <class T>
struct stknode
{
	BinTreeNode<T>* ptr;
	char tag ;
	stknode(BinTreeNode<T>* N = NULL):ptr(N),tag('L'){ }
};
template <class T>
class BinaryTree
{
public:
	BinaryTree() {  //CreatBinTree(root); 
		root = Creat(root);
	};
	~BinaryTree() { destroy(root);}
	//递归遍历
	void preorder(BinTreeNode<T>* r)
	{
		if (r == NULL)
			return;
		else
		{
			cout << r->data<<" ";
			preorder(r->leftchild);
			preorder(r->rightchild);
			
		}
	}
	//非递归遍历,递归就是运行栈,所以现在人工实现栈
	void preorder2()  //传入根结点进入
	{
		Stack <BinTreeNode<T>*> s;
		BinTreeNode<T>* t = root;
		while (!s.Isempty() || t != 0)
		{
			while (t != 0) //先往左边,然后转到右边。
			{
				cout << t->data;
				s.Push(t);
				t = t->leftchild;
			}
			if(!s.Isempty())
			{
				s.Pop(t); t = t->rightchild;
			}
		}
	}
	void inorder(BinTreeNode<T>* r)
	{
		if (r == NULL)
			return;
		else
		{
			preorder(r->leftchild);    //先左子树
			cout << r->data << " ";    //根
			preorder(r->rightchild);    //右
		}
	}
	void inorder2()  
	{
		Stack <BinTreeNode<T>*> s;
		BinTreeNode<T>* t = root;
		while (!s.Isempty() || t != 0)
		{
			while (t != 0) //先往左边,然后转到右边。
			{
				s.Push(t);
				t = t->leftchild;
			}
			if (!s.Isempty())
			{
				s.Pop(t);
				cout << t->data<<" ";
				t = t->rightchild;
			}
		}
	}
	void postorder(BinTreeNode<T>* r)
	{
		if (r == NULL)
			return;
		else
		{
			preorder(r->leftchild);    //先左子树
			preorder(r->rightchild);    //右
			cout << r->data << " ";    //根
		}
	}
	void postorder2()
	{   //左右根
		Stack<stknode<T>> s;  //存入栈中的元素,是树节点带左右返回标志
		stknode<T> w;
		BinTreeNode<T>* p = root;
		do
		{
			while (p != 0)
			{
				w.ptr = p;
				w.tag = 'L';
				s.Push(w);  //在第一次把根存入,后面存左节点
				p = p->leftchild;
			}
			int continue1 = 1;
			while (continue1 && !s.Isempty())
			{
				s.Pop(w); p = w.ptr;
				switch (w.tag)
				{
				case 'L': w.tag = 'R'; s.Push(w);
					continue1 = 0;
					p = p->rightchild;
					break;
				case 'R':  cout << p->data; break;
				}

			}
		} while (!s.Isempty());

	}
	void levelorder(){
		SeqQueue< BinTreeNode<T>*> s;
		BinTreeNode<T>* p = root;
		if(p!=0)  s.EnQueue(p);
		while (!s.IsEmpty())
		{
			s.DeQueue(p);
			cout << p->data;
			if (p->leftchild != 0 )
			{
				s.EnQueue(p->leftchild);
			}
			if (p->rightchild != 0)
			{
				s.EnQueue(p->rightchild);
			}
		}
		cout << endl;
	}
	bool Isempty() { returun(root == NULL); }
	//写一个函数,将左右子树交换,(注意是全部交换)
	void exchange(BinTreeNode<T>* r)
	{
		BinTreeNode<T>* x=r;
		if (r != 0)
		{
			x = r->leftchild;
			r->leftchild = r->rightchild;
			r->rightchild = x;
			exchange(r->leftchild);
			exchange(r->rightchild);
		}
		
	}
	//写一个函数,统计叶子结点总数
	void sumnode(BinTreeNode<T>* r,int& i)
	{
		BinTreeNode<T>* p=r;
		if (p != 0)
		{
			if (p->leftchild == 0 && p->rightchild == 0)
			{
				i++;
			}
		}
		if(p!=0)
		{
			sumnode(p->leftchild, i);
			sumnode(p->leftchild, i);
		}
	}
	//统计所有结点
	int Size(BinTreeNode<T>* r)
	{
		if (r != 0)
		{
			return 1+Size(r->leftchild) + Size(r->rightchild);
		}
		else
		{
			return 0;
		}
	}
	BinTreeNode<T>* getroot() { return root; }
protected :
	BinTreeNode<T>* root;
	T Refvalue;
    //创建
	//广义表的方式  A(B(D,E),Q)#
	void CreatBinTree( BinTreeNode<T>*& bt)
	{
		Refvalue = '#';
		Stack<BinTreeNode<char>*> s;
		bt = NULL;   //把树置空
		BinTreeNode<T>* p=bt, * t; int k;
		char ch;
		cin >> ch;
		while (ch != Refvalue)
		{
			switch (ch)
			{
			case '(': s.Push(p); k = 1; break; //把左括号进栈,k=1,标志下一次创建左结点
			case')':  s.Pop(t); break;
			case',': k = 2; break;  //建立右子树
			default:
				p = new BinTreeNode<T>(ch);
				if (bt == NULL) bt = p;  //建立根结点
				else if (k == 1) {
					s.getTop(t); t->leftchild = p;
				}
				else
				{
					s.getTop(t), t->rightchild = p;
				}
			}
			cin >> ch;
		}
	}
	BinTreeNode<T>* Creat(BinTreeNode<T>* bt)
	{
		char ch;
		cin >> ch;
		if (ch == '#')
		{
			bt = 0;
		}
		else {
			bt = new BinTreeNode<T>;
			bt->data = ch;
			bt->leftchild = Creat(bt->leftchild);
			bt->rightchild = Creat(bt->rightchild);
		}
		return bt;
	}
	//给输入输出使用的,因为这里是受保护的对象
	void destroy(BinTreeNode<T>*& bt)
	{
		if (bt->leftchild != NULL&&bt->rightchild!=NULL)
		{
			destroy(bt->leftchild);
			destroy(bt->rightchild);
			delete bt;
		}
	};
	void Traverse(BinTreeNode<T>* bt, ostream &out) {
		if (bt != NULL)
		{
			out << bt->data << " ";
			Traverse(bt->leftchild, out);
			Traverse(bt->rightchild, out);
		}
	}
	BinTreeNode<T>* parent(BinTreeNode<T>* subtree, BinTreeNode<T>* current)
	{
		if (subtree == NULL)
		{
			return NULL;
		}
		if (subtree->leftchild == current || subtree->rightchild == current)
		{
			return subtree;
		}
		BinTreeNode<T>* p;
		if ((p = parent(subtree->leftchild, current)) != NULL) return p;
		else return parent(subtree->rightchild, current);
	}
	friend istream& operator>>(istream& in, BinaryTree<T>& Tree) {
		CreatBinTree(in, Tree.root);
		return in;
	}
	friend ostream& operator <<(ostream& out, BinaryTree<T>& Tree) {
		out << "前序遍历";
		Tree.Traverse(Tree.root, out);
		out << endl;
		return out;
	}
};



作业

//5.24 设具有n个结点的完全二叉树采用顺序存储结构,
//设计算法将该顺序存储结构转换为二叉链式存储结构。
void creatBintree2(T* a, BinTreeNode<T>* &t, int n,int sum)
{
	if (n >= sum) return;
	if (t == NULL)
	{
		t = new BinTreeNode<T>(a[n]);
	}
	creatBintree2(a, t->leftchild, 2 * n + 1,sum);
	creatBintree2(a, t->rightchild, 2 * n + 2,sum);
}
template<class T>
//5.29 设具有n个结点的二叉树采用二叉链式存储结构,试写出一个算法将该二叉链式存储结构转换为顺序存储结构。
//这里实现的是完全二叉树,对于普通二叉树是不适用的
//这里对数组初始化,每一个都赋值空格。
//为了实现普通的二叉树,在输出顺序存储结构的数组时,只输出有赋值的元素。
void change_to_LinkBintree(T*& a, BinTreeNode<T>* s, int i, int n)
{
	if (i > n)return;
	if (s==0)return;
	else
	{
		a[i] = s->data;
	}
	change_to_LinkBintree(a, s->leftchild, i * 2 + 1, n);
	change_to_LinkBintree(a, s->rightchild, i * 2 + 2, n);
}
BinTreeNode<T>* Copy(BinTreeNode<T>* t)
{
	BinTreeNode<T>* current;
	if (t == 0) return 0;
	else
	{
		current = new BinTreeNode<T>;
		current->data = t->data;
		current->leftchild = Copy(t->leftchild);
		current->rightchild = Copy( t->rightchild);
		return current;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值