树和二叉树

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h> 


/* run this program using the console pauser or add your own getch, system("pause") or input loop */

#define MaxSize 100

//二叉链表
typedef struct node{
	int data;				//数据域 
	struct node * lchild;	//左孩子 
	struct node * rchild;	//右孩子 
}BTNode,BiTree;

//顺序栈
typedef struct{
	BTNode * data[MaxSize];
	int top;
}SqStack; 

//环形队列
typedef struct{
	BTNode *data[MaxSize];	//存放队中元素 
	int front,rear;			//队头 队尾指针 
}SqQueue; 

先序遍历二叉树

void PreOrder(BTNode *b){
	if(b!=NULL){
		printf("%d",b->data);	//根 
		PreOrder(b->lchild);	//左 
		PreOrder(b->rchild);	//右 
	}
}

中序遍历

void  InOrder(BTNode *b){
	if(b!=NULL){
		InOrder(b->lchild);
		printf("%d",b->data);
		InOrder(b->rchild); 
	}
}

后序

void PostOrder(BTNode *b){
	if(b!=NULL){
		PostOrder(b->lchild);
		PostOrder(b->rchild);
		printf("%d",b->data);
	}
} 

计算所有二叉树个数

/*递归模型 
			f(b) = 0	//b为NULL 
			f(b) = f(b->lchild) + f(b->rchild) + 1;
*/		 
int Nodes(BTNode *b){
	if(b==NULL){
		return 0;
	}else{
		return Nodes(b->lchild) + Nodes(b->rchild)+1;
	}
} 

非递归遍历二叉树

/*	中序非递归遍历
					建立一个栈
					根节点进栈	遍历左子树
					根节点出栈 	输出根节点	遍历右子树 
	 */
 void InOrder2(BiTree T){
 	InitStack(S);
 	BiTree p = T;
 	while(p!=NULL||IsEmpty){
 			Push(S,p);	//p不为空 	根节点入栈
			InOrder2(p->lchild);	//遍历左子树                                                                                                                                        
		 }else{
		 	Pop(S,p);	//栈顶元素出栈	
			printf("%d",p->data);	//访问出栈节点
			InOrder2(p->rchild);	//访问右子树 
		 }
	 } 
 }   
                       
 //非递归先序遍历 
 void PrePrder2(BiTree T){
 	InitStack(S);
 	BiTree p = T;
 	while(p!=NULL||IsEmpty(S)){
 		if(p){
 			printf("%d",p->data);
 			Push(S,p);
			 p=p->lchild; 
		 }else{
		 	Pop(S,p);
		 	p=p->rchild;
		 }
	 }
 }



//非递归层次遍历
/*
	根节点入队
	
	队列不空时循环:从队列中出列一个节点	*p 访问它
	
		若它有左孩子	左孩子进队
		若它有右孩子	有孩子进队
		
		*/ 
void LevelOrder(BTNode *b){
	BTNode *p;
	SqQueue *qu;	//初始化队列 
	enQueue(qu,b);	//根节点指针入队
	while(!QueueEmpty(qu)){	//队列不为空时 
		deQueue(qu,p);				//根节点出队
		printf("%c",p->data);		//访问根节点 
		if(p->lchild!=NULL)			//左右孩子入队 
			enQueue(qu,p->lchild);
		if(p->rchild!=NULL)
			enQueue(qu,p->rchild); 
	} 
} 

先序遍历建立二叉链表

/*	
	若输入为# 根节点为空
	否则
		为新的根节点分配内存空间
		赋值
		建立他的左子树
		建立他的右子树
*/ 
Status CreateBiTree(BiTree &T){
	char ch;
	scanf(&ch);
	if(ch=='#')
		T == NULL;
	else{
		if(!(T=(BiTNode *)malloc(sizeof(BiTNode))))
			exit(OVERFLOW);
		T->data = ch;	//生成根节点 
		CreateBiTree(T->lchild);	//构造左子树 
		CreateBitree(T->rchild);	//构造右子树 
	}
	return OK; 
 
} 

二叉树遍历算法的应用 复制二叉树

/*	如果是空树,递归结束
	否则,申请新节点空间 复制根节点
	递归复制左子树
	递归复制右子树
*/
int Copy(BiTree T,BiTree &NewT){
	if(T==NULL){
		NewT = NULL;
	}else{
		NewT = (BiTree *)malloc(sizeof(BiTree));
		NewT->data = T->data;
		Copy(T->lchild,NewT->lchild);
		Copt(T->rchild,NewT->rchild); 
	}
}

计算二叉树的深度

/*
	计算二叉树的深度
		如果树为空则返回0
		不为空
			计算它的左子树的深度
			计算它的右子树的深度
			比较左右子树大小
				将大的值+1返回(因为根节点算1层,所以+1)
*/
int Depth(BiTree T){
	int m;
	if(T==NULL)	
		return 0;
	else{
		m = Depth(T->lchild);
		m = Depth(T->rchild);
		//return m>n?m+1:n+1 ;	//返回最大的+1 
		if(m>n) 
			return (m+1);
		else
			return (n+1); 
	}
}
 

计算二叉树节点总数

	/*
	如果左子树为空 则节点个数为0
	否则,节点个数为左子树的节点个数+右子树的节点个数+1(1表示根节点) 
	*/ 
int NodeCount(BiTree T){
	int m;
	if(T==NULL)	
		return 0;
	else{
		return NodeCount(T->lchild) + SunCount(T->rchild) + 1; 
	}
}

计算叶子节点个数

/*	
	
		如果树为空	则叶子节点数为0
		否则	
			如果是叶子节点	则叶子节点数为1
			否则 
				为左子树的叶子节点树+右子树叶子节点数 
*/
int NodeLCount(BiTree T){
	if(T==NULL)
		return 0;
	else
		if(T->lchild==NULL&&T->rchild==NULL)
			return 1;
		else
			return NodeLCount(T->lchild) + NodeLCount(T->rchild); 
} 

线索二叉树——利用链表中的空指针域:

/*
	
		如果某个节点的左孩子为空,则将空的左孩子指针域改为指向其前驱;
		如果某个节点的右孩子为空,则将空的右孩子指针改为指向其后继; 
																		——线索	Threaded binary tree 
*/
		
//线索二叉树
typedef struct ThreadNode{
	char data;	//数据元素 
	struct ThreadNode *lchild,*rchild;	
	int ltag,rtag;
}ThreadNode,*ThreadTree;

//线索化访问操作 
void visit(ThreadNode *q){
	if(q->lchild==NULL){
		q->lchild=pre;
		q->ltag=1;
	}
	if(pre!=NULL&&pre->rchild==NULL){
		pre->rchild = q;
		pre->rtag=1;
	}
	pre = q;
}

中序遍历对二叉树线索化的递归算法如下

 void  InThread(ThreadTree &p,ThreadTree &pre){
 	if(p!=NULL){
 		//递归线索化左子树	
 		InThread(p->lchild,pre);
 		
 		
 		//左子树为空,建立前驱线索 
	 	if(p->lchild==NULL){
 			p->lchild = pre;
 			p->ltag = 1;
		 }
		//建立前驱节点的后继线索 
		 if(pre!=NULL&&pre->rchild==NULL){
		 	pre->rchild = p;
		 	pre->rtag = 1;
		 }
		//标记当前节点为刚刚访问过的节点,递归线索话右子树 
		 pre = p;
		 InThread(p->rchild,pre);
	
	}
 } 

//通过中序遍历建立中序线索二叉树的主过程
void CreateInThread(ThreadTree T){
	ThreadTree pre = NULL;
	if(T!=NULL){
		InThread(T,pre);	//非空二叉树线索化 
		if(pre->rchild==NULL)	//处理最后一个节点  
			pre->rtag = 1;
	}
} 



先序遍历二叉树,一遍遍历一边线索化


void PreThread(ThreadTree T){
	if(T!=NULL){
		visit(T);
//先序遍历艾蒂摩里转圈圈问题,第一次出现空左子树,由于是先序,所以其左指针已经线索化,指向其前驱节点,若不判断指针标记则出现死循环 
		if(T->ltag==0)	
			PreThRead(T->lchild);
		Prethread(T->rchild);
	}
} 

在中序线索二叉树中找到指定节点*p的中序后继next

/*中序线索二叉树找中序后继
 	
 	在中序线索二叉树中找到指定节点*p的中序后继next
	 
	 1.若p->ltag==1	则next = p -> rchild;
	 2.若p->rtag == 0 即为其后继 

*/
// 1.找到以p节点为根的子树中,第一个被中序遍历的节点 即最左子树 
ThreadNode *Fristnode(ThreadNode *p){
	//循环找到最坐下节点(不一定是叶节点)
	while(p->ltag==0) p=p->lchild;
	retuen p; 
} 

//在中序线索二叉树中找到节点p的后继结点
ThreadNode *Nextnode(ThreadNode *p){
	//右子树中最左下节点
	if(p->rtag==0)	return Fristnode(p->rchild);
	else
		return p->rchild;	//rtag==1 直接返回后继线索 
} 

//在先序线索二叉树中找到节点p的后继结点		1.若有左子节点,即为他的后继,否则为右 
ThreadNode *NextnodePre(ThreadNode *p){
	if(p->lchild!=NULL)
		return p->lchild;
	else
		return p->rchild;
			
} 

在后序线索二叉树中找到指定节点*p的后续前驱pre
/*
若p->ltag == 1,则 pre = p->lchild
若p->ltag == 0,
若有右孩子,即为前驱
否则为左孩子

在后序线索二叉树中找到指定节点*p的后续前驱pre

若p->rtag == 1,则next = p->rchild;
若p->rtag == 0
	后序遍历中,左右子树中的节点只有可能是跟的前驱,不可能是后继
		
		1.若能找到p的父节点且p是右孩子	其是其后继
		若能找到p的父节点,p是其左孩子,右兄弟为空  
													则后继为父节点
													否则为右兄弟 

*/

//树的存储结构——双亲表示法
#define MAX_TREE_SIZE 100

//树的节点定义
typedef struct{
char data; // 数据元素
int parent; // 双亲位置域
}PTNode;

//树的类型定义
typedef struct{
PTNode nodes[MAX_TREE_SIZE]; //双亲表示
int n; //节点数
}PTree;

//树的存储结构——孩子兄弟表示法
typedef struct CSNode{
char data; //数据域
struct CSNode *fristchild,*nextsibling; //第一个孩子和右兄弟指针
}CSNode,*CSTree;

//哈夫曼树
typedef struct{
char data;
double weight; //权重
int parent; //双亲节点
int lch; //左孩子
int rch; //右孩子
}HTNode;

//构造哈夫曼树——哈夫曼算法 初始化双亲孩子节点为0 设置初始节点权重
void CreatHuffmanTree(HuffmanTree HT,int n){

int m = 2*n-1;		//数组共2*n-1个元素 
if(n<=1)
	return ;
HTNode HT = (HTNode *)malloc(sizeof(HTNode)*m+1);
if(HT==NULL) 
	return ;
for(i = 1;i<=m;i++){
	HT[i].lch=0;
	HT[i].rch=0;
	HT[i].parent=0;
}

for(i = 1;i<=n;i++)
	scanf("%d",&HT[i].weight);

}

//求哈夫曼编码
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){

//从叶子节点到根逆向求每个字符的哈夫曼编码,存储在编码表HC中 
HC = new char *[n+1];	//存放哈夫曼编码 
cd = new char[n];		//作为零时存放编码的动态数组
cd[n-1] = '\0';

//逐个字符求haffman编码 
for(i =1;i<=n;i++){
	start = n-1;
	c = i;
	f = HT[i].parent;
	//从叶子节点开始向上回溯 
	while(f!=0){  
		--start;
		if(HT[f].lchild==c)			//c节点是左孩子,生成0 右孩子生成1 
			cd[start]='0';	
		else
			cd[start]='1';
			
		c = f;						
		f = HT[f].parent; 
	}
	
	HC[i] = new char[n-start]; //为第i个字符编码分配空间
	strcpy(HC[i],&cd[start]);	//将求的编码从零时空间复制到HC的当前运行中  
	 
} 
 delete cd;  
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值