二叉树链式存储结构
二叉链表
typedef struct BTNode{
ElemType data;
struct BTNode *lchild, *child;
}BTNode,*BiTree;
三叉链表
typedef struct BTNode{
ElemType data;
struct BTNode *lchild, *child, *pasrent;
}BTNode,*BiTree;
二叉树的遍历
1. 层序遍历
链表形式
void LevelOrder(BiTree T){
InitQueue(Q); //初始化空队列
BiTree p;
EnQueue(Q,T); //根入队列
while(!QueueEmpty(Q)){
//队列非空保持执行
DeQueue(Q,p); //队头结点出队
if(p!==NULL){
visit(p->data);
EnQueue(Q,p->lchild);
EnQueue(Q,p->rchild); //左右子树入队
}
}
}
数组形式(数组q[]+头尾front,rear)
void LevelOrder(BiTree T){
const int MAXSIZE=1024;
BiTree q[MAXSIZE];
int front,rear;
front=rear=0; //队列初始化
q[rear]=T; //根入队列
rear=(rear)%MAXSIZE;
while(front!=rear){
//非空则循环
p=q[front];
front=(front+1)%MAXSIZE;
if(p){
//p非空则左右子树入队
visit(p->data);
q[rear]=p->lchild;rear=(rear+1)%MAXSIZE;
q[rear]=p->rchild;rear=(rear+1)%MAXSIZE;
}
}
}
2.先序遍历
递归
void Preorder(BiTree T){
if(T!=NULL){
visit(T);
Preorder(T->lchild);
Preorder(T->rchild);
}
}
非递归(借助栈实现)
同中序遍历的顺序,将访问节点位置改为第一次指向该结点时
void Preorder(BiTree T,VisitFunc visit){
InitStack(S);
p=T;
while(p||!StackEmpty(S)){
if(p){
visit(p);
Push(S,p);
p=p->lchild;
}
else{
Pop(S,p);
p->rchild;
}
}
}
3.中序遍历
递归
void Inorder(BiTree T){
if(T!=NULL){
Inorder(T->lchild);
visit(T);
Inorder(T->rchild);
}
}
非递归
指针p从根开始,沿左子树向下移动并入栈保存
void InOrder(BiTree T,VisitFunc vist){
InitStack(S);
p=T;
whlie(p||!StackEmpty(S)){
if(p){
Push(S,p);
p=p->lchild;
}
else{
Pop(S,p);
visit(p); //中序访问结点位置
p=p->rchild;
}
}
}
4.后序遍历
递归
void Postorder(BiTree T){
if(T!=NULL){
Postorder(T->lchild);
Postorder(T->rchild);
visit(T);
}
}
非递归
只有从右子树返回时才访问根节点,需增加一个栈标记到达结点的次序
void PostOrder(BiTree T,VisitFunc visit){
InitStack(S),InitStack(tag);
p=T;
while(p||!StackEmpty(S))
{
if(p){
Push(S,p);Push(tag,1); //第一次入栈
p=p->lchild;
}
else{
//------------------------
Pop(S,p);Pop(tag,f);
if(f==1){
//左子树返回,二次入栈,p指向右子树
Push(S,p);Push(tag,2);
p=p->rchild;
}
else{
//从右子树返回,二次出栈,访问根节点,p指向上层
visit(p);
p=NULL;//为下次正常使用p,需要重置
}
} //-----------------------------
}
}
线索二叉树
存储结构
typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild,*rchild; //左右孩子指针
int ltag,rtag; //左右线索
}ThreadNode,*ThreadThree;
tag=0表示孩子结点,tag=1表示前驱后继
中序遍历对二叉树线索化(递归)
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->rcild=p; //建立前驱结点的后继
pre->rtag=1;
}
pre=p; //标记当前结点为刚访问的结点
InThread(p->rchild,pre); //递归,线索化右子树
}
}
主程序:
void CreatInTHread(ThreadTree T){
ThreadTree pre=NULL;
if(T!=NULL){
InThread(T,pre); //非空二叉树线索化
pre->rchild=NULL; //线索化二叉树
pre->rtag=1; //处理一遍后的最后一个结点
}
}
中序线索二叉树遍历
1求中序线索树中中序列的第一个结点
ThreadNode *Firstnode(ThreadNode *p){
while(p->ltag==0) p=p->lchild; //最坐下结点(不一定是叶子结点)
return p;
}
2求结点P在中序序列的后继
ThreadNode *Nextnode(ThreadNode *p){
if(p->rtag==0) return Firstnode(p->rchild);
else return p->rchild; //rtag==1时直接返回后继线索
}
3不含头结点的中序线索二叉树的中序遍历算法
void Inorder (ThreadNode *T){
for(ThreadNode *p=Firstnode(T);P=NULL;p=Nextnode(p))
visit(p);
}
树、森林
双亲表示法结构
#define MAX_TREE_SIZE 100
typedef struct{
ElemType data;
int parent;
}PTNode;
typedef struct{
PTNode nodes[MAX_TREE_SIZE];
int n;
}PTree;
孩子兄弟表示法结构
typedef struct CSNode{
ElemType data;
struct CSNode *firstchild, *nextsilbling; //第一个孩子和右兄弟指针
}CSNode,*CSTree;
二叉排序树
查找
递归:(思路:1.若为空,则找不到2.先于根比较,若小于根找左子树,反之右子树)
BstTree BstSearch(BiTree T,ElemType x){
if(T==NULL)
return NULL;
else if(T->data==x)
return T;
else if(x < T->data)
return BstSearch(T->lchild,x);
else
return BstSearch(T->rchild,x);
}
非递归
BstNode *BstSearch(BiTree T,ElemType x){
while(T!=NULL && key!=T->data){
//树空或等于当前节点,结束循环
if(key < T->data) T=T->lchild; //小于当前,去左子树找
else T=T->rchild; //大于当前去右子树
}
return T;
}
插入
int BST_Insert(BiTree &T,KeyType K){
if(T==NULL){
// 若当前T所指的树为空,则新插入的作为根结点
T=(BiTree)malloc(sizeof(BSTNode));
T->key=k;
T->lchild=T->rchild=NULL;
return 1; //返回1 表示插入成功
}
else if(k==T-key)
return 0;
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; //初始T为空
int i=0;
while(i,n){
//依次将每个关键字插入到二叉排序树中
BST_Insert(T,str[i]);
i++;
}
}
(哈弗曼树)
存储结构
typedef struct{
unsigned int weight;
unsigned parent,lchild,rchild;
}HTNode, *HuffmanTree; //动态分配数组存储哈弗曼树
typedef char * *HuffmanCode;//动态分配数组存储哈弗曼编码表
求哈夫曼编码
从叶子结点开始到根逆向处理
//w存放n个字符的权值(均>0),构造哈弗曼树HT,并求出n个字符的哈夫曼编码HC
void HuffmanCoding (HuffmanTree &HT,HuffmanCode &HC,int *w,int n){
if(n<=1) return;
m*2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeif(HTNode));//0号单元未用
for(p=HT+1,i=1;i<=n;++i,++p,++w) *p={
*w,0,0,0};
for(;i<=m;++i,++p) *p={
0,0,0,0};
for(i=n+1;i<=m;i++){
//建哈弗曼树
//在HT[1..i-1]选择parent为0且weight最小的两个结点,其序号分别为s1、s2
Select(HT,i-1,s1,s2);
HT[s1].parent=i;HT[s2].parent=i;
HT[i].lchild=s1;HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
//----从叶子到根逆向求每个字符的哈夫曼编码----
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//分配n个字符编码的头指针向量
cd=(char*)malloc(n*sizeof(char));分配求编码的空间
cd[n-1]="\0";//编码结束符
for(i=1;i<=n;++i){
//逐个字符求哈夫曼编码
start=n-1; //编码结束符位置
for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent) //从叶到根逆向求码
if(HT[f].lchild==c) cd[--start]='0';
else cd[--start]="1";
HC[i]=(char *)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间
strcpy(HC[i],&cd[start]);//从cd复制编码到HC
}
free(cd); //释放工作空间
}
从根出发求各个叶子结点的(p148)
HC = (HuffmanCode)malloc((n+1)*sizeof(char *));
p = m; cdlen = 0;
for(i=1;i<=m++i) HT[i].weight = 0; //遍历哈弗曼树时作用结点状态标志
while(p){
if(HT[p].weight==0){
//向左
HT[p].weight=1;
if(HT[p].lchild!=0){
p=HT[p].lchild; cd[cdlen++]="0";}
else if(HT[p].rchild==0){
//记录叶子结点的字符编码
HC[p]=(char * )malloc((cdlen+1)*sizeof(char));
cd[cdlen]="\0"; strcpy(HC[p],cd); //复制编码
}
}
else if(HT[p].weight==1){
HT[p].weight=2;
if(HT[p].rchild!=0){
p=HT[p].rchild;cd[cdlen++]="1";}
}else{
//HT[p].weight==2,退回
HT[p].weight=0;p=HT[p].parent;cdlen; //遇到父结点,编码长度减1
}//else
}//while