二叉树实现(创建,遍历)

1 简介

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个节点最多只能有两棵子树,且有左右之分 [1] 。
二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节

2 性质

二叉树性质
性质1:二叉树的第i层上至多有2i-1(i≥1)个节点 [6] 。
性质2:深度为h的二叉树中至多含有2h-1个节点 [6] 。
性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1 [6] 。
性质4:具有n个节点的满二叉树深为log2n+1。
性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点: [6]
当i=1时,该节点为根,它无双亲节点 [6] 。
当i>1时,该节点的双亲节点的编号为i/2 [6] 。
若2i≤n,则有编号为2i的左节点,否则没有左节点 [6] 。
若2i+1≤n,则有编号为2i+1的右节点,否则没有右节点 [6]

遍历实现分析:

遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有节点,使每一个节点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个节点转换成为一个线性序列来表示

在这里插入图片描述

以上图为例

  • 前序迭代:
    输出:ABDECFGH
    迭代要用到栈来保存父亲结点,
    先序遍历,所有访问过的结点都先输出,
    先遍历当前结点和当前结点的左子树,一直到左子树的最左边的结点,
    遍历过的这些结点都入栈,左孩子为空时,栈顶元素设为当前结点,出栈,
    然后把当前结点设为该节点的右孩子,循环一直到当前结点为空且栈也为空。

  • 中序迭代:
    输出DBEACGHF
    1.如果当前结点的左孩子不为空,则把当前结点的左孩子入栈,知道当前结点的左孩子为空;
    2.如果栈不为空,则出栈,栈顶元素为当前结点,输出当前结点,并把当前结点的右孩子设为当前结点;
    重复1,2直到当前结点为NULL且栈也为空;

  • 后序迭代
    输出:DEBHGFCA
    后序遍历比先序、中序都要复杂,
    第一种迭代方法,可以用两个栈来模拟递归的遍历;
    栈1初始化时把根节点入栈,
    1.栈1出栈,把出栈的元素加入栈2,然后把该元素的左孩子(如果不为空),右孩子(如果不为空)加入栈1,知道栈1为空;
    2.栈2出栈直到空,每次出栈时输出栈顶元素;
    通过两个栈,保证了栈2中的元素顺序,
    第二种迭代方法,
    用一个结点保存访问过的最后一个结点pre,如果pre为栈顶元素的右孩子,则说明栈顶元素的右子树已经遍历过了,直接输出栈顶元素,并把当前结点设为NULL,并更新pre为出栈的元素;
    1.如果当前结点存在,则一直向左遍历,入栈遍历的元素,直到结点为空;
    2.栈不为空时,出栈,当前结点为栈顶元素,
    如果当前结点的右孩子不为空且不为pre,说明当前结点的右子树没有遍历过,设置当前结点为该节点的右孩子,
    如果右孩子为空或者为pre,直接输出当前结点,更新pre为当前结点,并设当前结点为NULL,
    重复1,2直到当前结点为NULL并且栈为空;

  • 层次遍历
    输出ABCDEFGH
    这里采用队列最为简单,思路就是,先入队根节点,再循环;
    循环条件是判断队列是否为空;循环中先访问队列头部节点的元素,再做出队操作,然后再入队左边边子节点(前提是左边子节点不为空),然后再入队右边子节点(前提是右边子节点不为空),按照这个操作循环就能层次遍历所有的节点了

递归创建

ABD##E##CF##G#H##
其中#表示NULL,D节点的左右子节点都是NULL所以连续两个##,紧接着创建E,E节点的左右字节点也是NULL所以连续两个##,紧接着是C,C下面左节点F节点,F节点的左右字节点也是NULL所以连续两个##,C下面右子节点G节点,G节点下面左子节点为空所以一个#,G节点下面右子节点H节点,H节点的左右子节点都是NULL所以连续两个##

先看输出结果

lkdcom@lkdcom1:~/c++/binary_tree$ ./a.out 
A
B
D
#
#
E
#
#
C
F
#
#
G
#
H
#
#
prex:
ABDECFGH
ABDECFGH
mid:
DBEAFCGH
DBEAFCGH
last:
DEBFHGCA
DEBFHGCA
DEBFHGCA
层次
ABCDEFGH

代码实现:

#include <iostream>
#include <stack>
#include <algorithm>
#include <malloc.h>
#include <queue>

using namespace std;

/* 节点定义 */
struct treeNode {
	char data;
	struct treeNode *Lnode;
	struct treeNode *Rnode;
};

/*********************************普通创建*******************************************/
struct treeNode* creat(char dat)
{
	struct treeNode* node = (struct treeNode*)malloc(sizeof(struct treeNode));
	if(node == NULL)
	{
		return NULL;
	}
	cout << "malloc successed"<<endl;
	node->data = dat;
	node->Lnode = NULL;
	node->Rnode = NULL;
	return node;	
}
/*********************************普通创建*******************************************/

/*********************************递归创建*******************************************/
void recursion_creat(struct treeNode** nd)
{
	char userKey = 0;
	cin >> userKey;
	if(userKey == '#')	//# 表示空
	{
		*nd =NULL;
	}
	else
	{
		*nd = (struct treeNode*)malloc(sizeof(struct treeNode));
		if(*nd == NULL)
		{
			cout << "malloc failed" << endl;
			return ;
		}
		(*nd)->data = userKey;
		recursion_creat(&((*nd)->Lnode));
		recursion_creat((&(*nd)->Rnode));
	}
}

/*********************************递归创建*******************************************/

/*********************************插入操作*******************************************/
void insert(struct treeNode* parent,struct treeNode* L,struct treeNode* R)
{
	parent->Lnode = L;
	parent->Rnode = R;
}
/*********************************插入操作*******************************************/


/*********************************前序遍历*******************************************/
void prex_recursion_traverse(struct treeNode* p)	//递归
{
	if(p != NULL)	
	{
		cout << p->data;
		prex_recursion_traverse(p->Lnode);
		prex_recursion_traverse(p->Rnode);
	}
}
void prex_iterate_traverse(struct treeNode* p)	//迭代
{
	if(p == NULL) return;
	stack<struct treeNode*> stck;
	struct treeNode* tmp = p;
	while(!stck.empty() || tmp != NULL)
	{
		while(tmp != NULL)
		{
			cout << tmp->data;
			stck.push(tmp);
			tmp = tmp->Lnode;
		}
		if(!stck.empty())
		{
			tmp = stck.top();
			stck.pop();
			tmp = tmp->Rnode;
		}
	}
}

/*********************************前序遍历*******************************************/

/*********************************中序遍历*******************************************/
void mid_recursion_traverse(struct treeNode* p)	//递归
{
	if(p != NULL)	
	{
		mid_recursion_traverse(p->Lnode);
		cout << p->data;
		mid_recursion_traverse(p->Rnode);
	}
}
void mid_iterate_traverse(struct treeNode* p)	//迭代
{
	if(p == NULL) return;
	stack<struct treeNode*> stck;
	struct treeNode* tmp = p;
	while(!stck.empty() || tmp != NULL)
	{
		while(tmp != NULL)
		{
			stck.push(tmp);
			tmp = tmp->Lnode;
		}
		if(!stck.empty())
		{
			tmp = stck.top();
			stck.pop();
			cout << tmp->data;	
			tmp = tmp->Rnode;
		}
	}
}

/*********************************中序遍历*******************************************/

/*********************************后序遍历*******************************************/
void last_recursion_traverse(struct treeNode* p)	//递归
{
	if(p != NULL)	
	{
		last_recursion_traverse(p->Lnode);
		last_recursion_traverse(p->Rnode);
		cout << p->data;
	}
}

void last_iterate_traverse(struct treeNode* p)	//迭代
{
	if(p == NULL) return;
	stack<struct treeNode*> stck;
	struct treeNode* tmp = p;
	struct treeNode* pre = NULL;
	while(!stck.empty() || tmp != NULL)
	{
		while(tmp != NULL)
		{
			stck.push(tmp);
			tmp = tmp->Lnode;
		}
		if(!stck.empty())
		{
			tmp = stck.top();
			if(tmp->Rnode != NULL && tmp->Rnode != pre)
			{
				tmp = tmp->Rnode;
			}
			else
			{
				stck.pop();
				cout << tmp->data;	
				pre = tmp;
				tmp = NULL;;
			}
		}
	}
}
void last1_iterate_traverse(struct treeNode* p)	//迭代 双栈实现
{
	if(p == NULL) return;
	stack<struct treeNode*> stck,stck1;
	struct treeNode* tmp = p;
	struct treeNode* pre = NULL;

	stck.push(tmp);
	while(!stck.empty())
	{
		tmp = stck.top();
		stck.pop();
		stck1.push(tmp);
		
		if(tmp->Lnode != NULL)
		{
			stck.push(tmp->Lnode);
		}
		if(tmp->Rnode != NULL)
		{
			stck.push(tmp->Rnode);
		}
	}
	while(!stck1.empty())
	{
		pre = stck1.top();
		cout << pre->data;
		stck1.pop();
	}
}

/*********************************后序遍历*******************************************/


/*********************************层次遍历*******************************************/
void level_iterate_traverse(struct treeNode* p)	//迭代 队列实现
{
	if(p == NULL) return;
	struct treeNode* tmp = p;
	queue<struct treeNode*> que;
	que.push(tmp);
	
	while(!que.empty())
	{
		tmp = que.front();
		cout << tmp->data;
		que.pop();
		if(tmp->Lnode != NULL)
		{
			que.push(tmp->Lnode);
		}
		if(tmp->Rnode != NULL)
		{
			que.push(tmp->Rnode);
		}
	}
}
/*********************************层次遍历*******************************************/
#define RECURSION_CREEAT_SWITCH 1
void test(void)
{
#if RECURSION_CREEAT_SWITCH
	struct treeNode *A = NULL;
	recursion_creat(&A);	// ABD##E##C#FGH###
#else
	struct treeNode* A = creat('A');
	struct treeNode* B = creat('B');
	struct treeNode* C = creat('C');
	struct treeNode* D = creat('D');
	struct treeNode* E = creat('E');
	struct treeNode* F = creat('F');
	struct treeNode* G = creat('G');
	struct treeNode* H = creat('H');

	insert(A, B ,C);
	insert(B, D ,E);
	insert(C, NULL ,F);
	insert(F, G ,NULL);
	insert(G, NULL ,H);
#endif	

	/* 前序 */
	cout << "prex:"<<endl;
	prex_recursion_traverse(A);//递归
	cout <<  endl;
	prex_iterate_traverse(A);//迭代	
	cout <<  endl;

	/* 中序 */
	cout << "mid:"<<endl;
	mid_recursion_traverse(A);//递归
	cout <<  endl;
	mid_iterate_traverse(A);//迭代
	cout << endl;

	/* 后序 */
	cout << "last:" << endl;
	last_recursion_traverse(A);//递归
	cout << endl;
	last_iterate_traverse(A);//迭代
	cout << endl;
	last1_iterate_traverse(A);//迭代 队列实现
	cout << endl;
	
	/* 层次 */
	cout << "层次" << endl;	
	level_iterate_traverse(A);//递归
	
	cout << endl;
}


int main(void)
{
	test();
	return 0;
}



参考链接1

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值