文章目录
C/C++笔试练习
选择部分
(1)单链表插入节点
设一个有序的单链表中有n个结点,现要求插入一个新结点后使得单链表仍然保持有序,则该操作的时间复杂度()
A. O(log2n)
B. O(1)
C. O(n2)
D. O(n)
答案:D
在有序单链表中插入一个新结点并保持有序,通常需要遍历链表找到合适的位置插入新结点。遍历链表的时间复杂度是O(n),因为最坏情况下可能需要检查链表中的每个结点。 因此,插入新结点并保持有序的时间复杂度是O(n)。
(2)单链表删除操作
在一个单链表中,若删除 P 所指结点的后续结点,则执行?
A. p = p->next;p->next = p->next->next;
B. p->next = p->next;
C. p->next = p->next->next;
D. p = p->next->next
答案:C
我们删除一个节点需要:找到要删除的节点的前驱节点,将前驱节点的 next 指针指向要删除节点的后继节点,释放要删除的节点的内存。
(3)链表性质
设一个链表最常用的操作是在末尾插入结点和删除尾结点,则选用()最节省时间
A. 带头结点的双循环链表
B. 单循环链表
C. 带尾指针的单循环链表
D. 单链表
答案:A
带头结点的双循环链表:由于有两个头结点,我们可以通过任意一个头结点快速访问到链表的尾节点。插入和删除尾节点的时间复杂度都是O(1)。
单循环链表:如果从头结点开始访问,找到尾节点的时间复杂度是O(n)。
带尾指针的单循环链表:虽然尾指针指向尾节点,但如果我们需要从头部或中间访问链表,时间复杂度仍然是O(n)。
单链表:从头节点开始访问,找到尾节点的时间复杂度是O(n)。
(4)链式栈
单链表实现的栈,栈顶指针为Top(仅仅是一个指针),入栈一个P节点时,其操作步骤为()
A. Top->next=p;
B. p->next=Top->next;Top->next=p;
C. p->next=Top;Top=p->next;
D. p->next=Top;Top=Top->next;
答案:B
我们需要找到栈顶元素。这通常是通过指针Top来完成的,然后将新节点p放在链表的头部,这需要将其next指针指向当前的Top所指向的节点,最后将Top指针指向新节点p,这样我们就完成了入栈操作。
(5)链式队列
用不带头结点的单链表存储队列,其队头指针指向队头结点,队尾指针指向队尾结点,则在进行出队操作时()
A. 仅修改队头指针
B. 仅修改队尾指针
C. 队头、队尾指针都可能要修改
D. 队头、队尾指针都要修改
答案:C
当链式队列中有多个元素时,只需要修改队头指针,但是如果队列中只有一个元素的时候,队头和队尾指针就都需要修改了。
(6)二叉树的叶子结点
在具有 2n 个结点的完全二叉树中,叶子结点个数为()
A. n
B. n+1
C. n-1
D. n/2
答案:A
(7)二叉排序树的性质
在任意一棵非空二叉排序树T1中, 删除某结点v之后形成二叉排序树 T2,再将v 插入T2形成二叉排序树T3。下列关于T1与T3的叙述中,正确的是( )。
I.若 v 是 T1的叶结点,则 T1 与 T3 不同
II. 若 v 是 T1的叶结点,则 T1与 T3相同
III.若 v 不是 T1 的叶结点,则 T1 与 T3 不同
IV.若v 不是 T1 的叶结点,则 T1 与 T3 相同
A. 仅 I、 III
B. 仅 I、 IV
C. 仅 II、 III
D. 仅 II、 IV
答案:C
1.若 v 是 T1的叶结点,则 T1与 T3相同
当v是叶节点时,T1和T3只是对叶子进行简单的操作,整体的二叉排序树不变,所以T1和T3是相同的。所以叙述II是正确的。
2.若 v 不是 T1 的叶结点,则 T1 与 T3 不同
如果v不是叶节点,那么删除v后,T1将失去一些性质(比如某些节点的子节点或父节点),这可能导致T1不再是二叉排序树。而插入v后形成的T3,由于v的插入位置可能破坏T2的二叉排序性质。
(8)堆的特征
下述二叉树中,哪一种满足性质:从任一结点出发到根的路径上所经过的结点序列按其关键字有序()
A. 二叉排序树
B. 哈夫曼树
C. AVL树
D. 堆
答案:D
对于任意一个堆中的节点,它的左节点和右节点一定大于(小堆)或大于(大堆)根节点, 满足此性质,所以从任一结点出发到根的路径上所经过的结点序列按其关键字有序。
(9)哈希表散列法
散列文件使用散列函数将记录的关键字值计算转化为记录的存放地址。由于散列函数不是一对一的关系,所以选择好的( )方法是散列文件的关键。
A. 散列函数
B. 除余法中的质数
C. 冲突处理
D. 散列函数和冲突处理
答案:D
散列文件是一种利用散列函数将记录的关键字值转化为记录的存放地址的数据结构。由于散列函数不是一对一的关系,所以当两个或多个关键字通过散列函数计算得到相同的地址时,就会发生冲突。为了解决冲突,需要选择合适的冲突处理方法。
因此,选择好的散列函数和冲突处理方法是散列文件的关键。
(10)堆排序
将整数数组(7-6-3-5-4-1-2)按照堆排序的方式原地进行升序排列,请问在第一轮排序结束之后,数组的顺序是()
A. 2-6-3-5-4-1-7
B. 6-2-3-5-4-1-7
C. 6-5-3-2-4-1-7
D. 1-4-7-5-6-3-2
答案:C
编程题 day21
洗牌
解题思路:每次读取一个数之后,算出他经过k次洗牌后的位置,只用一个长度为2n数组用来输出,根据当前数的位置,可以算出经过一次洗牌后的位置,如果当前数小于等于n(即在左手),则他下次出现的位置是 2当前位置,与之对应的当前位置 + n(即在右手)的牌,则他下次出现的位置是 2当前位置 + 1。
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int T, n, k;
cin >> T;
while (T--)
{
cin >> n >> k;
int num = 2 * n;
vector<int> card(num);
for (int i = 0; i < num; ++i)
cin >> card[i];
//开始洗牌
for (int i = 0; i < k; ++i)
{
vector<int> tmp(card.begin(), card.end());
for (int j = 0; j < n; ++j)
{
card[2*j] = tmp[j]; //左手的牌排放的位置
card[2*j+1] = tmp[j+n];//右手的牌排放的位置
}
}
//输出洗牌的顺序
for (int i = 0; i < num - 1; ++i)
cout << card[i] << " ";
cout << card[num - 1] << endl; //最后一张牌后面不能有空格
}
return 0;
}
MP3光标位置
解题思路:通过解析指令,进行移动即可,分两种情况,歌曲数目不大于4和大于4的情况。
#include<iostream>
#include<string>
using namespace std;
int main()
{
int n;
string cmd;
while (cin >> n >> cmd)
{
//将n首歌进行编号1:n,其中num代表当前光标所在的歌曲编号,first代表当前页的第一首歌曲的编号
int num = 1, first = 1;
if (n <= 4)
{
//歌曲总数<=4
for (int i = 0; i < cmd.size(); ++i)
{
//解析命令
if (num == 1 && cmd[i] == 'U')
num = n;
else if (num == n && cmd[i] == 'D')
num = 1;
else if (cmd[i] == 'U')
num--;
else
num++;
}
for (int i = 1; i <= n; ++i)
cout << i << " ";
cout << endl;
cout << num << endl;
}
else
{
//歌曲总数>4
for (int i = 0; i < cmd.size(); ++i)
{
//解析命令
if (first == 1 && num == 1 && cmd[i] == 'U')
{
first = n - 3; //将first跳入最后一页
num = n;
}
else if (first == n - 3 && num == n && cmd[i] == 'D')
{
first = num = 1;
}
else if (first != 1 && num == first && cmd[i] == 'U')
{
first--;
num--;
}
else if (first != n - 3 && num == first + 3 && cmd[i] == 'D')
{
first++;
num++;
}
else if (cmd[i] == 'U')
num--;
else
num++;
}
for (int i = first; i <= first + 3; ++i)
cout << i << " ";
cout << endl;
cout << num << endl;
}
}
return 0;
}