【数据结构-陪读笔记】第六章:树

逻辑链条

在这里插入图片描述

1.树的定义

1.术语清单

将书中所有的加粗的基本概念摘录出来了,方便自查。

  1. 子树
  2. 树的度
  3. 叶子
  4. 孩子
  5. 双亲
  6. 兄弟
  7. 祖先
  8. 子孙
  9. 层次
  10. 堂兄弟
  11. 深度/高度:从1开始,从上往下。
  12. 有序树/无序树
  13. 森林

2.二叉树

二叉树的左右结点是不能调换的,换了就不是同一棵树了。

性质

二叉树可以视为一种公比为2的等比数列
将《数据结构》中的5个基本性质都简单证明了一遍。
在这里插入图片描述

特殊二叉树

  1. 满二叉树: 高度是h,同时有2^h - 1个结点。(判断:全是结点)
  2. 完全二叉树: 按照满二叉树进行数,序号和位置可以按照满二叉树位置对上。

二叉树的应用

  1. 递归版本: 什么序,根在哪。
  2. 非递归版本:
//非递归先序遍历: 根左右
void PreOrder(BiTree T){
	stack<BiTree> s;
	BiTree p = T;
	while(p != NULL ||s.empty() == false){//当p的值不为空的时候 或者  栈不空的时候 
		while(p != NULL){
			printf("%c " , p->data);
			s.push(p);
			p = p->lchild;
		}
		if(s.empty() == false){
			s.pop();
			p = p->rchild; 
		}
	}
}

中序遍历:

void InOrder(BiTree T){
	stack<BiTree> s;
	BiTree p = T;
	while(p != NULL || s.empty() == false){
		s.push(p);
		p = p->lchild;//这个循环里面一路找左结点// 
	}
	//出来的时候一定是没有左结点的// 
	p = s.top();//此时的栈顶必定是这个左结点的中结点// 
	s.pop();
	printf("%c " , p->data);
	p = p->rchild;
}

后序遍历:

void PostOrder(BiTree T){
	stack<BiTree> s;
	BiTree p , r = NULL;//r的意思是辅助指针, 
	while(p != NULL || s.empty() == false){
		if(p != NULL){
			s.push(p);
			p = p->lchild;//这个地方和中序遍历一样,一开始直接找最左边的左结点// 
		}	
		else{
			p = s.top();//指针指回栈顶,当前栈顶是最后的左下角的左指针的中节点
			if(p->rchild != NULL && p->rchild != r)//右结点不是空的并且尚未访问过 
				p = p->rchild;//那么指向这个右结点 
			else{//说明没有右结点,或者是右结点已经访问过了 
				s.pop();//弹出这个中结点 
				printf("%c" , p->data);
				r = p;//r指向访问过的右子树根节点// 
				p = NULL;//到这一步的时候,变成NULL是为了走==NULL分支再给p赋值//	
			}
		} 
	} 
}

层序遍历:

void LevelOrder(BiTree T){
	queue<BiTree> q;
	BiTree p;
	q.push(T);//头节点放进去// 
	while(q.empty() == false){
		p = q.front();
		q.pop();
		printf("%c " , p->data);
		if(p->lchild != NULL){
			q.push(p->lchild);
		}
		if(p->rchild != NULL){
			q.push(p->rchild);
		}
	}
}

线索二叉树:

ltaglchilddatarchildrtag

1.左子树为空,指向其前驱;右子树为空,指向其后继。先写出来它的序列,然后串起来即可。
2.既可橡树一样遍历,也可以通过指针直接遍历;但是在线索化之后,后序线索二叉树也会出现问题,需要栈来去辅助,原因是当后序遍历是左右根,导致右结点访问完之后往回找的时候因为已经占位指向孩子的右结点了,无法在指向父结点了。
 
 

树&森林

1.树的表示

双亲表示法

#include<iostream>
#define Maxsize 100 
using namespace std;
 
typedef char ElemType;
 
//树的结点定义 
typedef struct TNode{
	ElemType data;
	int parent;
}TNode;
 
//树的定义// 
typedef struct{
	TNode nodes[Maxsize];
	int n;//结点的数量// 
}Tree;

孩子表示法

#include<iostream>
#define Maxsize 100 
using namespace std;
 
typedef char ElemType;
 
//孩子结点的定义 
typedef struct CNode{
	int child;	//在表中的数组的下表// 
	struct CNode *next; //这个是一个结构 
}CNode , *Child;
 
//树的所有数据表
typedef struct{
	ElemType data;
	Child firstchild; // 指向的第一个孩子的数据 // 
}TNode; 
 
//树的定义// 
typedef struct{
	TNode nodes[Maxsize];
	int n;//结点的数量// 
}Tree; 

孩子兄弟表示法

#include<iostream>
#define Maxsize 100 
using namespace std;
 
typedef char ElemType;
 
//孩子结点的定义 
typedef struct CSNode{
	ElemType data;
	struct CNode *firstchild , *rightbro; //左手孩子,右手兄弟 
}CSNode;

 

2.树,森林转换

左孩右兄
 

3.树的遍历

森林二叉树
先根遍历先序遍历先序遍历
后根遍历中序遍历中序遍历

 

应用

1.并查集

并查集用于Kruskal算法,借鉴了树的思想,方便合并同类。

//初始化
void Init(){
	for(int i = 0 ; i < n ; i ++)
		father[i] = -1;
}

//并
void Union(int a , int b){
	if(a!= b){
		father[a] = b;
	}
}

//查
int Findfather(int father[] , int x){
	while(father[x] > 0){
		x = S[x];
	}
	return x;
}

 

2.Binary Search Tree

左 < 根 < 右,中序遍历可得一个递增序列。
查找操作

BSTNode *BST_Search(BiTree T , ElemType key , BSTNode *&p){
	p = NULL;
	while(T != NULL && key != T->data){
		p = T;
		if(key < T->data)	T = T->lchild;
		else T = T->rchild;
	}
	return T;
}

插入

int BST_Insert(BiTree &T , KeyType k){
	if(T == NULL){	//空树建立新节点
		T = (BiTree)malloc(sizeof(BSTNode));
		T->key = k;
		T->lchild = T->rchild = NULL;
	}
	else if(k == T->key)	//如果这个数存在
		return 0;
	else if(k < T->key)		//比这个小左拐
		return BST_Insert(T->lchild , k);
	else 					//比这个大右拐
		return BST_Insert(T->rchild , k);
}

构造

void Creat_BST(BiTree &T , KeyType str[] , int n){
	T = NULL;
	int i = 0;
	while(i < n){
		BST_Insert(T , str[i]);
	}	
}

删除
此处不涉及代码,只涉及思想。
左空补右,右空补左,左右不空,中序右补。(交换后单树调整。)
查找效率: 可能出现单边树;静态查找表用顺序表,动态查找表,二叉排序树。ASL会求,详见ASL树问题。
 

3.Balance Binary Tree

平衡因子: |左树高 - 右树高|不超过1。
插入: LL,RR,LR,RL。哪里不平衡,哪里就调整,从下往上。(细节看书,不做深究。)
查找: BST相同。
 

4.Huffman Tree

WPL最小,即为哈夫曼树。
WPL的求法: 树的WPL = ∑(叶结点权值 * 路径数)。
构造: 池子拿出最小两个点结合(权值相加),结合的结点放回池子里再次操作,得一棵树。权值越小,离根越远;n个结点最后树有2n - 1个结点,(结合一次多一个结点)
编码: 左0右1。可得最短二进制前缀编码,必是最优,但是不一定唯一。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值