#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;
}