数据结构——树(Tree)

一.树的定义及基本术语

1.树的定义:

树是n(n>=0)个节点的有限集:

  1. 有且仅有一个特定的称之为根的节点;
  2. 当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1、T2、…、Tn,其中每一个集合本身又是一棵树,并且称为根的子树。

如图所示:
在这里插入图片描述

2.基本概念

  1. 节点的度:节点拥有的子树数;
  2. 叶子节点(终端节点):度为0的节点;
  3. 分支节点:度不为0的节点;
  4. 树的度:树内各节点度的最大值;
  5. 孩子:节点子树的根称为该节点的孩子,该节点称为孩子的双亲
  6. 兄弟:同一双亲的节点之间互称兄弟;
  7. 层次:根为第0层,根的孩子为第1层,以此类推…;
  8. 深度:数中节点的最大层次;
  9. 森林:森林是m(m>=0)棵互不相交树的集合;
  10. 树分为有序树无序树

二.二叉树

1.定义

二叉树是节点的有限集合,它或者为空集,或者由一个根及两个互不相交的称为左右子树的二叉树组成。
二叉树的五种基本形态:
在这里插入图片描述

2.性质

  1. 在二叉树第i层上至多有 2 i 2^i 2i个节点(i>=0);
  2. 高为k(k>=0)的二叉树最多有 2 k + 1 − 1 2^{k+1}-1 2k+11个节点;
  3. 叶结点个数: n 0 n_0 n0,度为2的节点个数: n 2 n_2 n2,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1;
  4. 具有n个节点的完全二叉树的高度为 ⌊ l o g 2 n ⌋ \lfloor log_2 n\rfloor log2n;
  5. 满二叉树:一棵深度为k且有 2 k + 1 − 1 2^{k+1}-1 2k+11个节点的二叉树;
  6. 完全二叉树:将节点从上往下,从左向右依次编号,节点的编号与满二叉树的节点的编号一一对应;
  7. i i i个节点的左儿子的节点编号为 2 ∗ i 2*i 2i,右儿子为 2 ∗ i + 1 2*i+1 2i+1;

3.存储结构

1).顺序存储结构

用一组地址连续的存储单元依次自上而下、自左至右存储完全二叉树上的节点元素。
但这种结构仅适用于存储完全二叉树,存储其他形状的二叉树会浪费较大的空间。

#define MAX_SZIE 100
typedef TElemType SqBiTree[MAX_SIZE];
SqBiTree bt;

2).链式存储结构

节点结构如图:

lchildElementrchild

易证得:在含有n个节点的二叉链表中有n+1个空链域。
链式结构的存储表示:

typedef struct BiTNode{
    TElemType Element;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

4.建立二叉树

void BuildBiTree(BiTree& t) {
	char ch;
	cin >> ch;
	if (ch == ' ') {
		t = NULL;
		return;
	}
	else {
		t = new BiTNode;
		t->Element = ch - '0';
		BuildBiTree(t->lchild);
		BuildBiTree(t->rchild);
	}
	return;
}

5.遍历二叉树

1.) 先序遍历

递归方法:
void PreOrderBiTree(BiTree t){
    if(t!=NULL){
        cout<<t->Element;
        PreOrderBiTree(t->lchild);
        PreOrderBiTree(t->rchild);
    }
}
非递归方法:
void PreOrderBiTree_non_recursion(BiTree t) {
	vector<BiTNode*> stack;
	BiTNode* p = t;
	while (p || !stack.empty()) {
		if (p) {
			cout << p->Element << endl;
			stack.push_back(p);
			p = p->lchild;
		}
		else {
			p = stack.back();
			stack.pop_back();
			p = p->rchild;
		}
	}
}

2).中序遍历

递归方法:
void InOrderBiTree(BiTree t) {
	if (t != NULL) {
		InOrderBiTree(t->lchild);
		cout << t->Element << endl;
		InOrderBiTree(t->rchild);
	}
}
非递归方法:
void InOrderBiTree_non_recursion(BiTree t) {
	vector<BiTNode*> stack;
	BiTNode* p = t;
	while (p || !stack.empty()) {
		if (p) {
			stack.push_back(p);
			p = p->lchild;
		}
		else {
			p = stack.back();
			stack.pop_back();
			cout << p->Element << endl;
			p = p->rchild;
		}
	}
}

3).后序遍历

递归方法:
void PostOrderBiTree(BiTree t) {
	if (t != NULL) {
		PostOrderBiTree(t->lchild);
		PostOrderBiTree(t->rchild);
		cout << t->Element << endl;
	}
}
非递归方法:
void PostOrderBiTree_non_recursion(BiTree t) {
	vector<BiTNode*> stack;
	BiTNode* p = t, * r = NULL;
	while (p || !stack.empty()) {
		if (p) {
			stack.push_back(p);
			p = p->lchild;
		}
		else {
			p = stack.back();
			if (p->rchild != NULL && p->rchild != r) {
				p = p->rchild;
				stack.push_back(p);
				p = p->lchild;
			}
			else {
				cout << p->Element << endl;
				stack.pop_back();
				r = p;
				p = NULL;
			}
		}
	}
}

三.线索二叉树

线索二叉树的节点结构:

lchildLThreadvalRThreadrchild

LThread=0,代表lchild指向左儿子;
LThread=1,代表lchild指向节点的前驱;
RThread=0,代表rchild指向左儿子;
RThread=1,代表rchild指向节点的后继;
线索二叉树的存储表示:

typedef struct BiThrNode {
	TElemType Element;
	struct BiThrNode* lchild, * rchild;
	int LThread, RThread;
}BiThrNode,*BiThrTree;

线索化二叉树:

void InThreading(BiThrTree p, BiThrNode*& pre) {
	if (p) {
		InThreading(p->lchild, pre);
		if (p->lchild == NULL) {
			p->LThread = 1;
			p->lchild = pre;
		}
		if (pre!=NULL&&pre->rchild == NULL) {
			pre->RThread = 1;
			pre->rchild = p;
		}
		pre = p;
		InThreading(p->rchild, pre);
	}
}
//带头结点
void InOrderThreading(BiThrTree& Thrt, BiThrTree T) {
	Thrt = new BiThrNode;
	Thrt->LThread = 0, Thrt->RThread = 0;
	Thrt->rchild = Thrt;
	if (T == NULL) Thrt->lchild = Thrt;
	else {
		Thrt->lchild = T;
		BiThrNode* pre = Thrt;
		InThreading(T,pre);
		pre->rchild = Thrt, pre->RThread = 1;
		Thrt->rchild = pre;
	}
}
//不带头结点
void InOrderThreading( BiThrTree &T) {
	
	if (T != NULL)
	{
		BiThrNode* pre = NULL;
		InThreading(T, pre);
		pre->rchild = NULL, pre->RThread = 1;
	}
}

四.二叉排序树

1.定义

什么是二叉排序树?
二叉排序树或者是一棵空树,或者具有如下性质的二叉树:

1. 若它的左子树不空,则左子树上所有节点的值均小于它根节点的值;
2.若它的右子树不空,则右子树上所有节点的值均大于它根节点的值;
如图所示:在这里插入图片描述

2.实现

建立一个二叉排序树:

void InsertBST(BiTree &t,TElemType val){
	if(t==NULL){
		t=new BiTNode;
		t->Element=val;
		t->lchild=t->rchild=NULL;
	}else if(t->Element<val){
		InsertBST(t->rchild,val);
	}else if(t->Element>val){
		InsertBST(t->lchild,val);
	}
} 

####删除二叉排序树上值为val的节点:
如图所示:删除根节点
在这里插入图片描述

void Delete(BiTree& p){
	BiTree q,s;
	if(!p->rchild){
		q=p,p=p->lchild;
		delete q;
	}else if(!p->lchild){
		q=p,p=p->rchild;
		delete q;
	}else{
		q=p,s=p->lchild;
		while(s->rchild){
			q=s;
			s=s->rchild;
		}
		p->Element=s->Element;
		if(q!=p){
			q->rchild=s->lchild;
		}else{
			q->lchild=s->lchild;
		}
		delete s;
	}
}
void DeleteBST(BiTree &t,TElemType val){
	if(t==NULL) return;
	else{
		if(t->Element>val){
			DeleteBST(t->lchild,val);
		}else if(t->Element<val){
			DeleteBST(t->rchild,val);
		}else{
			Delete(t);
		}
	}
} 

五.平衡二叉树

1.定义

平衡二叉树又称AVL树。它或者是一棵空树,或者是具有下列性质的二叉树: 它的左子树和右子树都是平衡二叉树,且左右子树的深度之差的绝对值不超过1
在这里插入图片描述
在高度为h的AVL树中,最少节点数 S ( h ) = S ( h − 1 ) + S ( h − 2 ) + 1 S(h)=S(h-1)+S(h-2)+1 S(h)=S(h1)+S(h2)+1

2.实现

typedef struct AvlNode{
    ElementType Element;
    struct AvlNode *left,*right;
    int height;
}AvlNode,*AvlTree;

3.插入(旋转操作)

在对平衡二叉树插入操作时会打破平衡,因此我们需要对二叉树进行旋转使其再次平衡。
让我们把必须重新平衡的节点叫做 a a a。这种不平衡可能出现在下面四种情况中:

  1. a a a的左儿子的左子树进行一次插入;
  2. a a a的左儿子的右子树进行一次插入;
  3. a a a的右儿子的左子树进行一次插入;
  4. a a a的右儿子的左子树进行一次插入;

第一种情况和第四种情况通过对树的一次单旋转而完成调整;第二种和第三种情况通过对树的一次双旋转来处理。

单旋转

情形1:对k2的左儿子的左子树进行一次插入;

在这里插入图片描述
实现:

AvlNode* SingleRotateWithLeft(AvlNode* k2){
    AvlNode *k1;
    k1=k2->left;
    k2->left=k1->right;
    k1->right=k2;
    k2->height=max(height(k2->left),height(k2->right))+1;
    k1->height=max(height(k1->left),k2->height)+1;
    return k1;
}
情形4:对k1的右儿子的右子树进行一次插入;

在这里插入图片描述
实现:

AvlNode* SingleRotateWithRight(AvlNode* k1){
    AvlNode *k2;
    k2=k1->right;
    k1->right=k2->left;
    k2->left=k1;
    k1->height=max(height(k1->left),height(k1->right))+1;
    k2->height=max(k1->height,height(k2->right))+1;
    return k1;
}

双旋转

情形2: 对k3的左儿子的右子树进行一次插入;

在这里插入图片描述
实现:

AvlTree_Position DoubleRotateWithLeft(AvlTree K3){
	K3->lchild=SingleRotateWithRight(K3->lchild);
	return SingleRotateWithLeft(K3);
}
情形3:对k3的右儿子的左子树进行一次插入;

在这里插入图片描述
实现:

AvlTree_Position DoubleRotateWithRight(AvlTree K3){
	K3->rchild=SingleRotateWithLeft(K3->rchild);
	return SingleRotateWithRight(K3);
}

向平衡二叉树中插入一个节点:

AvlTree_Position AvlTree_Insert(AvlTreeElementType X,AvlTree T){
	if(T==NULL){
		T=new AvlTreeNode;
		T->Element=X;
		T->height=0;
		T->lchild=T->rchild=NULL;
		return T;
	}else if(X<T->Element){
		T->lchild=AvlTree_Insert(X,T->lchild);
		if(abs(AvlTree_Height(T->lchild))-AvlTree_Height(T->rchild)>1){
			if(X<T->lchild->Element){
				T=SingleRotateWithLeft(T);
			}else{
				T=DoubleRotateWithLeft(T);
			}
		}
	}else if(X>T->Element){
		T->rchild=AvlTree_Insert(X,T->rchild);
		if(abs(AvlTree_Height(T->lchild)-AvlTree_Height(T->rchild))>1){
			if(X>T->rchild->Element){
				T=SingleRotateWithRight(T);
			}else{
				T=DoubleRotateWithRight(T);
			}
		}
	}
	T->height=max(AvlTree_Height(T->lchild),AvlTree_Height(T->rchild))+1;
	return T;
}

六.HuffmanTree

关于HuffmanTree,我参考了CSDN中的文章。https://blog.csdn.net/qq_29542611/article/details/79334308

完结。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值