【C/C++笔试练习】双向循环链表、循环链表特点、双向链表插入、栈的特点、循环队列元素、层序遍历、二叉排序树的高、堆排序、散列表的查找长度、选择排序、小易的升级之路、找出字符串中第一个只出现一次的字符

文章详细介绍了C++中的数据结构和算法概念,包括双向循环链表的删除操作、循环链表特性、链表插入、栈的存储优化、循环队列元素分析、层序遍历、二叉搜索树深度、堆排序、散列表查找长度以及选择排序和字符串处理问题,特别是找出字符串中第一个只出现一次的字符的几种方法。
摘要由CSDN通过智能技术生成

C/C++笔试练习

选择部分

(1)双向循环链表

  在有序双向链表中定位删除一个元素的平均时间复杂度为

  A. O(1)
  B. O(N)
  C. O(logN)
  D. O(N*logN)

  答案:B

  在有序双向链表中,我们不能像在有序数组中那样使用二分查找来快速定位元素。在链表中,我们必须从头开始遍历链表,直到找到要删除的元素或到达链表的末尾。这个过程的时间复杂度是 O(N),其中 N 是链表的长度。

  删除一个元素的过程也是 O(1) 时间复杂度,因为它仅仅涉及更改一些链接,不涉及数据复制或移动。但由于定位元素的时间复杂度是 O(N),因此总的时间复杂度是 O(N)。

  

(2)循环链表特点

  在一个以 h 为头指针的单循环链表中,p 指针指向链尾结点的条件是( )

  A. p->next== NULL
  B. p->next== h
  C. p->next->next== h
  D. p->data== -1

  答案:B

  p->next == p;这个条件检查 p 是否指向链表的尾部。在单循环链表中,尾节点的 next 指针指向头结点,即 h。因此,这个条件是正确的。
在这里插入图片描述

  

(3)双向链表插入

  在双向链表中指针p的结点前插入一个指针q的结点操作是()

  A. p->Llink=q;q->Rlink=p;p->Llink->Rlink=q;q->Llink=q;
  B. p->Llink=q;p->Llink->Rlink=q;q->Rlink=p;q->Llink=p->Llink;
  C. q->Rlink=p;q->Llink=p->Llink;p->Llink->Rlink=q;p->Llink=q;
  D. q->Llink=p->Llink;q->Rlink=q;p->Llink=q;p->Llink=q;

  答案:C

  我们需要明确双向链表中插入一个节点的基本步骤:将新节点q的右链接指向p节点,将新节点q的左链接指向p节点的左链接,更新p节点的左链接的右链接指向新节点q,将p节点的左链接指向新节点q。

在这里插入图片描述

  

(4)栈的特点

  若用数组S[0…n]作为两个栈S1和S2的存储结构,对任何一个栈只有当S全满时才不能做入栈操作。为这两个栈分配空间的最佳方案是

  A. S1的栈底位置为0,S2的栈底位置为n
  B. S1的栈底位置为0,S2的栈底位置为n/2
  C. S1的栈底位置为1,S2的栈底位置为n/2

  答案:A

  当S1的栈底位置为0,S2的栈底位置为n时,两个栈可以有最大的分配空间。
在这里插入图片描述

  

(5)循环队列元素

  循环队列的存储空间为 Q(1:200) ,初始状态为 front=rear=200 。经过一系列正常的入队与退队操作后, front=rear=1 ,则循环队列中的元素个数为( )

  A. 0或200
  B. 1
  C. 2
  D. 199

  答案:A

  在循环队列中,front 和 rear 分别表示队头和队尾的指针。初始状态为front=rear=200,表示队列为空。当 front 和 rear 相等时,队列可能为空(front 和 rear 指向同一个位置)或队列可能为满(front 和 rear 指向同一个位置,但队列中有一个元素)。

  通常我们为了避免这种情况,所以我们会浪费循环队列中的一个元素,以用来区分队列为空和队列为满的情况。
在这里插入图片描述

  

(6)层序遍历

  将一棵二叉树的根结点放入队列,然后递归的执行如下操作,将出队结点所有子结点加入队。以上操作可以实现哪种遍历()

  A. 前序遍历
  B. 中序遍历
  C. 后序遍历
  D. 层序遍历

  答案:D

  层序遍历是按照二叉树的层级进行遍历, 从上到下、从左到右。根据题目描述的操作,每次从队列中取出一个节点,将其所有子节点加入队列,就是二叉树的层序遍历。

  

(7)二叉排序树的高

  已知数据元素为(34,76,45,18,26,54,92,65),按照依次插入节点的方法生成一棵二叉排序树,则该树的深度为()

  A. 7
  B. 6
  C. 4
  D. 5

  答案:D

在这里插入图片描述

  

(8)堆排序

  有 1000 个无序的整数,希望使用最快的方式找出前 50 个最大的,最佳的选择是( )

  A. 冒泡排序
  B. 基数排序
  C. 堆排序
  D. 快速排序

  答案:C

  冒泡排序:这种方法适用于小规模数据的排序,但对于大量数据,其效率较低。因此,它不适合此问题。

  基数排序:这是一种非比较排序算法,适用于整数或字符串。它的时间复杂度是O(n),但它需要额外的空间来执行。由于我们只有1000个整数,而且要求前50个最大的数,基数排序可能不是最高效的方法。

  堆排序:这是一个非常高效的排序算法,其时间复杂度为O(nlogn)。它特别适合找出数组中的最大或最小元素。通过构建一个最大堆,我们可以快速找到前50个最大的整数。

  快速排序:这是一个常用的排序算法,其平均时间复杂度为O(nlogn)。但在最坏的情况下,其时间复杂度为O(n^2)。因此,对于这个特定的问题,快速排序可能不是最佳选择。

  

(9)散列表的查找长度

  已知一个线性表(38,25,74,63,52,48),假定采用散列函数h(key) = key%7 计算散列地址,并散列存储在散列表A[0…6]中,若采用线性探测方法解决冲突,则
在该散列表上进行等概率成功查找的平均查找长度为()

  A. 1.5
  B. 1.7
  C. 2.0
  D. 2.3

  答案:C

在这里插入图片描述

  

(10)选择排序

  下面的排序方法中,关键字比较次数与记录的初始排列无关的是______。

  A. 希尔排序
  B. 冒泡排序
  C. 直接插入排序
  D. 直接选择排序

  答案:D

  希尔排序:这是一种基于插入排序的算法,通过比较相隔一定间隔的元素来工作。关键字比较次数与记录的初始排列有关,因为间隔序列的选择会影响比较和交换的次数。

  冒泡排序:这是一种简单的排序算法,通过重复地遍历待排序的记录序列,比较相邻的两个记录,并根据需要交换它们的位置。关键字比较次数与记录的初始排列有关,因为需要多次遍历才能将最大(或最小)的元素移到正确的位置。

  直接插入排序:这是一种简单的排序算法,通过将每个记录逐个插入到已排序的子序列中来工作。关键字比较次数与记录的初始排列有关,因为插入位置和比较次数会受到初始排列的影响。

  直接选择排序:这是一种简单的排序算法,通过重复地遍历待排序的记录序列,找到最小(或最大)的元素,并将其放在已排序序列的末尾。 关键字比较次数与记录的初始排列无关,因为无论初始排列如何,我们都只需要进行n次比较和交换操作(n为记录数)。

            

编程题 day22

小易的升级之路

小易的升级之路

  解题思路:本题的能力值的累加分两种情况,一种是直接相加bi,一种是累加当前能力值于bi的最大公约数。最大公约数可以通过碾转相除法求得:a与b的最大公约数相当于b与a,b余数的最大公约数。如果求余结果为0, 则b为所求结果。

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

//辗转相除法
int GCD(int a, int b) 
{
    int c;
    while (c = a % b) 
    {
        a = b;
        b = c;
    }
    return b;
}

int getPowerValue(int n, int power) 
{
    vector<int> num(n);
    for (int i = 0; i < n; ++i) //输入敌人的防御值
        cin >> num[i];
    for (int i = 0; i < n; ++i) 
    {
        if (power >= num[i])
            power += num[i];
        else
            power += GCD(power, num[i]);
    }
    return power;
}

int main() 
{
    int n, a, power;
    while (cin >> n >> a) 
    {
        power = getPowerValue(n, a);
        cout << power << endl;
    }
    return 0;
}

  

找出字符串中第一个只出现一次的字符

找出字符串中第一个只出现一次的字符

  解题思路:用一个数组的每一个位置表示对应的位置。对应的字符位置存放字符出现的次数。统计完之后,遍历输入字符,遇到第一个只出现一次的字符就停止。

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

//暴力法 O(n^2)
char getFirstOneChar_1(const string& str) 
{
    int j;
    for (int i = 0; i < str.size(); ++i) 
    {
        for (j = 0; j < str.size(); ++j) 
        {
            if (j == i) //排除自己跟自己比较
                continue;
            if (str[j] == str[i])
                break;
        }
        if (j >= str.size())
            return str[i];
    }
    return -1;
}

//hash法 O(n)
char getFirstOneChar_2(const string& str) 
{
    int hash[256] = {0};
    for (int i = 0; i < str.size(); ++i) //统计字符的次数
        hash[str[i]]++;
    for (int i = 0; i < str.size(); ++i) 
    {
        if (hash[str[i]] == 1)
            return str[i];
    }
    return -1;
}

//string类函数查找法
char getFirstOneChar_3(const string& str) 
{
    for (int i = 0; i < str.size(); ++i) 
    {
        int index1 = str.find(str[i]);
        int index2 = str.rfind(str[i]);
        if (index1 == index2)
            return str[i];
    }
    return -1;
}

int main() 
{
    string str;
    char res;
    while (getline(cin, str)) 
    {
        res = getFirstOneChar_3(str);
        if (res == -1)
            cout << -1 << endl;
        else
            cout << res << endl;
    }
    return 0;
}
  • 29
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鳄鱼麻薯球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值