二叉树从存储到遍历详解

本文详细介绍了二叉树的两种主要存储方式——顺序存储和链式存储,以及它们的特点和适用场景。同时,文章提供了先序、中序和后序遍历的具体实现代码,帮助读者深入理解二叉树的遍历过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

存储:顺序存储和链式存储

顺序存储:

顺序存储是将二叉树结点存储在一个一位数组中,因此,必须把二叉树的所有结点安排成为一个恰当的序列,结点在这个序列中的相互位置能反映出结点之间的逻辑关系,用编号的方法从树根起,自上层至下层,每层自左至右地给所有结点编号。

在这里为了更好地说明问题,我们举一个例子:

有一个表达式:a+b*(c-d)-e/f,我们现在需要采用顺序存储的方式来建立起这颗二叉树。

首先,我们需要清楚的是,这个表达式所建立起来的二叉树是什么样子的,这样我们才能正确的存入结点和正确的遍历这个二叉树。

因为这是一个表达式,我们遵循表达式的结合顺序来建立这颗二叉树,它应该是这个样子的:

 

注意虚线处的结点本身是不存在的,但是为了方便后面的说明,我在这里加了上去。

所以我们的一位数组中的存储就是将这颗二叉树的结点从上到下,从左往右依次填充在数组中(注意这里以完全二叉树存储),也就是图中所标注结点的序号和数组的下标一一对应,对于空节点,我们用0表示。

 

/*
二叉树的顺序存储以及遍历
*/
#include<stdio.h>
#define max_size 100

char Btree[max_size] = { 0 };
int len = 0;
void Btree_create()
{
	char c;
	int i = 0;
	while (i<max_size)
	{
		scanf_s("%c", &c);
		if (c=='&')
		{
			break;
		}
		Btree[i] = c;
		++i;
	}
	if (i>=100)
	{
		return;
	}
	len = i;
}

void Btree_pre(char Btree[],int start)
{
	int tmp = start;
	if (Btree[tmp]==0 || tmp >= len)
	{
		return ;
	}
	//打印
	if (Btree[tmp]!='0')
	{
		printf("%c", Btree[tmp]);
	}
	//左子树
	Btree_pre(Btree, 2 * tmp + 1);
	//右子树
	Btree_pre(Btree, 2 * (tmp+1));
}

void Btree_mid(char Btree[], int start)
{
	int tmp = start;
	if (Btree[tmp] == 0 || tmp >= len)
	{
		return;
	}
	//左子树
	Btree_mid(Btree, 2 * tmp + 1);

	//打印
	if (Btree[tmp] != '0')
	{
		printf("%c", Btree[tmp]);
	}
	
	//右子树
	Btree_mid(Btree, 2 * (tmp + 1));
}

void Btree_tail(char Btree[], int start )
{
	int tmp = start;
	if (Btree[tmp] == 0 || tmp >= len)
	{
		return;
	}
	//左子树
	Btree_tail(Btree, 2 * tmp + 1);
	
	//右子树
	Btree_tail(Btree, 2 * (tmp + 1));
	//打印
	if (Btree[tmp] != '0')
	{
		printf("%c", Btree[tmp]);
	}
}


int main()
{
	//顺序存储建立二叉树
	Btree_create();
	//先序遍历
	printf("先序遍历\n");
	Btree_pre(Btree,0);
	printf("\n");
	//中序遍历
	printf("中序遍历\n");
	Btree_mid(Btree, 0,max_size);
	printf("\n");
	//后序遍历
	printf("后序遍历\n");
	Btree_tail(Btree, 0,max_size);
	printf("\n");
	system("pause");
	return 0;
}

顺序存储可能会浪费空间(在非完全二叉树的时候),但是读取某个指定的节点的时候效率比较高O(0)

链式存储相对二叉树比较大的时候浪费空间较少,但是读取某个指定节点的时候效率偏低O(nlogn)

 

二叉树的顺序存储,寻找后代节点和祖先节点都非常方便,但对于普通的二叉树,顺序存储浪费大量的存储空间,同样也不利于节点的插入和删除。因此顺序存储一般用于存储完全二叉树。

链式存储相对顺序存储节省存储空间,插入删除节点时只需修改指针,但寻找指定节点时很不方便。不过普通的二叉树一般是用链式存储结构。

遍历:先序遍历、中序遍历、后序遍历

/*
二叉树的链式存储与遍历
*/

#include<iostream>
using namespace std;

//定义节点
typedef struct node
{
	struct node *lchild;
	struct node *rchild;
	char data;
}BiTreeNode, *BiTree;

//*BiTree的意思是给 struct node*起了个别名,叫BiTree,故BiTree为指向节点的指针。


//按照前序顺序建立二叉树
void createBiTree(BiTree &T) //&的意思是传进来节点指针的引用,括号内等价于 BiTreeNode* &T,目的是让传递进来的指针发生改变
{
	char c;
	cin >> c;
	if ('#' == c)             //当遇到#时,令树的根节点为NULL,从而结束该分支的递归
		T = NULL;
	else
	{
		T = new BiTreeNode;
		T->data = c;
		createBiTree(T->lchild);
		createBiTree(T->rchild);
	}
}

//前序遍历二叉树并打印
void preTraverse(BiTree T)
{
	if (T)
	{
		cout << T->data << " ";
		preTraverse(T->lchild);
		preTraverse(T->rchild);
	}
}
//中序遍历二叉树并打印
void midTraverse(BiTree T)
{
	if (T)
	{
		midTraverse(T->lchild);
		cout << T->data << " ";
		midTraverse(T->rchild);
	}
}
//后续遍历二叉树并打印
void postTraverse(BiTree T)
{
	if (T)
	{
		postTraverse(T->lchild);
		postTraverse(T->rchild);
		cout << T->data << " ";
	}
}
int main()
{
	BiTree T;               //声明一个指向二叉树根节点的指针               
	createBiTree(T);
	cout << "二叉树创建完成!" << endl;
	cout << "前序遍历二叉树:" << endl;
	preTraverse(T);
	cout << endl;
	cout << "中序遍历二叉树:" << endl;
	midTraverse(T);
	cout << endl;
	cout << "后序遍历二叉树:" << endl;
	postTraverse(T);
	system("pause");
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

9号信箱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值