3-树和二叉树

二叉树链式存储结构

二叉链表

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

猜你喜欢

转载自blog.csdn.net/qq_41962612/article/details/115082441