实验二源代码

/*二叉树的基本操作及哈夫曼编码/译码系统的实现

实验目的:
1、掌握二叉树的二叉链表存储表示及遍历操作实现方法。
2、实现二叉树遍历运算的应用:求二叉树中叶子结点个数、结点总数、二叉树的高度、交换
二叉树的左右子树等。
3、掌握二叉树的应用——哈夫曼编码的实现。*/

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>//bool类型

///////////////*完成二叉树的先序创建、先序遍历、中序遍历、后序遍历等*/////////////
#define ElemType int
typedef struct btnode{ 
    int element;
    struct btnode *lChild;
    struct btnode *rChild;
}BTNode;

typedef struct binarytree{ 
    BTNode *root;
}BinaryTree;

//先序遍历构建二叉树
BTNode* PreCreateBT(BTNode *t){
    char ch;
    ch=getchar();
    if(ch=='#')
        t=NULL;
    else{
        t=(BTNode *)malloc(sizeof(BTNode));
        t->element=ch;
        t->lChild=PreCreateBT(t->lChild);
        t->rChild=PreCreateBT(t->rChild);
    }
    return t;
}
void PreMakeTree(BinaryTree *bt){
    bt->root=PreCreateBT(bt->root);
}

/*另一种建树方法
void Create(BinaryTree *bt){
    bt->root=NULL;
}
BTNode* NewNode(ElemType x,BTNode *ln,BTNode *rn){
    BTNode *p=(BTNode *)malloc(sizeof(BTNode));
    p->element=x;
    p->lChild=ln;
    p->rChild=rn;
    return p;
}

bool Root(BinaryTree *bt,ElemType *x){
    if(bt->root){
        x=&bt->root->element;
        return false;
    }
    else
        return false;
}

void MakeTree(BinaryTree *bt,ElemType e,BinaryTree *left,BinaryTree *right){
    if(bt->root||left==right)
        return ;
    bt->root=NewNode(e,left->root,right->root);
    left->root=right->root=NULL;
}
*/


//先序遍历 根-左-右
void PreOrder(BTNode* t){
    if(!t)
        return;
    printf("%c",t->element);//打印根节点
    PreOrder(t->lChild);//遍历左子树
    PreOrder(t->rChild);//遍历右子树
}
void PreOrderTree(BinaryTree *bt){
    PreOrder(bt->root);
    printf("\n");
}


//中序遍历 左-根-右
void MidOrder(BTNode* t){
    if(!t)
        return;
    MidOrder(t->lChild);//遍历左子树
    printf("%c",t->element);//打印根节点
    MidOrder(t->rChild);//遍历右子树
}
void MidOrderTree(BinaryTree *bt){
    MidOrder(bt->root);
    printf("\n");
}

//后序遍历 左-右-根
void LastOrder(BTNode* t){
    if(!t)
        return;
    LastOrder(t->lChild);//遍历左子树
    LastOrder(t->rChild);//遍历右子树
    printf("%c",t->element);//打印根节点
}
void LastOrderTree(BinaryTree *bt){
    LastOrder(bt->root);
    printf("\n");
}

//清空二叉树
void Clear(BTNode* t){
    if(!t)
        return ;
    Clear(t->lChild);
    Clear(t->rChild);
    free(t);
}
void TreeClear(BinaryTree *bt){
    Clear(bt->root);
}


//////*实现求二叉树结点个数、叶子结点个数、二叉树的高度以及交换二叉树所有左右子树的操作。*/////

//求二叉树的结点个数
int TSize(BTNode *t){
    if(!t)
        return 0;
    else
        return TSize(t->lChild)+TSize(t->rChild)+1;
}
int TreeSize(BinaryTree *bt){
    return TSize(bt->root);
}

//求二叉树的叶子结点个数
int LeafSize(BTNode *t){
    if(!t)
        return 0;
    else{
        int x=LeafSize(t->lChild);
        int y=LeafSize(t->rChild);
        //printf("%d %d\n",x,y);
        if(x==0&&y==0)
        return 1;
        else return x+y;
    }
}
int LeafTreeSize(BinaryTree *bt){
    return LeafSize(bt->root);
}

int max(int a,int b){
    if(a>=b)return a;
    else return b;
}


//求二叉树的高度
int Height(BTNode *t){
    if(!t)
        return 0;
    else
       return max(Height(t->lChild),Height(t->rChild))+1;

}
int TreeHeight(BinaryTree *bt){
    return Height(bt->root);
}

//交换二叉树所有左右子树的操作
void Exchange(BTNode *t){
    if(!t)
        return;

    Exchange(t->lChild);
    Exchange(t->rChild);
    BTNode *a;
    a=t->lChild;
    t->lChild=t->rChild;
    t->rChild=a;
    
}
void ExchangeTree(BinaryTree *bt){
    Exchange(bt->root);
}

///////////////////*实现哈夫曼树的创建、哈夫曼编码以及解码的实现。*////////////////////

typedef struct hfmTNode{ 
    char element; //结点的数据域
    int w; //结点的权值
    int code;
    struct hfmTNode *lChild; //结点的左孩子指针
    struct hfmTNode *rChild; //结点的右孩子指针
}HFMTNode; 



//优先权队列的算法实现
typedef struct priorityQueue{
    HFMTNode **elements;
    int n;
    int maxSize;
}PriorityQueue;

//创建一个空的优先权队列
void CreatePQ(PriorityQueue *PQ,int mSize){
    PQ->maxSize=mSize;
    PQ->n=0;
    PQ->elements=(HFMTNode**)malloc(mSize*sizeof(HFMTNode*));
    for(int i=0;i<mSize;i++){
        PQ->elements[i] = (HFMTNode*)malloc(sizeof(HFMTNode)); 
        PQ->elements[i]->w=0;
    }
}

//销毁一个优先权队列,释放其占用的空间
void Destroy(PriorityQueue *PQ){
    free(PQ->elements);
    PQ->n=0;
    PQ->maxSize=0;
}

//判断优先权队列是否为空
int isEmpty(PriorityQueue *PQ){
    if(PQ->n==0)
        return 1;
    else 
        return 0;
}

//判断优先权队列是已满
int isFull(PriorityQueue *PQ){
    if(PQ->n>=PQ->maxSize)
        return 1;
    else 
        return 0;
}

//获取当前优先权队列中的元素个数
int Size(PriorityQueue *PQ){
    return PQ->n;
}
//向上调整
void AdjustUp(HFMTNode* heap[],int current){
    int p=current;
    HFMTNode* temp=(HFMTNode*)malloc(sizeof(HFMTNode));

    while(p>0){
         int parent = (p - 1) / 2;
      //  printf("%d\n",heap[p]->w);
      // printf("%d\n",heap[parent]->w);
        if(heap[p]->w<heap[parent]->w){//若p指向的元素小于其双亲结点,则与双亲结点交换
            temp=heap[p];
            heap[p]=heap[parent];
            heap[parent]=temp;
            p=parent;//将p向上移动至当前考察元素双亲结点的位置
        }
        else 
            break;//若p指向的元素不小于其双亲结点,则调整完毕
    }
}

//向下调整
void AdjustDown(HFMTNode *heap[],int current,int border){
    int p=current;
    int minChild;
    HFMTNode *temp=(HFMTNode*)malloc(sizeof(HFMTNode));
    while(2*p+1<=border){//p不是叶子节点,执行调整
        if((2*p+2)<=border&&heap[2*p+1]->w>heap[2*p+2]->w)
            minChild=2*p+2;//右孩子存在且较小,则minChild指向p的右孩子
        else
            minChild=2*p+1;//左孩子存在且较小,则minChild指向p的左孩子
        if(heap[p]->w<=heap[minChild]->w)
            break;//若当前结点不大于其最小的孩子,则调整结束
        else{//否则将p与其最小孩子交换
            temp=heap[p];
            heap[p]=heap[minChild];
            heap[minChild]=temp;
            p=minChild;//设置下轮循环待考察的元素的位置(即当前下移元素的位置)
        }
    }
}

//在优先权队列中增加一个新元素x
void Append(PriorityQueue *PQ,HFMTNode *x){
    if(isFull(PQ))return;
    
 PQ->elements[PQ->n]->element=x->element;
   PQ->elements[PQ->n]->w=x->w;
   PQ->elements[PQ->n]->lChild=x->lChild;
   PQ->elements[PQ->n]->rChild=x->rChild;
  //  PQ->elements[PQ->n]=x;
    PQ->n++;
   
   AdjustUp(PQ->elements,PQ->n-1);
}
//取出优先级最高的元素,利用参数x返回,并在优先权队列中删除该元素
HFMTNode* Serve(PriorityQueue *PQ){
    if(isEmpty(PQ))
        return NULL;
    HFMTNode* p=(HFMTNode*)malloc(sizeof(HFMTNode));
    p->w = PQ->elements[0]->w;
    p->element = PQ->elements[0]->element;
    p->lChild = PQ->elements[0]->lChild;
    p->rChild = PQ->elements[0]->rChild;
PQ->n--;
    PQ->elements[0]->w=PQ->elements[PQ->n]->w;
    PQ->elements[0]->lChild=PQ->elements[PQ->n]->lChild;
    PQ->elements[0]->rChild=PQ->elements[PQ->n]->rChild;
    PQ->elements[0]->element=PQ->elements[PQ->n]->element;
    //PQ->elements[0]=PQ->elements[PQ->n-1];
   
   // PQ->n--;
    AdjustDown(PQ->elements,0,PQ->n-1);

    return p;
}

HFMTNode* CreateHFMTree(char data[],int w[],int m){
    PriorityQueue PQ;//定义优先权队列PQ,用于存放二叉树根结点指针
    HFMTNode* x=(HFMTNode*)malloc(sizeof(HFMTNode));
    HFMTNode* y=(HFMTNode*)malloc(sizeof(HFMTNode));
    HFMTNode* z=(HFMTNode*)malloc(sizeof(HFMTNode));//x,y,z 为二叉树变量
    CreatePQ(&PQ,m); //初始化优先权队列 PQ,设优先权值存在根结点数据域
    for(int i=0; i<m; i++){
      //  printf("w[i]=%d data=%d\n",w[i],data[i]);
        x->element=data[i];
        x->code=0;
        x->w=w[i];
        x->lChild=NULL;
        x->rChild=NULL;
       
        Append(&PQ,x); //将新创建的二叉树插入优先权队列
    }
    while(PQ.n>1){
        x=Serve(&PQ);//从PQ中取出根结点权值最小的二叉树,存入x
        
       // printf("serve=%d PQ-N=%d\n",PQ.elements[0]->w,PQ.n);
        y=Serve(&PQ); //从PQ中取出根结点权值次小的二叉树,存入y
        //合并x和y,作为新二叉树z的左右子树,z的优先权值等于x和y的优先权值之和
        z->w=x->w+y->w;
        //printf("x=%dy=%dz=%d\n",x->w,y->w,z->w);
        if(x->w < y->w) //设置左子树根结点权值小于右子树
        {
            z->lChild=x;
            z->rChild=y;
        }
        else{
            z->rChild=x;
            z->lChild=y;
        }
        Append(&PQ,z);//将合并生成的新二叉树z插入优先权队列
    }
    x=Serve(&PQ); //获取优先权队列中唯一的二叉树,存入x,该二叉树即为哈夫曼树
    return x;
}

void HFMcode(HFMTNode *h){
   // HFMTNode* p=(HFMTNode*)malloc(sizeof(HFMTNode));
   // HFMTNode* t=(HFMTNode*)malloc(sizeof(HFMTNode));
   // p=h;
    if(h->lChild==NULL||h->rChild==NULL){
        printf("数据为%c,权值为%d的哈夫曼编码为:",h->element,h->w);
        int t=h->code,i=0;
        int s[10];
        while(t!=0){
            s[i]=t%10;
            t=t/10;
            i++;
        }
        while(i){
            if(s[i-1]==8)
            printf("0");
            else printf("1");
            i--;
        }
        printf("\n");
        return;
    }
    h->lChild->code=h->code*10+8;
    h->rChild->code=h->code*10+1;
    HFMcode(h->lChild);
    HFMcode(h->rChild);

}

int HFMdecode(HFMTNode *h,char* s){
    int i=0;
    HFMTNode* x=h;
    int a;
    while(s[i]!='\0'){
        if(s[i]=='0')h=h->lChild;
        else if(s[i]=='1')h=h->rChild;
        i++;
    }
    a=h->element;
    return a;
}

//先序遍历 根-左-右
void Pre(HFMTNode* t){
    if(!t)
        return;
    t->code=0;
    printf("%d ",t->w);//打印根节点
    Pre(t->lChild);//遍历左子树
    Pre(t->rChild);//遍历右子树
}



int main(){
    BinaryTree a;
    printf("请输入二叉树:");
    PreMakeTree(&a);//先序创建树
    
/*  建树另一种方法
    BinaryTree a,b,x,y,z;
    Create(&a);
    Create(&b);
    Create(&x);
    Create(&y);
    Create(&z);
    MakeTree(&y,'E',&a,&b);
    MakeTree(&z,'F',&a,&b);
    MakeTree(&x,'C',&y,&z);
    MakeTree(&y,'D',&a,&b);
    MakeTree(&z,'B',&y,&x);*/


    printf("二叉树的先序遍历为:");
    PreOrderTree(&a);//先序遍历
    printf("二叉树的中序遍历为:");
    MidOrderTree(&a);//中序遍历
    printf("二叉树的后序遍历为:");
    LastOrderTree(&a);//后序遍历
    
    printf("二叉树的结点个数为:%d\n",TreeSize(&a));
    printf("二叉树的叶子结点个数为:%d\n",LeafTreeSize(&a));
    printf("二叉树的高度为:%d\n",TreeHeight(&a));

    ExchangeTree(&a);
    
    printf("二叉树的先序遍历为:");
    PreOrderTree(&a);//先序遍历
    printf("二叉树的中序遍历为:");
    MidOrderTree(&a);//中序遍历
    printf("二叉树的后序遍历为:");
    LastOrderTree(&a);//后序遍历

    
    TreeClear(&a);//清空树

    char data[100];
    int w[100];
    int m;
    //哈夫曼树的创建、哈夫曼编码以及解码的实现d
    printf("请输入需要编码的数据个数:");
    scanf("%d",&m);
    for(int i=0;i<m;i++){
    printf("请输入第%d个数据和权值:\n",i+1);
    char cc=getchar();
    printf("数据为=");
    scanf("%c",&data[i]);
    
    printf("权值为=");
    scanf("%d",&w[i]);
    }
    
    //创建哈夫曼树
    HFMTNode *HFM=CreateHFMTree(data,w,m);
    //给哈夫曼树进行编码
    printf("哈夫曼树的先序遍历输出结果为:");
    Pre(HFM);
    printf("\n");
    HFMcode(HFM);
    char s[10];
    printf("请输入需要解码的哈夫曼编码:");
    scanf("%s",s);
    printf("%s所对应的数据为:%c",s,HFMdecode(HFM,s));
    return 0;
}

  

posted @ 2025-02-20 14:16  jxt0823  阅读(16)  评论(0)    收藏  举报