数据结构(C语言)二叉树的表示和实现

二叉树

二叉树的顺序存储

按满二叉树的结点层次编号,依次存放二叉树中的数据元素。

若有空节点则不能连续存储,空出位置!

二叉树顺序存储缺点

最坏情况:右单支树,深度为k的且只有k个结点的单支树需要长度为2k-1的一维数组。
特点:结点间蕴含在其存储位置中浪费空间,适合存满二叉树和完全二叉树。

二叉树的链式存储

二叉链表
typedef struct BiNode {
	TElemType data;
	struct BiNode* lchild, * rchild;//左右孩子指针
}BiNode,*BiTree;
三叉链表

再增加一个parent指针域指向双亲结点

typedef struct TriTNode {
	TElemType data;
	struct TriTNode* child, * parent, * rchild;
}TriTNode,*TriTree;

遍历二叉树

  • 遍历定义 :顺着某一条搜索路径巡访二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次。
  • 遍历目的 :得到树中所有结点的一个线性排列。
  • 遍历用途 :它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心。
遍历方法

假设: L :遍历左子树 D :访问根节点 R :遍历右子树
规定先左后右:
DLR ——先序遍历
LDR ——中序遍历
LRD ——后序遍历

先序遍历 中序遍历 后序遍历
1.访问根结点 2.先序遍历左子树 3.先序遍历右子树 1.中序遍历左子树 2.访问根结点 3.中序遍历右子树 1.后序遍历左子树 2.后序遍历右子树 3.访问根节点

这里是二叉树的遍历方法,当初学二级公共基础知识(前面十分)的题就不会,点我点我!!!

复制一颗二叉树

Status Copy(BiTree T, BiTree& NewT)
{
	if (T == NULL)
	{
		NewT = NULL;
		return OK;
	}
	else
	{
		NewT = (BiTNode*)malloc(sizeof(BiTree));
		NewT->data = T->data;
		Copy(T->lchild, NewT->lchild);
		Copy(T->rchild, NewT->rchild);
		return OK;
	}
}//Copy

计算二叉树的深度

int Depth(BiTree T)
{
	int m = 1;
	int n = 1;
	if (T == NULL)
		return 0;
	else
	{
		m = Depth(T->lchild);
		n = Depth(T->lchild);
		if (m > n)
			return (m + 1);
		else
			return (n + 1);
	}
}//Depth

计算二叉树的结点个数

int NodeCount(BiTree T)
{
	if (T == NULL)
		return 0;
	else
		return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}//NodeCount

计算二叉树的叶子结点

int LeafCount(BiTree T)
{
	if (T == NULL)
		return 0;
	if (T->lchild == NULL && T->rchild == NULL)
		return 1;
	else
		return LeafCount(T->lchild) + LeafCount(T->lchild);
}//LeafCount

完整代码

#pragma warning(disable:4996)
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

//Status是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char TElemType;

typedef struct BiNode {
	TElemType data;
	struct BiNode* lchild, * rchild;//左右孩子指针
}BiTNode, * BiTree;

Status CreateBiTree(BiTree& T);
//按先序次序输入二叉树中结点的值(一个字符),@字符表示空树
//构造二叉链表表示的二叉树T
Status Copy(BiTree T, BiTree& NewT);
//复制一颗二叉树
int Depth(BiTree T);
//计算二叉树的深度
int NodeCount(BiTree T);
//计算二叉树的结点

Status CreateBiTree(BiTree& T)
{
	char ch;
	scanf("%c", &ch);
	if (ch == '@')
		T = NULL;
	else
	{
		T = ((BiTNode*)malloc(sizeof(BiTNode)));
		if (!(T = (BiTNode*)malloc(sizeof(BiTNode))))
			exit(OVERFLOW);
		T->data = ch;
		CreateBiTree(T->lchild);//构造左子树
		CreateBiTree(T->rchild);//构造右子树
	}
	return OK;
}//CreateBiTree
Status Copy(BiTree T, BiTree& NewT)
{
	if (T == NULL)
	{
		NewT = NULL;
		return OK;
	}
	else
	{
		NewT = (BiTNode*)malloc(sizeof(BiTree));
		NewT->data = T->data;
		Copy(T->lchild, NewT->lchild);
		Copy(T->rchild, NewT->rchild);
		return OK;
	}
}//Copy
int Depth(BiTree T)
{
	int m = 1;
	int n = 1;
	if (T == NULL)
		return 0;
	else
	{
		m = Depth(T->lchild);
		n = Depth(T->lchild);
		if (m > n)
			return (m + 1);
		else
			return (n + 1);
	}
}//Depth
int NodeCount(BiTree T)
{
	if (T == NULL)
		return 0;
	else
		return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}//NodeCount
int LeafCount(BiTree T)
{
	if (T == NULL)
		return 0;
	if (T->lchild == NULL && T->rchild == NULL)
		return 1;
	else
		return LeafCount(T->lchild) + LeafCount(T->lchild);
}//LeafCount
int main()
{
	BiTree(T);
	CreateBiTree(T);
	printf("二叉树深度为:%d\n", Depth(T));
	printf("结点个数为:%d\n", NodeCount(T));
	printf("叶子结点个数为:%d", LeafCount(T));
	return 0;
}

线索二叉树(Threaded Binary Tree)

当用二叉链表作为二叉树的存储结构时,可以很方便地找到某个结点的左右孩子;但一般情况下,无法直接找到该结点在某种遍历序列中的前驱和后继结点。

提出问题

如何寻找特定遍历序列中二叉树结点的前驱和后继

探讨空指针数

具有n个结点的二叉链表中,一共有2n个指针域;因为n个节点中有n-1个孩子,即2n个指针域中,有n-1个用来指示结点的左右孩子,其余n+1个指针域为空。

解决方案

如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;如果某结点的右孩子为空,则将空的右孩子指针域改为指向其后继。为了区分lchild和rchild到底是指向孩子的指针,还是指向前驱或者后继的指针,对二叉链表中每个结点增设两个标志域Itag和rtag,并约定:

I t a g = 0 Itag=0 l c h i l d lchild指向该结点的左孩子
I t a g = 1 Itag=1 l c h i l d lchild指向该结点的前驱
r t a g = 0 rtag=0 r c h i l d rchild指向该结点的右孩子
r t a g = 1 rtag=1 r c h i l d rchild指向该结点的前驱

猜你喜欢

转载自blog.csdn.net/qq_44864262/article/details/107163957