【错题本】考研-2024-数据结构错题本

  1. 1. 数据结构错题本
    1. 1.1. 王道考研-2024-数据结构考研复习指导
      1. 1.1.1. p017.08[交换两数组问题]
      2. 1.1.2. p017.10[数组元素移动问题]
      3. 1.1.3. p017.11[找两升序序列中位数]
      4. 1.1.4. p017.12[找过半主元素][难点]
    2. 1.2. 总结部分
      1. 1.2.1. 1.考研综合题给分方式:

数据结构错题本

王道考研-2024-数据结构考研复习指导

p017.08[交换两数组问题]

已知在一维数组$A[m+n]$中以此存放两个线性表$(a_1,a_2,a_3,…,a_m)$和$(b_1,b_2,b_3,…,b_n)$。编写一个函数,将数组中两个顺序表的位置互换,即将$(b_1,b_2,b_3,…,b_n)$放到$(a_1,a_2,a_3,…,a_m)$的前面。

  • 算法思想:先将数组$A[m+n]$中的全部元素$(a_1,a_2,a_3,…,a_m,b_1,b_2,b_3,…,b_n)$原地逆置为$(b_n,b_{n-1},…,b_1,a_m,a_{m-1},…,a_1)$,再对前n个元素和后m个元素分别使用逆置算法,即可得到$(b_1,b_2,b_3,…,b_n,a_1,a_2,a_3,…,a_m)$,从而实现顺序表的位置互换。
  • tips:实际上是离散数学的德摩根定理,设原序列为AB,想要得到的序列为BA,则AB逆置,即$(AB)^{-1}=B^{-1}A^{-1}$,因此再次对$B^{-1}$和$A^{-1}$进行逆置运算,得到BA

==本题代码如下:==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef int DataType;

//此函数用于逆转数组,left是逆转开始的最左侧,right为最右侧,arraySize是数组大小,用于防止越界
bool Reverse(DataType A[], int left, int right, int arraySize)
{
if(left >= right || right >= arraySize)
return false;
int mid = (left + right) / 2;
for(int i = 0; i <= mid - left; i++)
{
DataType temp = A[left + i];
A[left + i] = A[right - i];
A[right - i] = temp;
}
}

void Exchange(DataType A[], int m, int n, int arraySize)
{
// 下面三步为思路中的三步
Reverse(A, 0, m + n - 1, arraySize);
Reverse(A, 0, n - 1, arraySize);
Reverse(A, n, m + n - 1, arraySize);
}

p017.10[数组元素移动问题]

image-20230329201007799

分析:此题目其实和上面的第八题如出一辙,都是讲一部分换到另一部分,可以使用相同的办法,输入输出稍加改动即可

标准答案:

image-20230329201849313

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bool Reverse(int R[], int from, int to)
{
int i, temp;
for(i = 0; i < (to - from + 1); i++)
{
temp = R[from + i];
R[from + i] = R[to - i];
R[to - i] = temp;
}
}

//数组R,一共有n个元素,向左移动p个元素
//即前p个元素和后n-p个元素换位置
void Exchange(int R[], int n, int p, int arraySize)
{
// 下面三步为思路中的三步
Reverse(A, 0, p - 1);
Reverse(A, p, n - 1);
Reverse(A, 0, n - 1);
}

image-20230330103241208

p017.11[找两升序序列中位数]

image-20230329201052996

分析:本题目所给两数组为升序,因此可以采用中位舍弃法(最佳答案),也可以双指针遍历法。双指针法也可以得到12分

标准答案:

image-20230330103224650

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int M_Search(int A[], int B[], int n)
{
int s1 = 0, d1 = n - 1, m1, s2 = 0, d2 = n - 1, m2;
// 分别表示序列A和B的首位数,末位数和中位数(下标)
while (s1 != d1 || s2 != d2)
{
m1 = (s1 + d1) / 2;
m2 = (s2 + d2) / 2;
if (A[m1] == B[m2])
{
return A[m1]; //满足条件1
}
if (A[m1] < B[m2]) //满足条件2
{
if ((s1 + d1) % 2 == 0) //若元素个数为奇数
{
s1 = m1; //舍弃A的中间点以前的部分,保留中间点
d2 = m2; //舍弃B的中间点以后的部分,保留中间点
}
else //元素个数为偶数
{
s1 = m1 + 1; //舍弃A中间点及以前的部分
d2 - m2; //舍弃B的中间点以后的部分,保留中间点
}
}
else //满足条件3
{
if ((s1 + d1) % 2 == 0) //若元素个数为奇数
{
d1 = m1; //舍弃A的中间点以后的部分,保留中间点
s2 = m2; //舍弃B的中间点以前的部分,保留中间点
}
else //元素个数为偶数
{
d1 = m1; //舍弃A的中间点以后的部分,保留中间点
s2 = m2 + 1; //舍弃B中间点及以前的部分
}
}
}
return (A[s1] < B[s2]) ? A[s1] : B[s2];
}

image-20230330105517142

p017.12[找过半主元素][难点]

image-20230329201138835

分析:解法一(最优):若元素在数组中的个数超过一般,则可以看作一定有连续的存在,故可以通过和其他元素消去的办法,最终数量仍然大于0。解法二(一般):因为题目已知$0\leq a_i \lt n (0\leq i\lt n)$,因此该整数学列是有限个的,创建一个大小为n的整数数组,依次遍历目标数组,遍历到的值为下标的计数数组的值加一。最后再遍历一遍计数数组,最大的值如果超过数组长度的一半则为主元素,否则无主元素

image-20230330120250135

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int Majority(int A[], int n)
{
int i, c, count = 1; //c用来保存候选主元素,count用来计数
c = A[0]; //设置A[0]为候选主元素
for (i = 1; i < n; i++) //查找候选主元素
{
if (A[i] == c)
{
count++; //对A中的候选主元素计数
}
else
{
if (count > 0) //处理不是候选主元素的情况
{
count--;
}
else //更换候选主元素,重新计数
{
c = A[i];
count = 1;
}
}
}
if (count > 0)
{
for (i = count = 0; i < n; i++)//统计候选主元素的实际出现次数
{
if (A[i] == c)
{
count++;
}
}
}
if (count >= n / 2)
{
return c; //确认候选主元素
}
else
{
return -1; //不存在主元素
}
}

image-20230330181211794

总结部分

1.考研综合题给分方式:

  • 考研常见设计思想,程序实现,复杂度分析经典三段式,这种题型实际答案并不唯一,不需要和答案完全相同(==包括算法==),算法不同,只要第三问分析正确,第三问不扣分。复杂度升高通常前两问同时扣分,按照升高的大小扣1-2分,因此,除非专业课要考满分(我),否则无需对答案的完美方法斤斤计较。