DS05-查找

0.PTA得分截图

1.本周学习总结

1.1 总结查找内容

1.2 谈谈你对查找的认识及学习体会

2.PTA题目介绍

2.1 7-1 是否完全二叉搜索树

  • 题目

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

输入格式:
输入第一行给出一个不超过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

  • 代码

#include<iostream>
#include<string.h>//memset头文件是string.h,记成stdlib.h了
using namespace std;
int tree[100], num;
int N;
void AddTree(int i, int d);//加入到二叉搜索树中
int main()
{
    int i = 0;
    int j = 0;//j记录结点的总数量
    int flag = 0;//flag记录输出的个数

    cin >> N;//给出一个不超过20的正整数N

    memset(tree, -1, sizeof(tree));//初始化树的所有结点为-1

    for (i = 0; i < N; i++)//输入N个互不相同的正整数
    {
        cin >> num;
        AddTree(1, num);//加入到二叉搜索树中
    }

    while (flag < N)
    {
        while (tree[j] == -1)//当j结点为-1,即该结点没有存入的数值
        {
            j++;//去下一个结点
        }

        if (flag)//不是0,前面需要输出空格
        {
            cout << " " << tree[j];
        }
        else//flag为0,即第一个,直接输出
        {
            cout << tree[j];
        }

        j++;
        flag++;
    }

    if (j == N + 1)//j等于N+1,表示已经输出了N个数,因为j++是放在输出后面的
    {
        cout << endl << "YES";//需要换行
    }
    else
    {
        cout << endl << "NO";
    }
}

void AddTree(int i, int d)//加入到二叉搜索树中
{
    if (tree[i] == -1)//该结点为空,没有孩子
    {
        tree[i] = d;//将输入的数字存入该结点
        return;
    }

    if (d > tree[i])//如果大于该结点
    {
        AddTree(i * 2, d);//函数递归找其左孩子继续判断,左子树与根节点位置的关系是2*i
    }
    else//如果小于该结点
    {
        AddTree(i * 2 + 1, d);//函数递归找其右孩子继续判断,右子树与根节点位置关系是2*i+1
    }
    //因为题目已经说明是N个互不相同的正整数,所以不用考虑等于
}

2.1.1 该题的设计思路

  • 题面分析

    • 首先这道题先要输入N,代表接下来要将N个数构建一棵二叉搜索树;然后接下来就是输入这N个数。
    • 在构建二叉搜索树时,需要注意的是题干中的“定义为左子树键值大,右子树键值小”,也就是比父结点大的数在左孩子处,比父结点小的数在右孩子处,和我们平时构建的不一样;构建时还需要按照给定数字顺序来构建。
    • 在输出时,需要层次遍历二叉搜索树,然后将遍历的结果输出,注意空格问题;当该二叉搜索树是完全二叉树(若设二叉树的深度为k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k层所有的结点都连续集中在最左边,这就是完全二叉树)时,输出“YES”;其他情况输出“NO”。
  • 图文介绍

(1)完全二叉树:若设二叉树的深度为k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k层所有的结点都连续集中在最左边,这就是完全二叉树。

(2)样例1构建的二叉搜索树

层次遍历结果:38 45 24 58 42 30 12 67 51,符合完全二叉树,输出YES
(3)样例2构建的二叉搜索树

层次遍历结果:38 45 24 58 42 12 67 51,第三层的12没有兄弟,但是接下来还有第四层,所以不符合完全二叉树,输出NO

  • 复杂度分析
    • 建立二叉搜索树的时间复杂度为O(log2n),层次遍历二叉树的时间复杂度为O(n),所以总的时间复杂度为O(log2n)

2.1.2 该题的伪代码


tree[100]存储各结点的值
num为结点的数值
N为输入的数目

int main()
{
    i为遍历序号
    j记录结点的总数量
    flag记录输出的个数

    输入一个不超过20的正整数N

    初始化树的所有结点为-1

    for (i = 0 to i < N,i++)//输入N个互不相同的正整数
    {
        输入正整数num
        调用函数AddTree()加入到二叉搜索树中,从1开始才能符合后面的结点间的2*i和2*i+1的关系
    }

    while (flag 小于 N)
    {
        while (tree[j]为 - 1)
        {
            该结点没有存入的数值,去下一个结点
        }

        if (flag不是0)
        {
            输出tree[j],且前面需要输出空格
        }
        else
        {
            直接输出tree[j]
        }

        j++,flag++
    }

    if (j 等于 N + 1)
    {
        换行输出YES
    }
    else
    {
        换行输出NO
    }
}

void AddTree(int i, int d)
{
    if (tree[i] 等于 - 1)
    {
        将输入的数字存入该结点
            返回
    }

    if (d 大于 该结点tree[i])
    {
        函数递归找其左孩子继续判断,左子树与根节点位置的关系是2* i
    }
    else
    {
        函数递归找其右孩子继续判断,右子树与根节点位置关系是2* i + 1
    }
}

2.1.3 PTA提交列表

  • memset头文件应该是string.h,记成stdlib.h了,所以导致了编译错误
  • 最后输出YES或者NO时的判断由于j++是放在输出后面的,所以应该是jN+1,不是jN

2.1.4 本题涉及的知识点

  • memset函数:
    • memset函数是计算机中C/C++语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值,这个函数通常为新申请的内存做初始化工作。
    • 本题我所使用的是memset()的深刻内涵是:用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化。例如:memset(a,'\0',sizeof(a));
    • memset函数在头文件:#include<string.h>中
  • 运用了创建二叉树时左子树与根节点位置的关系是2i、右子树与根节点位置关系是2i+1的关系
  • 判断是否是完全二叉树时通过j将遍历过的结点的数量记录下来,然后进行判断,且层次遍历直接按照下标顺序来判断即可

2.2 题目

  • 题目



  • 代码



2.2.1 该题的设计思路

2.2.2 该题的伪代码




2.2.3 PTA提交列表

2.2.4 本题涉及的知识点

2.3 7-5(哈希链) 航空公司VIP客户查询

  • 题目

不少航空公司都会提供优惠的会员服务,当某顾客飞行里程累积达到一定数量后,可以使用里程积分直接兑换奖励机票或奖励升舱等服务。现给定某航空公司全体会员的飞行记录,要求实现根据身份证号码快速查询会员里程积分的功能。

输入格式:
输入首先给出两个正整数N(≤10^5)和K(≤500)。其中K是最低里程,即为照顾乘坐短程航班的会员,航空公司还会将航程低于K公里的航班也按K公里累积。随后N行,每行给出一条飞行记录。飞行记录的输入格式为:18位身份证号码(空格)飞行里程。其中身份证号码由17位数字加最后一位校验码组成,校验码的取值范围为0~9和x共11个符号;飞行里程单位为公里,是(0, 15 000]区间内的整数。然后给出一个正整数M(≤10^5),随后给出M行查询人的身份证号码。

输出格式:
对每个查询人,给出其当前的里程累积值。如果该人不是会员,则输出No Info。每个查询结果占一行。

输入样例:
4 500
330106199010080419 499
110108198403100012 15000
120104195510156021 800
330106199010080419 1
4
120104195510156021
110108198403100012
330106199010080419
33010619901008041x

输出样例:
800
15000
1000
No Info

  • 代码



2.3.1 该题的设计思路

  • 题面分析

    • 首先理解题目数据:
      • N表示的是接下来有N条飞行记录,但是这N条飞行记录的持有者都是会员。
      • K表示的是会员的飞行里程的最低要求,其中需要注意的是低于K公里的航班也按K公里累积,即:比如规定最低里程K为20时,当某客户飞行里程为5,按照20算;飞行里程为20时,即为20;飞行里程超过20时,就按实际飞行里程计算。
      • M表示的是要查询M个人的里程累积值,但是前提是这个人是会员,也就是前面所给的N条飞行记录里是否有这个人的身份证号码;如果他不是会员,即飞行记录里没有他,就输出No Info;格式上要注意每个查询结果占一行。
    • 然后分析所给示例:
      • 题目中首先给了4条飞行记录,以及最低飞行里程要求为500公里。
      • 第一个和第二个要查询的人都是会员,且飞行里程都超过了500,所以输出其实际的飞行里程就可以。
      • 而第三个要查询的人,4条记录中的第一条和第四条是这个人的,且都没有达到最低要求500,所以相当于是两个500,也就是身份证号为330106199010080419的这个人相当于累计了1000公里的飞行里程,所以输出的是1000。
      • 第四个人,在前面的飞行记录中没有他的身份证号码,也就是说他不是会员,所以要No Info。
  • 解题思路

  • 复杂度分析

2.3.2 该题的伪代码




2.3.3 PTA提交列表

2.3.4 本题涉及的知识点

猜你喜欢

转载自www.cnblogs.com/xyx129221/p/12897663.html
DS
今日推荐