树相关基础代码——考研备考篇

目录

二叉树

二叉树链式存储结构

先序递归遍历        

中序递归遍历

后序递归遍历 

层序遍历

先序非递归遍历   

中序非递归遍历

后序非递归遍历

 线索二叉树

线索二叉树结点定义

中序线索二叉树 

前序线索二叉树 

后序线索二叉树

二叉排序树

存储结构

查找关键字

二叉排序树的构造

删除关键字

哈夫曼树

存储结构

对各字符的哈夫曼编码程序如下

读入二进制流的哈夫曼编码

译码过程


二叉树

二叉树链式存储结构

typedef struct BTNode
{
    char data; //数据域
    struct BTNode *lchild; //左指针域
    struct BTNode *rchild; //右指针域
}BTNode;

先序递归遍历        

void preorder(BTNode *p)
{
    if(p!=NULL)
    {
        visit(p); //其中包含了对结点P的各种访问操作
        preorder(p->lchild); //先序遍历左子树
        preorder(p->rchild); //先序遍历右子树
    }
}

中序递归遍历

void inorder(BTNode *p)
{
    if(p!=NULL)
    { 
        inorder(p->lchild); //先序遍历左子树
        visit(p); //其中包含了对结点P的各种访问操作
        inorder(p->rchild); //先序遍历右子树
    }
}

后序递归遍历 

void postorder(BTNode *p)
{
    if(p!=NULL)
    {
        postorder(p->lchild); //先序遍历左子树
        postorder(p->rchild); //先序遍历右子树
        visit(p); //其中包含了对结点P的各种访问操作
    }
}

层序遍历

void level(BTNode *p)
{
    int front,rear;
    BTNode *que[maxSize]; //定义循环队列,用来记录将要访问的层次上的结点
    front=rear=0;
    BTNode *q;
    if(p!=NULL)
    {
        rear=(rear+1)%maxSize;
        que[rear]=p; //根结点入队
        while(front!=rear) //队列不空时进行循环
        {
            front=(front+1)%maxSize;
            q=que(front); //队头结点出队
            visit(q); //访问队头结点
            if(q->lchild!=NULL) //如果左子树不空,左子树根结点入队
            {
                rear=(rear+1)%maxSize;
                que[rear]=q->lchild;
            }
            if(q->rchild!=NULL) //如果右子树不空,右子树根结点入队
            {
                rear=(rear+1)%maxSize;
                que[rear]=q->rchild;
            }
        }
    }
}
void LevelOrder(BiTree T){
	InitQueue(Q);	//初始化辅助队列 
	BiTree p;
	EnQueue(Q,T);	//将根结点入队 
	while(!IsEmpty(Q)){	//队列不空则循环 
		DeQueue(Q,p);	//队头结点出队 
		visit(p);	//访问出队结点 
		if(p->lchild != NULL)
			EnQueue(Q,p->lchild);
		if(p->rchild != NULL)
			EnQueue(Q,p->rchild);
	} 
} 

先序非递归遍历   

(注意先入右孩子后入左孩子)

void preorderNonrecursion(BTNode *bt)
{
    if(bt!=NULL)
    {
        BTNode *Stack[maxSize]; //定义一个栈
        int top=-1; //初始化栈
        BTNode *p;
        Stack[++top]=bt; //根结点入栈
        while(top!=-1) //栈空循环结束
        {
            p=Stack[top--]; //出栈并输出栈顶结点
            visit(p); //访问p结点
            if(p->rchild!=NULL) //栈顶结点的右孩子存在,则右孩子入栈
                Stack[++top]=p->rchild;
            if(p->lchild!=NULL) //栈顶结点的左孩子存在,则左孩子入栈
                Stack[++top]=p->lchild;
        }
    }
}

中序非递归遍历

void inoderNonrecursion(BTNode *bt)
{
    if(bt!=NULL)
    {    
        BTNode *Stack[maxSize]; //定义一个栈
        int top=-1; //初始化栈
        BTNode *p;
        p=bt; //从根结点开始遍历
        while(top!=-1||p!=NULL) //注意条件为栈非空或p非空
        {
            while(p!=NULL) //左孩子非空,左孩子持续入栈
            {    
                Stack[++top]=p;
                p=p->lchlid;
            }
            if(top!=-1) //栈非空情况下出栈并输出出栈结点
            {
                p=Stack[top--];
                visit(p); //访问出栈结点
                p=p->rchild;  //出栈结点右孩子准备入栈
            }
        }
    }
}

后序非递归遍历

(采用的是逆输出 逆后序遍历序列,而逆后序遍历序列 即 将 先序遍历序列左右子树顺序交换)

void postorderNonrecursion(BTNode *bt)
{
    if(bt!=NULL)
    {
        BTNode *Stack1[maxSize];
        int top1=-1;
        BTNode *Stack2[maxSize];
        int top2=-1; //定义并初始化两个栈
        BTNode *p=NULL;
        Stack1[++top1]=bt; //根结点入栈
        while(top1!=-1) //栈非空则循环
        {
            p=Stack1[top1--];
            Stack2[++top2]=p; //注意将前面的出栈换成了入栈2
            if(p->lchild!=NULL)
                Stack1[++top1]=p->lchild;
            if(p->rchild!=NULL)
                Stack1[++top1]=p->rchild; //注意与前序遍历比先入左孩子
        }
        while(top2!=-1)
        {
            p=Stack2[top2--];
            visit(p); //访问p的函数
        }
    }
}

 线索二叉树

线索二叉树结点定义

typedef struct TBTNode
{
    char data;
    int ltag,rtag; //线索标记
    struct TBTNode *lchild; //tag=1,则为前驱,tag=0,则为左孩子
    struct TBTNode *rchild; //tag=1,则为前驱,tag=0,则为右孩子
}TBTNode;

中序线索二叉树 

二叉树线索化

void InThread(TBTNode *p,TBTNode *&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; //使p成为下一个结点的前驱结点
        InThread(p->rchild,pre); //递归,右子树线索化
    }
}

建立中序线索二叉树主程序

void createInThread(TBTNode *root)
{
    TBTNode *pre=NULL; //前驱结点指针
    if(root!=NULL)
    {
        InThread(root,pre); //非空二叉树线索化
        pre->rchild=NULL; 
        pre->rtag=1; //处理最后一个结点的后继(线索化过程最后一个节点停在pre上)
    }
}

中序线索二叉树找中序序列下第一个结点

TBTNode *First(TBTNode *p)
{
    while(p->ltag==0)
        p=p->lchild; //最左下结点(不一定是叶节点)
    return p;
}

结点p在中序下的后继结点

TBTNode *Next(TBTNode *p)
{
    if(p->rtag==0)
        return First(p->rchild); //无线索,找右孩子的最左下结点(即前一步所求的中序下一结点)
    else
        return p->rchild; //直接返回后继线索

中序线索二叉树上执行中序遍历的算法

void Inorder(TBTNode *root)
{
    for(TBTNode *p=First(root);p!=NULL;p=Next(p))
        visit(p); //访问结点p
}

前序线索二叉树 

二叉树线索化

void preThread(TBTNode *p,TBTNode *&pre)
{
    if(p!=NULL)
    {
        if(p->lchild==NULL) //建立当前结点的前驱结点
        {    
            p->lchild=pre;
            p->ltag=1;
        }
        if(pre!=NULL&&pre->rchild==NULL) //建立前驱结点的后继线索
        {
            pre->rchild=p;
            pre->rtag=1;
        }
        pre=p; //使p成为下一个结点的前驱结点
        //注意这里只有左右指针不是线索才需要递归
        if(p->ltag==0)
            preThread(p->lchild,pre); //递归,左子树线索化
        if(p->rtag==0)
            preThread(p->rchild,pre); //递归,右子树线索化
    }
}

执行前序遍历 

void preorder(TBTNode *root)
{
    if(root!=NULL)
    {
        TBTNode *p=root;
        while(p!=NULL)
        {
            while(p->ltag==0) //左指针不是线索时,边访问边左移
            {    
                visit(p);
                p=p->lchild;
            }
            visit(p); //p的左指针为线索,但还未访问
            p=p->rchild; //无论是否为线索都指向其后继
        }
    }
}

后序线索二叉树

void postThread(TBTNode *p,TBTNode *&pre)
{
    if(p!=NULL)
    {   
        preThread(p->lchild,pre); //递归,左子树线索化
        preThread(p->rchild,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; //使p成为下一个结点的前驱结点
       
    }
}

二叉排序树

存储结构

typedef struct BTNode
{
    int key; // 关键字
    struct BTNode *lchild; // 左指针域
    struct BTNode *rchild; // 右指针域
}BTNode;

查找关键字

BTNode* BSTSearch(BTNode* bt, int key)
{
    if (bt == NULL)
        return NULL; // 来到空指针域,查找不成功返回NULL
    else
    {
        if (key == bt->key) // 查找成功,返回关键字所在结点指针
            return bt;
        else if (key < bt->key) // 小于根结点关键字前往左子树
            return BSTSearch(bt->lchild, key); //该查找函数有返回值,所以递归调用时要用return
        else // 大于根结点关键字前往左子树
            return BSTSearch(bt->rchild, key);
    }
}

插入关键字

int BSTInsert(BTNode *&bt, int key) // 指针bt要改变,所以用引用型指针
{
 
    if (bt == NULL) //原本为空,即创建新树
    {
        bt = new BTNode; // 创建新结点
        // bt = (BTNode*)malloc(sizeof(BTNode));
        bt->lchild = bt->rchild = NULL; // 将子树赋空
        bt->key = key; //将值插入
        return 1; // 插入成功,返回1
    }
    else
    {
        if (key == bt->key) // 关键字已存在于树中,插入失败,返回0
            return 0;
        else if (key < bt->key)
            return BSTInsert(bt->lchild, key);
        else
            return BSTInsert(bt->rchild, key);
    }
}

二叉排序树的构造

void CreateBST(BTNode *&bt, int key[], int n)
{
    int i;
    bt = NULL; // 将树清空
    for (int i = 0;i < n; ++i) // 调用插入函数,逐个插入关键字
        BSTInsert(bt, key[i]);
}

删除关键字

void DeleteBTS(BTNode *&bt, int key)
{
    if (bt == NULL) // 关键字不存在树中,删除失败,返回0
        return 0;
    else
    {
        if (key == bt->key) // 找到关键字,执行删除函数
            return Delete(bt);
        else if (key < bt->key)
            return DeleteBTS(bt->lchild, key);
        else
            return DeleteBTS(bt->rchild, key);
    }
}

void Delete(BTNode *&bt)
{
    if (bt->lchild != NULL && bt->rchild == NULL) // 右子树为空
    {
        BTNode* q = bt;
        bt = bt->lchild; //用右孩子填补
        delete(q);
    }
    else if (bt->lchild == NULL && bt->rchild != NULL) // 左子树为空
    {
        BTNode* q = bt;
        bt = bt->rchild; //用左孩子填补
        delete(q);
    }
    else // 左右子树均不为空
    {
        BTNode* q = bt;
        BTNode* s = bt->lchild;
        while (s->rchild != NULL) //先转向左孩子,然后找最右结点,即为中序遍历下bt的直接前驱
        {
            q = s; // q记录的是s的双亲结点
            s = s->rchild;
        }
        bt->data = s->data; // 用直接前驱的关键值替换bt
        if (q != bt) // 若双亲不是待删除结点
            q->rchild = s->lchild; //s是最右结点,要么有左孩子要么没有左孩子
                                   //删除s后q会空出右指针域,将s的左孩子或NULL给q的右指针域
        else // 若双亲就是待删除结点,相当于s为其左孩子也为其直接前驱
            q->lchild = s->lchild; //删除s后q会空出左指针域,将s的左孩子或NULL给q的左指针域
        delete(s);
    }
}

哈夫曼树

存储结构

typedef struct{
    unsigned int weight;
    unsigned int parent,lchild,rchild;
}HTNode, *HuffmanTree;

对各字符的哈夫曼编码程序如下

typedef char **HuffmanCode; //动态二维数组存储哈夫曼编码
void HuffmanCoding(HuffmanTree HT,Huffmancode &HC,int n) //从叶子到根逆向求编码,存储在HC中
{    
    HC=new char*[n+1]; //为了方便实现,从1号单元开始使用
    cd=new char[n]; //存放结点哈夫曼编码的字符串数组
    cd[n-1]= '\0'; //字符串结束符
    for(int i=1;i<=n;i++) //从叶子结点出发,得到的哈夫曼编码是逆序的,在字符串数组里逆序存放
    {
        int start=n-1;
        int c=i; //当前结点在数组中的位置
        int p=HT[i].parent; //当前结点的父节点在数组中的位置
        while(p!=0) //一直寻找到根结点
        {    
            --start; //回溯一次,start向前一位
            if(HT[p].lchild==c) //如果该结点为左孩子,则对应字符编码“0”
                cd[start]='0';
            else //如果该结点为右孩子,则对应字符编码“1”
                cd[start]='1';
            c=p; //以父结点为孩子结点,继续朝树根方向遍历
            p=HT[p].parent;
        }
        HC[i]=new char[n-start]; //跳出循环后为第i个字符编码分配空间
        strcpy(HC[i],&cd[start]); //cd数组中从下标start开始,存放的即为哈夫曼编码
    }
    delete(cd); //释放临时空间
}

读入二进制流的哈夫曼编码

void ReadHaffmanTree(char s[],Bitree T)
{    
    int len=strlen(s);
    int i=0;
    Bitree now = T;
    while(i++<len)
    {
        if(now->left==NULL&&now->right==NULL) //叶子结点
        {
            count<<now->data<<"";
            now = T;
            continue;
        }
        if(s[i]=='0')
        {    
            if(now->left=NULL) //没有左孩子了
            {    
                printf(“编码错误”);
                return 1;
            }
            else     
                now=now->left;
        }
        else if(s[i]=='1')
        {    
            if(now->right==NULL) //没有右孩子了
            {
                printf(“编码错误”);
                return 1;
            }
            else 
                now=now->right;
        }
    }
}

译码过程

void HuffmanTreeDeCoding(char string){
    char a;
    BiTree p = T;
    while((a=getchar())!='\n'&&a!=EOF){
        if(a=='0')
            p=p->left;
        else if(a=='1')
            p=p->right;
        if(p->kind==leaf){
            printf("%c",p->x);
            p=T;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值