【二叉树】二叉搜索树与完全二叉树的创建和操作

二叉树
概念:度最大为二的树
形态:空树;只有根节点;只有左子女;只有右子女;既有左子女,也有右子女。

【表示】: 
1. 二元组表示:<前驱,后继>   序偶:尖括号表示一对节点
    eg:DATA={A,B,C,D,E,F,G,H,I}  
    BR={<A,B>,<A,C>,<B,D>,<B,E>,<C,F>,<E,G>,<E,H>,<F,I>}
2. 广义表示法: 双亲(左子女,右子女)       
    eg:  DATA={A,B,C,D,E,F,G,H,I}               
    A(B(D,E(D,H)),C(  ,F( I ))) 【若缺失左子女,逗号不可省略】 
【二叉树的性质】:
    ①:叶子节点总比双分支节点个数多一
    ②:将一棵满二叉树按层进行编号,层数设为i,则每一层都有 2^(i-1)个节点,一棵h层的二叉树有(2^h -1)个节点。

创建二叉搜索树:

二叉搜索树:左子女的数据域值小于或等于根节点的数据域值,右子女的数据域值大于或等于根节点的值
节点类型:[左子女节点地址]<-[节点数据]->[右子女节点地址]
则有:
typedef struct node{
int data;
struct node* left;
struct node* right;
}BTnode;


代码如下——>

/*通过已有数组元素创建二叉搜索树  
先为root分配单元,将数组中的第一个元素放置在root->data 上,然后遍历数组其他元素
用指针c 在二叉树上跑,指针pa 跟在c 的后面,当要插入的元素比 c 大时,c 往右边跑,反之往左边跑
c 为空时停下来,pa 指在待被插结点上,然后判断待插结点p 与 pa 的大小,小的插在左边,大的插在右边
结束后返回根节点root ,二叉搜索树创建完成                                                    */
BTnode* BtSearchTree::CreateBtSearchTree(int a[]){
    BTnode * root , *p, *pa, *c ;
    int i;
    root=(BTnode *)malloc(sizeof(BTnode));
    root->data = a[0];
    root->left= root->right= NULL;
    for(i=1; i<N; i++){
        p=(BTnode *)malloc(sizeof(BTnode));
        p->data= a[i];
        p->left=p->right= NULL;
        c= root;
        while(c){
            pa= c;
            if(c->data< p->data) 
                c= c->right;
            else 
                c= c->left;
        }
        if(pa->data > p->data)
            pa->left= p;
        else 
            pa->right= p;
    }
    return root;
}

创建完全二叉树:

完全二叉树:
一棵h层的二叉树,前h-1 层是满的,第h层连续缺失右边子女
i.满二叉树是特殊的完全二叉树
ii.完全二叉树最多只有一个单分支
iii.一棵h层的完全二叉树有n个节点,则:

        (n<=2^h-1)&&(n>2^(h-1)-1)==>2^(h-1)<n+1<=2^h
         h-1<log2(n+1)<=h

代码如下——>


#define N 8

typedef struct node{
        int data;                         
        struct node* left;          
        struct node* right;
    }BTnode;
/*使用队列 创建完全二叉树;由完全二叉树的性质可知,使用顺序存储满足完全二叉树的存储特点,便采用队列*/

BTnode * CreateCompleteBiTree(int a[]){
    BTnode **Q, *pa, *p, *root;
    Q=(BTnode **)malloc(N*sizeof(BTnode *));        //给队列Q 分配单元
    int front,rear;
    front= rear = 0;                                //初始化
    int i;
    root= (BTnode *)malloc(sizeof(BTnode));         //初始化根节点
    root->data= a[0];
    root->left= root->right= NULL;
    pa= root;                                       //使pa 指向根节点
    for(i= 1; i<N; i++){                            //对a[1]~a[N]的数据进行遍历,最终完成完全二叉树的遍历
        p= (BTnode *)malloc(sizeof(BTnode));
        p->data= a[i];
        p->left= p->right = NULL;
        if(!pa->left   )                            //如果待插结点pa 左空, p插在左边
            pa->left =p;
        else{                                       //左不空,右空,p插在右边
            pa->right= p;
            pa= Q[++front];                         //pa 出队
        }
        Q[++rear]= p;                               //p  入队
    }
    free(Q);
    return root;
}

总结
由以上代码可以看出来,创建完全二叉树时,因h层的完全二叉树是前h-1层是满的,第h层连续缺失右边子女(*注意,不是右子女),所以使用顺序存储的方式,按层一一存储下来,并应用到了队列。
其创建过程为:
i、创建根节点
ii、创建其他节点——>先创建节点,然后找到双亲,判断左右是否空,最后挂新根节点


  • 二叉树的前、中、后序递归遍历
    前序(先序)递归遍历:
    void Forder(BTnode *root){
    if(root){
    cout<<setw(4)<<root->data;
    Forder( root->left);
    Forder( root->right);
    }
    }

    中序递归遍历:
    void INorder(BTnode * root){
    if(root){
    INorder(root->left);
    cout<<setw(3)<<root->data;
    INorder(root->right);
    }
    }

    后序递归遍历:
    void Laorder(BTnode *root){
    if(root){
    Laorder( root->left);
    Laorder(root->right);
    cout<<setw(3)<<root->data;
    }
    }


* 二叉树的非递归按层、前序、中序遍历


二叉树的非递归按层遍历:

   按层遍历时,会用到队列存取指向节点的指针。

i、进行按层遍历时,先创建存储二叉树指针的队列;
ii、初始化后将根节点入队;
iii、然后以队不空为条件,架一个循环:先输出队列的一个元素,判断该节点的左子女是否为空,不为空则将其入队;在判断右子女是否为空,不为空入队。
iiii、这样每次将所输出节点的两个子女依次入队,便能实现按层输出该二叉树的所有节点。

代码如下——>

void LevelOrder(BTnode * root){
    BTnode **Q,*p;                              //p为指向出队元素指针
    int front, rear;
    Q=(BTnode ** )malloc(N*sizeof(BTnode *));   //创建队列单元
    front= rear= 0;
    Q[++rear]= root;
    while(front-rear){                          //while(当队不空时)
        p= Q[++front];
        cout<<setw(3)<<p->data;                 //输出出队元素
        if( p->left) Q[++rear]= p->left;
        if(p->right) Q[++rear]=p->right;        //出队元素为入队元素的左右子女,实现按层遍历
    }

}

二叉树的非递归(前序)先序遍历:

算法描述:
i、生成有N个元素的栈空间S,初始化栈顶指针 top=-1
ii、先将根节点入队
iii、当栈不空时{将出栈元素赋给p;元素出栈;出栈元素的右子女不空,则入栈;出栈元素的左子女不空,则入栈}
iiii、释放S空间,函数结束

代码如下——>

void UnrecurForder(BTnode * root){
    BTnode **S;                                 
    BTnode *p;
    S=(BTnode **)malloc(N*sizeof(BTnode *));    //声明栈,分配动态存储空间
    int top=-1;
    S[++top]=root;                              //根节点入栈
    while(top+1){
        p=S[top--];
        cout<<setw(3)<<p->data;                 //输出出出栈元素
        if(p->right) S[++top]=p->right;         //右先入栈,左再入栈
        if( p->left) S[++top]= p->left;
    }
    free(S);
}

二叉树的非递归中序遍历:

中序非递归遍历与先序非递归遍历一样,都用到了栈

代码如下——>

void UnrecurINorder(BTnode * root){
    int top=-1;
    BTnode **S,*p;
    S=(BTnode **)malloc(N*sizeof(BTnode *));
    p=root;
    /*先将二叉树的左列子女入栈*/
    while(p){
        S[++top]= p;
        p=p->left;
    }
    /*栈不为空时循环:出站一个元素,判断出栈元素的右子女是否为空,不为空则入栈其左线子女*/
    while(top+1){
        p=S[++top];
        cout<<setw(3)<<p->data;
        if(p->right){
            p=p->right;
            while(p->right){
                S[++top]= p;
                p=p->left;          //入栈其左线子女
            }
        }
    }
    free(S);
}

· 其他一些关于二叉树的递归操作


递归返回非空二叉树叶子节点个数:

int  CountLeafnode(BTnode * root){
    static int l= 0;
    if(root){
        if(root->left== NULL && root->right== NULL)     //如果左右子女都为空,则 l 加一
            l++;
        CountLeafnode( root->left);     //遍历二叉树左子女直到叶子处
        CountLeafnode(root->right);     //遍历二叉树右子女直到叶子处
    }
    return l;
}

递归返回 二叉树的深度

int DepthBTSeaTree(BTnode * root){
    int h1,h2,H;
    h1= h2= H= 0;
    if(root){
        h1=DepthBTSeaTree( root->left);
        h2=DepthBTSeaTree(root->right);
        H=h1>h2?(h1+1):(h2+1);
    }
    return H;
}

递归返回将要查找的关键字的节点地址

BTnode * RecurFindKey(BTnode * root, int key){
    if(root) {
        if(root->data==key)
            return root;
        RecurFindKey( root->left,key);
        RecurFindKey(root->right,key);
        return NULL;
    }
}


以下是调试时完整代码


//创建二叉搜索树并且进行操作(全).cpp
//2015-8-10-21:45//////////////////////////////////////////////
/*                  从创建二叉搜索树到对其的所有操作(遍历&查找等),使用递归与非递归                                       */
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include<iostream>
#include<iomanip>
#include<stdlib.h>
using namespace std;
#define N 8         //宏定义数组元素个数
/****************************************************************************************************************************/
/*声明二叉树的节点类型*/
    typedef struct node{
        int data;
        struct node* left;
        struct node* right;
    }BTnode;

class BtSearchTree  
{
private:
                    //在类中声明的自定义数据类型
public:
    BtSearchTree();
    ~BtSearchTree();
    BTnode* CreateBtSearchTree(int a[]);                //通过已有数组元素创建二叉搜索树
    BTnode* CreateCompleteTree(int a[]);                //创建完全二叉树
    void Forder(        BTnode * root);                 //前序遍历-》递归
    void INorder(       BTnode * root);                 //中序遍历-》递归
    void Laorder(       BTnode * root);                 //后序遍历-》递归
    void UnrecurForder( BTnode * root);                 //非递归 前序
    void UnrecurINorder(BTnode * root);                 //非递归 中序
    void UnrecurLaorder(BTnode * root);                 //非递归 后序
    void LevelOrder(    BTnode * root);                 //按层遍历
    int  CountLeafnode( BTnode * root);                 //返回非空二叉树叶子节点个数
    int  DepthBTSeaTree(BTnode * root);                 //返回二叉树的深度
BTnode * UnrecurFindKey(BTnode * root, int key);        //非递归查找元素key 返回key 节点地址,找不到返回NULL
BTnode * RecurFindKey(  BTnode * root, int key);        //递归查找关键字key 返回key 节点地址,找不到返回NULL
};
BtSearchTree::BtSearchTree(){
    cout<<"程序开始!"<<endl<<"-—————————————————————————————————————————————————-"<<endl<<endl<<endl;
}
BtSearchTree::~BtSearchTree(){
    cout<<"-—————————————————————————————————————————————————-"<<endl<<"程序结束,再见ヾ( ̄▽ ̄)Bye~Bye~"<<endl<<endl<<endl;
}




/*通过已有数组元素创建二叉搜索树   
先为root分配单元,将数组中的第一个元素放置在root->data 上,然后遍历数组其他元素
用指针c 在二叉树上跑,指针pa 跟在c 的后面,当要插入的元素比 c 大时,c 往右边跑,反之往左边跑
c 为空时停下来,pa 指在待被插结点上,然后判断待插结点p 与 pa 的大小,小的插在左边,大的插在右边
结束后返回根节点root ,二叉搜索树创建完成                                                    */
BTnode* BtSearchTree::CreateBtSearchTree(int a[]){
    BTnode * root , *p, *pa, *c ;
    int i;
    root=(BTnode *)malloc(sizeof(BTnode));
    root->data = a[0];
    root->left= root->right= NULL;
    for(i=1; i<N; i++){
        p=(BTnode *)malloc(sizeof(BTnode));
        p->data= a[i];
        p->left=p->right= NULL;
        c= root;
        while(c){
            pa= c;
            if(c->data< p->data) 
                c= c->right;
            else 
                c= c->left;
        }
        if(pa->data < p->data)
            pa->left= p;
        else 
            pa->right= p;
    }
    return root;
}

/*返回非空二叉树叶子节点个数*/
int  BtSearchTree::CountLeafnode(BTnode * root){
    static int l= 0;
    if(root) {
        if(root->left== NULL && root->right== NULL)     //如果左右子女都为空,则 l 加一
            l++;
        CountLeafnode( root->left);     //遍历二叉树左子女直到叶子处
        CountLeafnode(root->right);     //遍历二叉树右子女直到叶子处
    }
    return l;
}

/*返回二叉树的深度\层数【递归】*/
int BtSearchTree::DepthBTSeaTree(BTnode * root){
    int h1,h2,H;
    h1= h2= H= 0;
    if(root){
        h1=DepthBTSeaTree( root->left);
        h2=DepthBTSeaTree(root->right);
        H=h1>h2?(h1+1):(h2+1);
    }
    return H;
}

/*非递归查找关键字,返回关键字为key 的节点地址,未找到返回NULL*/
BTnode * BtSearchTree::UnrecurFindKey(BTnode * root, int key){
    BTnode * p;
    p= root;
    while(p){
        if(p->data< key)
            p=p->right;
        else if(p->data >key)
                    p=p->left;
             else if(p->data==key)
                  cout<<"已经找到key了,就在二叉树上"<<endl;
        return p;
    }
    cout<<"没找到key,不在二叉树上!"<<endl;
    return NULL;
}

/*递归查找关键字key,返回关键字为key 的节点地址*/
BTnode * BtSearchTree::RecurFindKey(BTnode * root, int key){
    if(root) {
        if( root->data == key)
            return root;
            RecurFindKey( root->left,key);
            RecurFindKey(root->right,key);
            return NULL;
    }
}

/*按层遍历:LevelOrder——非递归*/
void BtSearchTree::LevelOrder(BTnode * root){
    BTnode **Q,*p;                              //p为指向出队元素指针
    int front, rear;
    Q=(BTnode ** )malloc(N*sizeof(BTnode *));   //创建队列单元
    front= rear= 0;
    Q[++rear]= root;
    while(front-rear){                          //while(当队不空时)
        p= Q[++front];
        cout<<setw(3)<<p->data;                 //输出出队元素
        if( p->left) Q[++rear]= p->left;
        if(p->right) Q[++rear]= p->right;       //出队元素为入队元素的左右子女,实现按层遍历
    }

}

/*前序递归遍历【根——>左——>右】*/
void BtSearchTree::Forder(BTnode * root){
    if(root) {
        cout<<setw(3)<<root->data;
        Forder(root->left);
        Forder(root->right);
    }
}

/*前序非递归遍历                    在作前序非递归遍历的时候 要借用栈来实现*/
void BtSearchTree::UnrecurForder(BTnode * root){
    BTnode **S;                                 
    BTnode *p;
    S=(BTnode **)malloc(N*sizeof(BTnode *));    //声明栈,分配动态存储空间
    int top=-1;
    S[++top]=root;                              //根节点入栈
    while(top+1){
        p=S[top--];
        cout<<setw(3)<<p->data;                 //输出出出栈元素
        if(p->right) S[++top]=p->right;         //右先入栈,左再入栈
        if( p->left) S[++top]= p->left;
    }
    free(S);
}
/*中序递归遍历【左——>根——>右】*/
void BtSearchTree::INorder(BTnode * root){
    if(root){
        INorder(root->left);
        cout<<setw(3)<<root->data;
        INorder(root->right);
    }
}

/*中序非递归遍历【左——>根——>右】*/
void BtSearchTree::UnrecurINorder(BTnode * root){
    int top=-1;
    BTnode **S,*p;
    S=(BTnode **)malloc(N*sizeof(BTnode *));
    p=root;
    /*先将二叉树的左列子女入栈*/
    while(p){
        S[++top]= p;
        p=p->left;
    }
    /*栈不为空时循环:出站一个元素,判断出栈元素的右子女是否为空,不为空则入栈其左线子女*/
    while(top+1){
        p=S[++top];
        cout<<setw(3)<<p->data;
        if(p->right){
            p=p->right;
            while(p->right){
                S[++top]= p;
                p=p->left;          //入栈其左线子女
            }
        }
    }
    free(S);
}

/*后序递归遍历*/
void BtSearchTree::Laorder(BTnode *root){
    if(root){
        Laorder( root->left);
        Laorder(root->right);
        cout<<setw(3)<<root->data;
    }
}

/*使用队列 创建完全二叉树;由完全二叉树的性质可知,使用顺序存储满足完全二叉树的存储特点,便采用队列*/

BTnode * BtSearchTree::CreateCompleteTree(int a[]){
    BTnode **Q, *pa, *p, *root;
    Q=(BTnode **)malloc(N*sizeof(BTnode *));        //给队列Q 分配单元
    int front,rear;
    front= rear = 0;                                //初始化
    int i;
    root= (BTnode *)malloc(sizeof(BTnode));         //初始化根节点
    root->data= a[0];
    root->left= root->right= NULL;
    pa= root;                                       //使pa 指向根节点
    for(i= 1; i<N; i++){                            //对a[1]~a[N]的数据进行遍历,最终完成完全二叉树的遍历
        p= (BTnode *)malloc(sizeof(BTnode));
        p->data= a[i];
        p->left= p->right = NULL;
        if(!pa->left   )                            //如果待插结点pa 左空, p插在左边
            pa->left =p;
        else{                                       //左不空,右空,p插在右边
            pa->right= p;
            pa= Q[++front];                         //pa 出队
        }
        Q[++rear]= p;                               //p  入队
    }
    free(Q);
    return root;
}








int main(void){

/*  在这里,输入创建二叉树的数组元素,二叉搜索树按照先序遍历的顺序输入数字
    int a[N],i;
    cout<<"请输入要创建的数组的元素个数n:"<<N<<endl;
    cout<<"创建数组用以放入创建二叉树的元素,数组顺序使用中序遍历的顺序输入:"<<endl;
    for(i=0;i<N;i++)
        cin>>a[i];
    cout<<"您刚才输入的数组是:";
    for(i=0;i<N;i++)
        cout<<setw(3)<<a[i];
    cout<<endl;
    数组创建完成,接下来创建类对象,进行二叉树的一系列操作                                                                           */
    int a[N]={5,3,2,4,7,6,8,9};

    BTnode* root;
    int count1,count2;
    int key= 7;

    BtSearchTree text;
    root=text.CreateCompleteTree(a);
    cout<<"先序遍历————";
    text.Forder(root);
    cout<<endl;
    cout<<"后序遍历————";
    text.Laorder(root);
    cout<<endl;
    count1=text.CountLeafnode(root);
    cout<<"叶子结点个数:"<<count1<<endl;
    count2=text.DepthBTSeaTree(root);
    cout<<"完全二叉树深度:"<<count2<<endl;
    cout<<endl;








    cout<<endl;
    return 0;
}



























发布了31 篇原创文章 · 获赞 17 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览