其他分享
首页 > 其他分享> > 二叉树/前中后序遍历/二叉搜索树/哈夫曼树

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

作者:互联网

参考资料

遍历的非递归写法

目录

中序遍历

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

//非递归的中序遍历
#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