ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

二叉树/前中后序遍历/二叉搜索树/哈夫曼树

2022-08-18 16:31:22  阅读:141  来源: 互联网

标签:return struct 哈夫曼 前中 int 二叉树 NULL root 节点


参考资料

遍历的非递归写法

目录

中序遍历

左子树-->根节点-->右子树,在访问完成根节点后,接下来访问的下一个节点是右子树的最左边节点, 这个结论可用于中序线索二叉树的遍历

//非递归的中序遍历
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;

typedef struct node
{
    int data;
    struct node* lchild;  //左孩子
    struct node* rchild;  //右孩子
    bool visite;
}BTNode;

void PreOrderWithoutRecursion(BTNode* root){
    if (root == NULL)
        return;
    BTNode* p = root;
    stack<BTNode*> s;

    while (!s.empty() || p){
        if(p!=NULL){
            s.push(p);
            p = p->lchild;
        }else{
            p = s.top();
            cout<<p->data<<"  ";
            //根节点p以及它的左子树以及访问完成 p出栈 去往p的右子树
            s.pop();
            p = p->rchild;
        }
    }
}

int main(){
    BTNode node[10];
    for(int i=1;i<10;i++){
        node[i].data = i;
        node[i].lchild = NULL;//一开始结构体里面有其他数据,所以要初始化
        node[i].rchild = NULL;
        node[i].visite = false;
    }
    node[1].lchild = &node[2];
    node[2].lchild = &node[4];
    node[2].rchild = &node[5];
    node[1].rchild = &node[3];
    node[3].rchild = &node[6];
    PreOrderWithoutRecursion(&node[1]);
    return 0;
}

前序遍历

根节点-->左子树-->右子树,在访问完成一个节点后,接下来访问的下一个节点是

  1. 左节点存在就是左节点
  2. 左节点不存在,右节点存在就是右节点
  3. 如果是叶子节点,根据前序二叉线索树的线索找下一个节点
//非递归前序
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;

typedef struct node
{
    int data;
    struct node* lchild;  //左孩子
    struct node* rchild;  //右孩子
    bool visite;
}BTNode;

void PreOrderWithoutRecursion(BTNode* root){
    if (root == NULL)
        return;
    BTNode* p = root;
    stack<BTNode*> s;

    while (!s.empty() || p){
        if(p!=NULL){
            cout<<p->data<<"  ";
            s.push(p);
            p = p->lchild;
        }else{
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
}

int main(){
    BTNode node[10];
    for(int i=1;i<10;i++){
        node[i].data = i;
        node[i].lchild = NULL;//一开始结构体里面有其他数据,所以要初始化
        node[i].rchild = NULL;
        node[i].visite = false;
    }
    node[1].lchild = &node[2];
    node[2].lchild = &node[4];
    node[2].rchild = &node[5];
    node[1].rchild = &node[3];
    node[3].rchild = &node[6];
    PreOrderWithoutRecursion(&node[1]);
    return 0;
}

后序遍历

非递归后序遍历方式1

非递归的后序遍历需要用到标记位visite,只有左右2个子树都访问完成,才能访问根节点

//非递归的后序
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;

typedef struct node
{
    int data;
    struct node* lchild;  //左孩子
    struct node* rchild;  //右孩子
    bool visite;
}BTNode;
//后序遍历
void AfterOrderWithoutRecursion(BTNode* root){
    if (root == NULL)
        return;
    BTNode* p = root;
    stack<BTNode*> s;
    while (!s.empty() || p){
        if(p->lchild!=NULL && !p->lchild->visite){
            s.push(p);//回去的路
            p = p->lchild;
        } else if(p->rchild!=NULL && !p->rchild->visite){
            s.push(p);
            p = p->rchild;
        } else {
            cout<< p->data << "  ";
            p->visite = true;
            p = s.top();
            //mark: p==Null 说明栈已经空了,已经没有回去的路了
            if(p==NULL)
                break;
            s.pop();
        }
    }
    cout << endl;
}

int main(){
    BTNode node[10];
    for(int i=1;i<10;i++){
        node[i].data = i;
        node[i].lchild = NULL;//一开始结构体里面有其他数据,所以要初始化
        node[i].rchild = NULL;
        node[i].visite = false;
    }
    node[1].lchild = &node[2];
    node[2].lchild = &node[4];
    node[2].rchild = &node[5];
    node[1].rchild = &node[3];
    node[3].rchild = &node[6];
    AfterOrderWithoutRecursion(&node[1]);
    return 0;
}

非递归后序遍历方式2

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;

typedef struct node
{
    int data;
    struct node* lchild;  //左孩子
    struct node* rchild;  //右孩子
    bool visite;
}BTNode;
//后续遍历
void AfterOrderWithoutRecursion(BTNode* root){
    if (root == NULL)
        return;
    BTNode* p = root, *pre = NULL;//pre是上一次访问的节点
    stack<BTNode*> s;

    while (!s.empty() || p){
        if(p!=NULL){
            s.push(p);
            p = p->lchild;
        }else{
            p = s.top();
            //有有孩子且有孩子不是上一次访问的节点 说明右子树还没访问
            if(p->rchild!=NULL && p->rchild!=pre){
                p = p->rchild;
            } else{
                cout<<p->data<<"  ";
                pre  = p ;
                s.pop();
                p = NULL;
            }
        }
    }
}

int main(){
    BTNode node[10];
    for(int i=1;i<10;i++){
        node[i].data = i;
        node[i].lchild = NULL;//一开始结构体里面有其他数据,所以要初始化
        node[i].rchild = NULL;
        node[i].visite = false;
    }
    node[1].lchild = &node[2];
    node[2].lchild = &node[4];
    node[2].rchild = &node[5];
    node[1].rchild = &node[3];
    node[3].rchild = &node[6];
    AfterOrderWithoutRecursion(&node[1]);
    return 0;
}

二叉搜索树

插入节点

二叉搜索树的插入

#include<bits/stdc++.h>
using namespace std;
int ans = 0;
struct BSTNode{
    BSTNode* lchild;
    BSTNode* rchild;
    int data;
};
int insert(int k,BSTNode* &T){ //注意这里是&
    if(T==NULL){
        T = (BSTNode*)malloc(sizeof (BSTNode));
        T->rchild = T->lchild =NULL;
        T->data = k;
        return 1;
    }
    if(T->data==k) return 0;
    if(k<T->data) return insert(k,T->lchild);
    else return insert(k,T->rchild);
}
void inorder(BSTNode* T){
    if(T==NULL) return;
    inorder(T->lchild);
    cout<<T->data<<" ";
    inorder(T->rchild);
}
int main(){
    BSTNode* root = NULL;//分配一块空间存指针类型
    insert(5,root);
    insert(3,root);
    insert(1,root);
    insert(6,root);
    insert(7,root);
    inorder(root);
    return 0;
}

删除节点

1)没有左子树或者右子树 直接删除
2)有左子树和右子树,删除15节点,因为有先找到右子树最小的节点17
在这里插入图片描述

哈夫曼树

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x7fffffff;
string huffmanCode[20];//设立一个临时数组存哈弗曼编码
int sum;//节点个数
struct HuffNode
{
    char data;//结点数据
    int weight;//权值
    int parent;
    int lchild;
    int rchild;
};
void Select(HuffNode* &T, int k, int& i1, int& i2) {
    /*选择根结点权值最小的两个结点。*/
    int min1 = inf , min2 = inf;
    for(int i=0;i<k;i++){
        if(T[i].parent==-1 && T[i].weight<min1){
            min1 = T[i].weight;
            i1 = i;
        }
    }
    for(int i=0;i<k;i++){
        if(T[i].parent==-1 && T[i].weight<min2 && i!=i1){
            min2 = T[i].weight;
            i2 = i;
        }
    }
}


void CreatHufftree(HuffNode* &T, int n){
    int s1, s2;
    int i;
    if (n <= 1){
        cout << "您输入的结点个数有误请输入的结点个数大于1" << endl;
        return;
    }
    //首先!初始化!
    for (i = 0; i <= 2 * n; i++){
        T[i].parent = -1;
        T[i].lchild = -1;
        T[i].rchild = -1;
    }


    //进行归并 //进行n-1次的结合 //最后一个位置为2n-1  0~n-1是一开始存的初始节点
    for (i = n ; i < 2 * n-1; i++){
        //权值最小的两个结点归并成一个父结点  s1 s2作为返回值接收 s1,s2是T[]里面权重最小且没有合并的2个节点
        Select(T, i , s1, s2);
        T[i].weight = T[s1].weight + T[s2].weight;
        T[s1].parent = i;
        T[s2].parent = i;
        T[i].lchild = s1;
        T[i].rchild = s2;
    }
}


void  HuffmanCode(HuffNode* T, string huffmanCode[]) {
    //设置一个临时存储空间
    int cur;
    int parent;
    //遍历哈夫曼树,生成哈夫曼编码
    for (int i = 0; i < sum; i++) {
        cur = i;//记录当前处理位置
        parent = T[i].parent;//找到当前结点的父节点
        while (parent != -1) {//父节点不等于-1指的就是当前
            if (T[parent].lchild == cur)
                huffmanCode[i] = '0' + huffmanCode[i];//当前为左子树则编码0
            else
                huffmanCode[i] = '1' + huffmanCode[i];
            //向上搜索
            cur = parent;
            parent = T[parent].parent;
        }
    }

}

int main(){

    cin >> sum;//节点个数
    //sum个初始节点合成哈夫曼树会再生成sum-1个新节点  一共2*sum-1个节点
    HuffNode *T = new HuffNode[2 * sum];
    //录入数据!
    for (int i = 0; i < sum; i++){
        cin >> T[i].data;
        cin >> T[i].weight;
    }
    CreatHufftree(T, sum);
    cout << "哈夫曼编码为:" << endl;
    HuffmanCode(T, huffmanCode );
    for (int i = 0; i < sum; i++){
        cout << "结点" << T[i].data << ":" << huffmanCode[i] << endl;
    }
    return 0;
}
/*
 6
 a 45
 b 13
 c 12
 d 16
 e 9
 f 5
 */

练习题

对称二叉树

#include<bits/stdc++.h>
using namespace std;
int ans = 0;
struct node{long long l,r,val;}bt[1000002];
int book[1000002];//记忆化以该节点为根节点的树节点个数
int count(long long now){//递归的对左右子树计数
    if(book[now]!=0) return book[now];
    if(now==-1){
        book[now] = 0;
    } else{
        book[now] = count(bt[now].l) + count(bt[now].r) + 1;
    }
    return book[now];
}

bool same(long long now1,long long now2){//判断是否对称 now是树的id

    if(now1==-1&&now2==-1) return true;
    if(now2==-1||now1==-1) return false;//小技巧
    if(bt[now1].val!=bt[now2].val) return false;
    //now1的左子树和now2的右子树一样  todo 可以将结果保存
    return same(bt[now1].l,bt[now2].r)&&same(bt[now1].r,bt[now2].l);
}

int main(){
    int n;cin>>n; //n个点
    for(int i=1;i<=n;i++) cin>>bt[i].val; //每个点的值
    for(int i=1;i<=n;i++) cin>>bt[i].l>>bt[i].r; //每个点的左孩子id和右孩子id
    for(int i=1;i<=n;i++)/*枚举每棵子树*/
        if(same(i,i))
            ans=max(ans,count(i));
    return 0&printf("%d",ans);
}

标签:return,struct,哈夫曼,前中,int,二叉树,NULL,root,节点
来源: https://www.cnblogs.com/cyfuture/p/16599155.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有