数据结构C语言版:树和二叉树

树型结构是一类重要的非线性数据结构。

6.1树的定义和基本术语

        树是n(n≥0)个结点的有限集。任何一颗非空树中:

                1)有且仅有一个称为的结点。

                2)n>1时,其余结点可分为m(m≥0)个互不相交的有限集。其中每一个集合本身又是一棵树。如图6.1,以A为根结点是一颗有13个结点的树,其余结点又可以分为以B为根结点,以C为根结点,以D为根结点的三棵树,以此类推。

         树的基本术语:

        树的结点包含一个数据元素以及若干指向其子树的分支。结点拥有的子树数量称为结点的度。例如图6.1中,A结点的度为3。

        度为0的结点称为叶子终端结点。图6.1中,K、L、F、G、M、I、J,都是叶子结点。

        树的度是树内各结点的度的最大值。图6.1树的度是3。

        结点的子树的根称为该结点的孩子,相应的,该结点称为孩子结点的双亲。如图6.1,B是A的孩子结点,A是B的双亲结点。

        同一个双亲的孩子结点之间互称兄弟。图6.1中,B、C、D互为兄弟结点。结点的祖先是从根到该节点所经分支上所有结点,反之,以某结点为根的子树中的任一结点都是该结点得子孙

        结点的层次从根开始定义,根为第一层,根的孩子为第二层。树中结点最大层次称为树的深度,如图6.1,深度为4。

        如果树中结点各子树有次序不可互换,称为有序树,否则为无序树。有序树最左边的孩子为第一个孩子,最右边的孩子为最后一个孩子。

        森林是m棵(m≥0)互不相交的树的集合。对树中每个结点而言,其子树的集合就是森林。

6.2二叉树

        特点:每个结点至多只有两棵子树(不存在度大于二的结点),并且,二叉树子树有左右之分,次序不可任意颠倒

树的术语均适用于二叉树 

6.2.2二叉树的性质

        性质1:在二叉树的第i层上至多有2^{i-1}次方个结点(n≥1)。

        性质2:深度为k的二叉树至多有2^{k}-1个结点(k≥1)。

        性质3:任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。

        完全二叉树和满二叉树是两种特殊形态的二叉树。满二叉树:只有最后一层是叶子节点,并且其余层结点度数均为2。完全二叉树:结点编号从左子树到右子树一一对应。

6.2.3二叉树的存储结构

1.顺序存储结构:

        用一组地址连续的存储单元依次自上而下,自左至右存储完全二叉树上的结点元素,即将完全二叉树上编号为i的结点元素存储在如上定义的一位数组中下标为i-1的分量重。图中以“0”表示不存在此节点,这种顺序存储结构只适用于完全二叉树,因为最坏的情况下会浪费大量空间。 

2.链式存储结构:

        设计不同的结点结构可以构成不同形式的链式存储结构。二叉树的链表中结点至少包含3个域:数据域,左指针域,有指针域。这种存储结构称之为二叉链表。有时,为了方便找到结点的双亲,还会设置一个指向双亲节点的指针域,称之为三叉链表。

 6.3.1遍历二叉树

        分为三种遍历方式:

                1)前序遍历,顺序为根左右

                2)中序遍历,顺序为左根右

                3)后序遍历,顺序为左右根

6.3.2线索二叉树

        若结点有左孩子,则lchild域指示其左孩子,否则令lchild指向其前驱;若结点有右孩子,其rchild域指向其右孩子,否则指向其后继,为了避免混淆,最好设置一个表明指向什么的标志。

6.4.1树的存储结构

       这里介绍3中常用的链表结构

        1.双亲表示法

        以一组连续空间存储树的结点,同时每个结点中附设一个指示器指示其双亲结点在链表中的位置。

        

        2.孩子表示法

        图6.14(a)是树的孩子表示法,该法不适合寻找双亲结点

         3.孩子兄弟表示法

        如图6.14(b),通俗的说就是左边指针指孩子,右边指针指兄弟。又称二叉树表示法,或者二叉链表表示法。利用这种存储结构便于实现各种树的操作。首先易于实现寻找孩子结点。如果每个结点增设一个双亲域,便于找双亲。

6.4.2森林域二叉树的转化、

        由于二叉树和树都可用二叉链表作为存储结构,所以以二叉链表可以导出树与二叉树之间一个对应的关系。通俗的说,给定一棵树,可以找到唯一的一棵二叉树与之对应。

6.4.3树和森林得遍历 

        两种遍历方法

        1)先序遍历森林,先序遍历每一棵树

        2)中序遍历森林,中序遍历每一棵树

        没有后序遍历

树的基本操作:

#include<iostream>
#include <stdlib.h>
#include<stack>
using namespace std;
typedef char TElemType;
// 二叉链表结点结构
typedef struct BiTNode
{
	TElemType      data;
	struct BiTNode* lchild, * rchild;  // 左右孩子指针
} *BiTree;   //结点类型名为BiTNode,结点指针类型名为BiTree 

//以二叉树的先序序列创建二叉树的二叉链表存储结构,先序序列包含空结点 
void CreateBiTree(BiTree& T)
{
	char ch;
	cout << "请输入二叉链表的序列";
	cin >> ch;
	if (ch== '#')
		T = NULL;
	else {
		T = (BiTNode*)malloc(sizeof(BiTNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}
// 用递归算法实现前序遍历二叉树,输出遍历序列 
void PreOrderTraverse(BiTree T)
{
	if (T) {
		cout << T->data << " ";
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
	}
}
// 用递归算法实现中序遍历二叉树,输出遍历序列
void InOrderTraverse(BiTree T)
{
	if (T) {
		InOrderTraverse(T->lchild);
		cout << T->data << " ";
		InOrderTraverse(T->rchild);
	}
}
// 用递归算法实现后序遍历二叉树,输出遍历序列
void PostOrderTraverse(BiTree T)
{
	if (T) {
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		cout << T->data << " ";
	}
}
// 用非递归算法实现中序遍历二叉树,输出遍历序列
void InOrderTraverseNon(BiTree T)
{
	stack<BiTree>NodeStack;
	BiTree p=T;
	if (T) {
		while (p || !NodeStack.empty()) {
			if (p) {
				NodeStack.push(p);
				p = p->lchild;
			}
			else
			{
				p = NodeStack.top();
				cout << p->data << " ";
				NodeStack.pop();
				p = p->rchild;
			}
		}
	}
	else 
		return;
}
// 实现层次遍历二叉树,输出遍历序列
void LayerOrder(BiTree T)
{
	BiTree p[100];
	int in = 0;
	int out = 0;
	p[in++] = T;
	while (in > out) {
		if (p[out]) {
			cout << p[out]->data << " ";
			p[in++] = p[out]->lchild;
			p[in++] = p[out]->rchild;
		}
         out++;
	}
}
// 求二叉树深度,返回深度值 
int Depth(BiTree T)
{
	int n = 0;
	int lift, right;
	if (!T) { n = 0; }
	else {
		lift = Depth(T->lchild);
		right = Depth(T->rchild);
		n = 1 + (lift > right ? lift : right);
	}
	return n;
}
// 统计二叉树结点个数,返回二叉树结点个数 
int Count(BiTree T)
{
	int n ,m;
	if (!T) return 0;
	if (!T->lchild && !T->rchild) return 1;
	else {
		m=Count(T->lchild);
		n=Count(T->rchild);
		return (m + n + 1);
	}
}
// 查找二叉树结点,在根指针为T的二叉树中,查找值为x的结点
//查找成功,p赋值为该结点指针,返回true;查找失败,p==NULL ,返回false 
bool Search(BiTree T, TElemType x, BiTree& p)
{
	if (T) {
		if (T->data == x) {
			p = T;
			return 1;
		}
		else
		{
			if (Search(T->lchild, x, p))
				return 1;
			else
				return (Search(T->rchild, x, p));
		}
	}
	else { p = NULL; return false; }
}

int main(void)
{
	BiTree T=NULL;
	int c = 0;
	int d = 0;
	int num = 0;
	TElemType elem;
	BiTree p = NULL;
	while (c != 10)
	{
		cout << endl << "1. 建立二叉树的二叉链表";
		cout << endl << "2. 前序遍历二叉树";
		cout << endl << "3. 中序遍历二叉树";
		cout << endl << "4. 后序遍历二叉树";
		cout << endl << "5. 非递归中序遍历二叉树";
		cout << endl << "6. 层次遍历二叉树";
		cout << endl << "7. 求二叉树深度";
		cout << endl << "8. 求二叉树结点个数";
		cout << endl << "9. 查找结点";
		cout << endl << "10. 退出";
		cout << endl << "选择功能(1~10):";
		cin >> c;
		switch (c)
		{
		case 1:
			CreateBiTree(T);
			break;
		case 2:
			PreOrderTraverse(T);
			break;
		case 3:
			InOrderTraverse(T);
			break;
		case 4:
			PostOrderTraverse(T);
			break;
		case 5:
			InOrderTraverseNon(T);
			break;
		case 6:
			cout << "层次遍历二叉树结果";
			LayerOrder(T);
			break;
		case 7:
			d = Depth(T);
			cout << "二叉树深度为:" << d;
			break;
		case 8:
			num = Count(T);
			cout << "二叉树结点个数为:" << num;
			break;
		case 9:
			cout << "请输入要查找的结点值:";
			cin >> elem;
			if (Search(T, elem, p))
				cout << "结点查找成功!结点左孩子为:" << p->lchild << "结点右孩子为:" << p->rchild;
			else
				cout << "查找失败!";
			break;
		case 10:
			cout << "结束操作" << endl;
			break;
		}
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值