- P18开始的习题
- 算法真美妙
- 不保证正确,欢迎讨论,本质是伪代码,只是一个思路,实现还需要考虑一些细节
文章目录
- Seqlist
- 1. 删除最小元素
- 2. 顺序表逆置
- 3. 删除所有值为x的元素
- 4. 删除范围元素
- 5. 删除范围元素(与第四题相似)
- 6. 删除重复元素
- 7. 合并两个有序数组
- 8. 两个链表换位
- 9. 二分查找
- 10. [2010统考真题]循环移动
- 11. [2011统考真题]找两个顺序表合并的中位数
- 12. [2013统考真题]出现超过一半的元素
- 13. [2018统考真题] 数组未出现最小正整数
- 14. [2020统考真题]三元数组最小距离
1. 删除最小元素
从顺序表中删除具有最小值的元素( 假设唯一)并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; //算法思路:遍历顺序表,如果比value小,value就等于它,并且记录该数据的下标,最后将最后一个字符与之交换 bool Del_Min(SL& ps, SLDateType& value) { //如果为空,返回错误 if (ps.size == 0) { return false; } //记录数组下标 size_t index = 0; for (size_t i = 0; i < ps.size; i++) { //如果比value小赋值给value if (value > ps.a[i]) { value = ps.a[i]; index = i; } } //交换 //ps.a[index] = ps.a[ps.size - 1]; //这里template void swap (T& a, T& b); swap(ps.a[index], ps.a[ps.size - 1]); ps.size--; return true; }
2. 顺序表逆置
设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为0(1)。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; //算法思路:两个指针指向left和right,向中间首尾交换,直到相遇 void Reverse(SL& ps) { size_t left = 0; size_t right = ps.size - 1; //直到中间相等或者right比left大退出循环 while (left < right) { //交换 swap(ps.a[left], ps.a[right]); //向中间移动 left++; right--; } }
3. 删除所有值为x的元素
对长度为n的顺序表L,编写一个时间复杂度为0(n)、空间复杂度为0(1)的算法,该算法删除线性表中所有值为x的数据元素。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; //算法思路:遍历,一个指针遇到x停下,另一个指针寻找不是x元素的数值,将该值赋值给该位置。 void Del_Value(SL& ps, SLDateType x) { //记录可以替换的位置 int cur = 0; //寻找x元素 int index = 0; while(index < ps.size -1) { if (ps.a[index] != x) { ps.a[cur] = ps.a[index]; cur++; } //遇到相等的时候cur停止移动,而index继续右移动,将数值赋值给cur(覆盖掉x) index++; } ps.size = cur; }
4. 删除范围元素
从有序顺序表中删除其值在给定值s与t之间(要求s
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; bool Del_ValueRange(SL& ps, const SLDateType& s, const SLDateType& t) { //s和t不合法,数组为空 if (s >= t || ps.size == 0) { return false; } size_t k = 0; for (size_t i = 0; i < ps.size; i++) { if (ps.a[i] > s && ps.a[i] < t) { k++; } else { ps.a[i - k] = ps.a[i]; } } ps.size -= k; return true; }
5. 删除范围元素(与第四题相似)
从顺序表中删除其值在给定值s与t之间(包含s和t,要求s
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; bool Del_ValueRange(SL& ps, const SLDateType& s, const SLDateType& t) { //s和t不合法,数组为空 if (s >= t || ps.size == 0) { return false; } size_t k = 0; for (size_t i = 0; i < ps.size; i++) { if (ps.a[i] >= s && ps.a[i] =< t) { k++; } else { ps.a[i - k] = ps.a[i]; } } ps.size -= k; return true; }
6. 删除重复元素
从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; void Del_Dup_Ele(SL& ps) { size_t cur = 0; for (size_t i = 0; i < ps.size - 1; i++) { if (ps.a[cur] != ps.a[i]) { cur++; ps.a[cur] = ps.a[i]; } } ps.size = cur; }
7. 合并两个有序数组
将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; bool Merge_Ordered_List(const SL& ps1, const SL& ps2, SL& ps3) { if (ps1.size + ps2.size > ps3.size) { return false;//放不下 } int i = 0; int j = 0; int k = 0; while (i < ps1.size && j < ps2.size) { if (ps1.a[i] < ps2.a[j]) { ps3.a[k++] = ps1.a[i++]; } else { ps3.a[k++] = ps2.a[j++]; } } while (i < ps1.size) { ps3.a[k++] = ps1.a[i++]; } while (j < ps2.size) { ps3.a[k++] = ps2.a[j++]; } ps3.size = k; return true; }
8. 两个链表换位
已知在一维数组A[m + n]中依次存放两个线性表(an, a2, a… am)和(b, b2, b3…… bn)。编写一
个函数,将数组中两个顺序表的位置互换,即将(b1, b2, b3… bn,)放在(a1, a2, a3…… am)的前面。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; void Reverse_List(SLDateType* a, int sz) { int begin = 0; int end = sz - 1; while (begin < end) { swap(a[begin], a[end]); } } void Dul_List_Swap_Position(SL& pl, int m, int n) { Reverse_List(pl.a, m); Reverse_List(pl.a + m, n); Reverse_List(pl.a, m + n); }
9. 二分查找
线性表(a1, a2, a3…… an)中的元素递增有序且按顺序存储于计算机内。要求设计一个算法,完成用最少时间在表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; void Binary_Search(SL& pl, SLDateType x) { int left = 0; int right = pl.size; int mid = (left + right) / 2; while (left <= right) { if (x > pl.a[mid]) { left = mid + 1; mid = (left + right) / 2; } if (x < pl.a[mid]) { right = mid - 1; mid = (left + right) / 2; } //找到了 if (pl.a[mid] == x) { break; } } if (pl.a[mid] == x && mid != pl.size - 1) { swap(pl.a[mid], pl.a[pl.size - 1]); } else { for (int i = pl.size - 1; i > mid ; i--) { pl.a[i + 1] = pl.a[i]; } pl.a[mid + 1] = x; } }
10. [2010统考真题]循环移动
设将n (n> 1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0
要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C+或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; void Reverse_List(SLDateType* a, int sz) { int begin = 0; int end = sz - 1; while (begin < end) { swap(a[begin], a[end]); } } void Dul_List_Swap_Position(SL& pl, int m, int n) { Reverse_List(pl.a, m); Reverse_List(pl.a + m, n); Reverse_List(pl.a, m + n); }
11. [2011统考真题]找两个顺序表合并的中位数
一个长度为L (L≥1) 的升序序列s,处在第[L/2]个位置的数称为s的中位数。例如,若序列S1=(11,13,15,17,19),则S的中位数是15, 两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2=(2, 4, 6, 8, 20),则S;和S2的中位数是11.现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++或Java语言描述箕法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; int Find_Mid(SL& p1, SL& p2) { int left1 = 0; int right1 = p1.size - 1; int mid1 = (left1 + right1) / 2; int left2 = 0; int right2 = p1.size - 1; int mid2 = (left2 + right2) / 2; while (left1 != right1 && left2 != right2) { if (p1.a[mid1] < p2.a[mid2]) { //留下右边 if (left1 < right1) { left1 = mid1 + 1; mid1 = (left1 + right1) / 2; } //留下左边 if (left2 < right2) { right2 = mid2 - 1; mid2 = (left2 + right2) / 2; } } //反之 if (p1.a[mid1] > p2.a[mid2]) { //留下右边 if (left2 < right2) { left2 = mid2 + 1; mid2= (left2 + right2) / 2; } //留下左边 if (left1 < right1) { right1 = mid1 - 1; mid1 = (left1 + right1) / 2; } } } return p1.a[mid1] > p1.a[mid2] ? p1.a[mid1] : p2.a[mid2]; }
12. [2013统考真题]出现超过一半的元素
已知一个整数序列A = (a0, a1,an-1),其中0
若存在ap1=ap2= … =apm=x且m> n/2 (0≤pk
出A的主元素。若存在主元素,则输出该元素;否则输出-1. 要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释.
3)说明你所设计算法的时间复杂度和空间复杂度。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; int Main_Ele(SL& pl) { int x = 0; int count = 0; for (size_t i = 0; i < pl.size; i++) { if (x != pl.a[i]) { if (count == 0) { x = pl.a[i]; } else { count--; } } else { count++; } } if (count > 0) { int count = 0; for (size_t i = 0; i < pl.size; i++) { if (x == pl.a[i]) { count++; } } } if (count > pl.size / 2) { return x; } return -1; }
13. [2018统考真题] 数组未出现最小正整数
给定一个含n (n≥1)个整数的数组,请设计一个在时间上尽可能高.
效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3, 2,3}中未出现的最小正
整数是1;数组{1,2,3}中未 出现的最小正整数是4.要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。.
3)说明你所设计算法的时间复杂度和空间复杂度。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; int Min_Pos_Int(SL& pl) { int x = INT_MAX; for (size_t i = 0; i < pl.size; i++) { if (pl.a[i] > 0) { if (pl.a[i] < x) { x = pl.a[i]; } } } return x; }
14. [2020统考真题]三元数组最小距离
定义三元组(a, b,c) (a、 b、c均为正数)的距离D=|a-b| + |b-c| +|c-a|
给定3个非空整数集合S1、S2和S3按升序分别存储在3个数组中。请设计一个尽可能高效的算法 ,计算并输出所有可能的三元组(a,b,c) (a∈S|, b∈S2, cESj) 中的最小距离
例如Si={-1,0,9}, S2={-25,-10, 10,11}, S3= {2, 9, 17,30, 41},则最小距离为2,相应的三元组为(9, 10, 9)。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C语言或C++语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
#define _CRT_SECURE_NO_WARNINGS #include#include using namespace std; typedef int SLDateType; typedef struct SeqList { SLDateType* a; size_t size; size_t capacity; }SL; bool Min(int a , int b, int c) { if (a <= b && a <= c) { return true; } return false; } int ThreeArray_Min_Distance(SL& s1, SL& s2, SL& s3) { //距离 int d = INT_MAX; //数组下标 int i = 0, j = 0, k = 0; while (i < s1.size && j < s2.size && k < s3.size) { int ret = abs(s1.a[i] - s2.a[j]) + abs(s1.a[i] - s3.a[k]) + abs(s2.a[j] - s3.a[k]); if (ret < d) { d = ret; } if (Min(s1.a[i], s2.a[j], s3.a[k])) { i++; } else if (Min(s2.a[j], s1.a[i], s3.a[k])) { j++; } else { k++; } } return d; }



