大家好鸭,目前刚好在复习数据结构,考研数据结构的编程大题真是一个让人头大的问题,从本篇开始我会收录历届编程大题的代码和思路,一起刷起来吧~
完整代码已同步至Gitee码云代码仓库,需要的同学可自取
Gitee代码仓库—408数据结构历年编程题代码(完整可运行)
已知一个带有表头结点的单链表,结点结构
data link 假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第 k k k个位置上的结点( k k k为正整数)。若查找成功,算法输出该结点的data域的值,并返回1;否则,只返回0。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
typedef struct Lnode{ // 链表结点的结构定义
int data;
struct Lnode *next;
}Lnode, *LinkedList;
int Search_k(LinkedList L, int k) {
Lnode *p = L->next, *q = L->next;
// q先移动到第k个结点
for (int i = 1; i < k; i++) {
q = q->next;
if (q == NULL)
return 0;
}
// p和q同时向前移动,直到q移动到最后一个结点
while (q->next != NULL) {
p = p->next;
q = q->next;
}
cout << p->data << endl;
return 1;
}
设将 n ( n > 1 ) n(n>1) n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法,将R中保存的序列循环左移 p ( 0 < p < n ) p_{(0
p(0<p<n)
个位置,即将R中的数据由 ( X 0 , X 1 , . . . , X n − 1 ) (X_0,X_1,...,X_{n-1}) (X0,X1,...,Xn−1)变换为 ( X p , X p + 1 , . . . , X n − 1 , X 0 , X 1 , . . . , X p − 1 ) (X_p,X_{p+1},...,X_{n-1},X_0,X_1,...,X_{p-1}) (Xp,Xp+1,...,Xn−1,X0,X1,...,Xp−1)。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
题解:
// 反转指定的区间,区间左闭右开
void reverse(int R[], int from, int to) {
for (int i = 0; i < (to - from) / 2; i++) {
int temp = R[from + i];
R[from + i] = R[to - i - 1];
R[to - i - 1] = temp;
}
}
void converse(int R[], int n, int p) {
reverse(R, 0, p);
reverse(R, p, n);
reverse(R, 0, n);
}
一个长度为 L ( L > = 1 ) L(L >= 1) L(L>=1)的升序序列 S S S,处在第 [ L / 2 ] [L/2] [L/2]个位置的数称为 S S S的中位数。例如,若序列 S 1 = ( 11 , 13 , 15 , 17 , 19 ) S_1=(11,13,15,17,19) S1=(11,13,15,17,19),则 S 1 S_1 S1的中位数是 15 15 15,两个序列的中位数是它们所有元素的升序序列的中位数。例如,若 S 2 = ( 2 , 4 , 6 , 8 , 20 ) S_2=(2,4,6,8,20) S2=(2,4,6,8,20),则 S 1 S_1 S1和 S 2 S_2 S2的中位数时 11 11 11。现在有两个等长升序序列 A A A和 B B B,设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列 A A A和 B B B的中位数。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
题解:
分别求两个升序序列A和B的中位数,设为a,b,求序列A、B的中位数过程如下:
在保留的两个升序序列中,重复步骤1,2,3直到序列中均只含有一个元素,较小者即为所求。
C++代码如下:
int SearchMedian(int A[], int B[], int n) {
int left1 = 0, right1 = n - 1;
int left2 = 0, right2 = n - 1;
while (left1 + 1 < right1 || left2 + 1 < right2) {
int mid1 = (left1 + right1) >> 1;
int mid2 = (left2 + right2) >> 1;
if (A[mid1] == B[mid2])
return A[mid1];
if (A[mid1] > B[mid2]) {
right1 = mid1;
left2 = mid2;
} else {
left1 = mid1;
right2 = mid2;
}
}
if (A[left1] > B[left2]) {
return min(A[left1], B[right2]);
} else {
return min(A[right1], B[left2]);
}
}
时间复杂度为 O ( l o g 2 N ) O(log_2N) O(log2N),空间复杂度为 O ( 1 ) O(1) O(1)。
假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,可共享相同的后缀存储空间,例如,“loading”和”being“的存储映像如下图所示。
设str1和str2分别指向两个单词所在单链表的头结点,链表结点结构为|data| |next|
,请设计一个时间上尽可能高效的算法,找出由str1和str2所指向的两个链表共同后缀的起始位置(如图中字符i所在结点的位置p)。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
typedef struct LNode {
char data;
struct LNode *next;
}LNode, *LinkedList;
int Length(LinkedList L) {
LNode *p = L;
int count = 0;
while (p->next != NULL) {
p = p->next;
count++;
}
return count;
}
LNode* find_addr(LinkedList str1, LinkedList str2) {
int n = Length(str1), m = Length(str2);
LNode *p = str1, *q = str2;
if (n > m)
for (int i = 0; i < (n - m); i++)
p = p->next;
else
for (int i = 0; i < (m - n); i++)
q = q->next;
while (p->next != NULL && q->next != NULL) {
p = p->next;
q = q->next;
if (p == q)
return p;
}
return NULL;
}
已知一个整数序列 A = ( a 0 , a 1 , . . . , a n − 1 ) A=(a_0,a_1,...,a{n-1}) A=(a0,a1,...,an−1),其中 0 < = a i < n ( 0 < = i < n ) 0<=a_i
0<=ai<n(0<=i<n) 。若存在 a p 1 = a p 2 = . . . = a p m = x a_{p1}=a_{p2}=...=a_{pm}=x ap1=ap2=...=apm=x且 m > n / 2 ( 0 < = p k < n , 1 < = k < = m ) m>n/2_{(0<=p_km>n/2(0<=pk<n,1<=k<=m) ,则称 x x x为 A A A的主元素。例如 A = ( 0 , 5 , 5 , 3 , 5 , 7 , 5 , 5 ) A=(0,5,5,3,5,7,5,5) A=(0,5,5,3,5,7,5,5),则 5 5 5为主元素;又如 A = ( 0 , 5 , 3 , 5 , 1 , 5 , 7 ) A=(0,5,3,5,1,5,7) A=(0,5,3,5,1,5,7),则 A A A中唯有主元素。假设 A A A中的 n n n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出 A A A中的主元素。若存在主元素,则输出该元素;否则输出 − 1 -1 −1。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
using namespace std;
int Majority(int A[], int n) {
int c = A[0], count = 1;
for (int i = 1; i < n; i++) {
if (A[i] == c)
count++;
else {
count--;
if (count == 0) {
c = A[i];
count = 1;
}
}
}
count = 0;
for (int i = 0; i < n; i++)
if (A[i] == c)
count++;
if (count > n / 2)
return c;
return -1;
}
用单链表保存m个整数,结点的结构为
[data][link]
,且|data|<=n
(n为正整数)。现在要求设计一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的结点,仅保留第一次出现的结点而删除其余绝对值相等的结点。例如,若给定的单链表head如下:
head->21->-15->-15->-7->15->^
则删除结点后的head为
head->21->-15->-7->^
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
|data|<=n
,故辅助数组q的大小为n+1,各元素的初值均为0。依次扫描链表中的各结点,同时检查q[|data|]的值,若为0则保留该结点,并令q[|data|] = 1;否则将该结点从链表中删除。typedef struct LNode {
char data;
struct LNode *next;
}LNode, *LinkedList;
void func(LinkedList &L, int n) {
int table[n + 1];
memset(table, 0, sizeof(int) * (n + 1));
LNode *p = L->next;
LNode *pre = L;
while (p != NULL) {
if (table[abs(p->data)] == 0) {
table[abs(p->data)] = 1;
p = p->next;
pre = pre->next;
} else {
LNode *q = p;
pre->next = q->next;
p = p->next;
free(q);
}
}
}
给定一个含 n ( n > = 1 ) n(n>=1) n(n>=1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组 { − 5 , 3 , 2 , 3 } \{-5,3,2,3\} {−5,3,2,3}中未出现的最小正整数是1;数组 { 1 , 2 , 3 } \{1,2,3\} {1,2,3}中未出现的最小正整数是 4 4 4。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
int findMissMin(int A[], int n) {
int B[n + 1];
memset(B, 0, sizeof(int) * (n + 1));
for (int i = 0; i < n; i++)
if (A[i] > 0)
B[A[i]] = 1;
for (int i = 1; i < n + 1; i++)
if (B[i] == 0)
return i;
return n + 1;
}
设线性表L=( a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3,…, a n − 2 a_{n-2} an−2, a n − 1 a_{n-1} an−1, a n a_n an)采用带头结点的单链表保存,链表中的结点定义如下:
typedef struct node { int data; struct node*next; }NODE;
请设计一个空间复杂度为 O ( 1 ) O(1) O(1)且时间是尽可能高效的算法,重新排列L中的各个结点,得到线性表L’=( a 1 a_1 a1, a n a_n an, a 2 a_2 a2, a n − 1 a_{n-1} an−1, a 3 a_{3} a3, a n − 2 a_{n-2} an−2…)。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
typedef struct LNode {
int data;
struct LNode *next;
}LNode, *LinkedList;
void ChangeList(LinkedList &L) {
LNode *slow = L;
LNode *fast = L;
while (fast->next != NULL) { // 寻找中间结点
slow = slow->next;
fast = fast->next;
if (fast->next != NULL)
fast = fast->next;
}
LNode *p = slow->next; // slow所指结点为中间结点,p为链表后半段的首结点
slow->next = NULL;
slow = slow->next;
while (p != NULL) { // 将链表的后半段逆置
LNode *r = p->next;
p->next = slow;
slow = p;
p = r;
}
// 此时slow指向链表的后半段逆置后的首结点
// 令P指向链表前半段的首结点
p = L->next;
// 将链表的后半段插入指定位置
while (slow != NULL) {
LNode *r = slow->next;
slow->next = p->next;
p->next = slow;
p = slow->next;
slow = r;
}
}
定义三元组 ( a , b , c ) (a,b,c) (a,b,c)(a、b、c均为正数)的距离 D = ∣ a − b ∣ + ∣ b − c ∣ + ∣ c − a ∣ D=|a-b|+|b-c|+|c-a| D=∣a−b∣+∣b−c∣+∣c−a∣。给定3个非空整数集合 S 1 、 S 2 和 S 3 S_1、S_2和S_3 S1、S2和S3,按升序分别存储在3个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组 ( a , b , c ) ( a ⊆ S 1 , b ⊆ S 2 , c ⊆ S 3 ) (a,b,c)(a\subseteq{S_1},b\subseteq{S_2},c\subseteq{S_3}) (a,b,c)(a⊆S1,b⊆S2,c⊆S3)中的最小距离。例如 S 1 = { − 1 , 0 , 9 } S_1=\{-1,0,9\} S1={−1,0,9}, S 2 = { − 25 , − 10 , 10 , 11 } S_2=\{-25,-10,10,11\} S2={−25,−10,10,11}, S 3 = { 2 , 9 , 17 , 30 , 41 } S_3=\{2,9,17,30,41\} S3={2,9,17,30,41},则最小的距离为2,相应的三元组为 ( 9 , 10 , 9 ) (9,10,9) (9,10,9)。要求:
1)给出算法的基本设计思想
2)根据设计思想,采用C或C++描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
int findMinofTrip(int A[], int n, int B[], int m, int C[], int p) {
int i = 0, j = 0, k = 0, D_min = int_max;
// D_min如果等于0,那么肯定是最终结果,可以直接结束循环
while (i < n && j < m && k < p && D_min > 0) {
int D = abs(A[i] - B[j]) + abs(B[j] - C[k]) + abs(C[k] - A[i]);
if (D < D_min)
D_min = D;
if (A[i] == min(min(A[i], B[j]), C[k]))
i++;
else if (B[j] == min(min(A[i], B[j]), C[k]))
j++;
else
k++;
}
return D_min;
}