L3-010 是否完全二叉搜索树(30 分)

L3-010 是否完全二叉搜索树(30 分)

将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果。
输入格式:

输入第一行给出一个不超过20的正整数N;第二行给出N个互不相同的正整数,其间以空格分隔。
输出格式:

将输入的N个正整数顺序插入一个初始为空的二叉搜索树。在第一行中输出结果树的层序遍历结果,数字间以1个空格分隔,行的首尾不得有多余空格。第二行输出YES,如果该树是完全二叉树;否则输出NO。
输入样例1:

9
38 45 42 24 58 30 67 12 51

输出样例1:

38 45 24 58 42 30 12 67 51
YES

输入样例2:

8
38 24 12 45 58 67 42 51

输出样例2:

38 45 24 58 42 12 67 51
NO

思路:
一开始想的是只要没有只有右叶子的节点就可以,显然是不对的(其实没那么显然,要自己动手画画),如果左、右子树都完全,但深度相差超过2就符合我的条件,但不是完全二叉树。
后来想的是标号,但这种方法最底层节点的NULL和缺的点的NULL是一样的,无法区分。
最后看了题解:还是用广搜的思路,用队列把所有节点都层序入队,所有的NULL也入队(其实队里直存指针),如果遇到第一个NULL就退出,开始遍历队列里剩下的指针,如果全为NULL,就是完全二叉树;如果还有指针指向节点就不是完全二叉树。
下面来简单分析一下,上图这里写图片描述
下文中的c点表示当前节点。
首先层序遍历,所有节点肯定只访问一遍。这种算法的特点是当把c从队列里拿出来时,它的前面节点的下一层肯定都在队列里面了。所以如果c为空,那么要想是完全二叉树,它的后面就不应该有节点了。有朋友可能会说,如果他的前面恰好都为空,而c点的后面节点还有节点呢,这种情况显然不可能,因为c的下一层后半部分要想有节点,那c的后面一点有节点,这样显然不是二叉树。
总结:
1.这种判断点是否按顺序出现,应该想到队列的(按顺序就是排队嘛),因为这是一个天然的队,如果依次入队,遇到第一个空洞时,后面就不应该有节点了,当然只想到队还是不好做,细节还是要多练,多思考才能做出来。比如这个题要把c点的左右节点统统入队,c点第一次为NULL时就退出循环,这点也是很难想的。
2.队的入队,和出队一定要分开想清楚,这样不容易想当然。分别时两次操作,如果混为一谈,或者指向入不想出,那就没了队的优点了。
3.自己脑补模拟队时,当入队出现特殊元素时,和出队出现特殊元素时也要区分,这个题就是很好的例子。

#include<iostream>
#include<queue>
using namespace std;

struct node{
    node *l, *r;
    int val;
    int num;
};

node* createRoot(int val);

bool isCmplt(node* r);

bool insrt(node *r, int val);

bool del(int val);

void levelshow(node* r);

int N;




int main(){
    int a;
    cin >> N >> a;
    node *root = createRoot(a);
    for(int i = 1; i < N; i++){
        cin >> a;
        insrt(root, a);
    }
    levelshow(root);
    if(isCmplt(root))
        cout << "YES" << endl;
    else
        cout << "NO" << endl;
    return 0;
}




node* createRoot(int val){
    node *root = new node();
    root->val = val;
    root->l = NULL;
    root->r = NULL;
    return root;
}

bool insrt(node *cur, int val){
    if(val > cur->val){
        if(cur->l != NULL)
            insrt(cur->l, val);
        else{
            node *tmp = new node();
            tmp->l = NULL;
            tmp->r = NULL;
            tmp->val = val;
            cur->l = tmp;
            return true;
        }
    }
    else if(val < cur->val){
        if(cur->r != NULL){
            insrt(cur->r, val);
        }
        else{
            node *tmp = new node();
            tmp->l = NULL;
            tmp->r = NULL;
            tmp->val = val;
            cur->r = tmp;
            return true;
        }
    }
    else{
        cout << "already exist" << endl;
        return false;
    }
}

void levelshow(node *cur){
    queue<node*> q;
    q.push(cur);
    int flag = 0;
    while(!q.empty()){
        cur = q.front();
        cout << cur->val;
        if( (q.size() > 1 || flag == 0) && N > 1){
            cout << " ";
            flag = 1;
        }
        q.pop();
        if(cur->l != NULL)
            q.push(cur->l);
        if(cur->r !=NULL)
            q.push(cur->r);
    }
    cout << endl;
}

bool isCmplt(node *cur){
    queue<node*> q;
    q.push(cur);
    while(cur != NULL){
        q.push(cur->l);
        q.push(cur->r);
        q.pop();
        cur = q.front();
    }
    while(!q.empty()){
        cur = q.front();
        if(cur != NULL)
            return false;
        q.pop();
    }
    return true;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值