王道数据结构——线性表中顺序表的一些综合应用题

1.长度为n的顺序表中,编写一个时间复杂度为O(n),空间复杂度为O(1)的算法,用于删除线性表中所有值为x的数据元素。(满足要求的数放在第k位上)

 1 #include <cstdio>
 2 
 3 /*输出数组名为a、长度为n的数组*/
 4 void print(int *a, int n){
 5     for(int i = 0;i < n; i++){
 6         printf("%d ", a[i]);
 7     }
 8     puts("");
 9 }
10 
11 /*解法1,第几个不等于x的数就应该在结果的第几个位置上,千万记得最后修改删除后的数组长度为k*/
12 void f1(int *a, int n, int x){
13     int k = 0;
14     for(int i = 0; i < n; i++){
15         if(a[i] != x){
16             a[k++] = a[i];
17         }
18     } 
19     n = k;
20     print(a,k);
21 }
22 
23 /*解法2,用k记录等于x的个数,那么下一个不等于x的数在结果中的位置应该提前k个位置,最后数组的长度减去k*/
24 void f2(int *a, int n, int x){
25     int k = 0;
26     for(int i = 0; i < n; i++){
27         if(a[i] == x)
28             k++;
29         else
30             a[i - k] = a[i];
31     }
32     n -= k;
33     print(a, n);
34 } 
35 
36 int main()
37 {
38     int a[10] = {1,2,3,2,4,2,5,2,6,2};
39     f1(a,10,2);
40 
41     int b[10] = {1,2,3,2,4,2,5,2,6,2};
42     f2(b,10,2);
43     return 0;
44 }

 2.从有序顺序表中删除其值在给定值s与t之间(包括s和t,要求s<t)的所有元素,如果s或者t不合理或者顺序表为空则显示出错信息并退出运行。(掐掉中间这段)

 1 #include <cstdio>
 2 
 3 /*在有序顺序表中,删除值在[s,t]内的元素
 4 只需找到第一个大于或者等于s的位置计数为i,然后往后找第一个大于t的数,将其后的所有元素依次放到i及之后*/ 
 5 
 6 bool Del_s_t(int a[], int n, int s,int t){
 7     if(s>=t || n == 0)
 8         return false;
 9     int i = 0, j = 0;
10     for(i = 0; i < n && a[i] < s; i++);
11     if(i >= n)
12         return false;//全部小于s
13     for(j = i; j < n && a[j] <= t; j++);
14     for(;j < n; j++){
15         a[i++] = a[j];
16     }
17     n = i;
18     //输出 
19     for(int i = 0; i < n; i++){
20         printf("%d ", a[i]);
21     }
22     puts("");
23     return true;
24 }
25 int main()
26 {
27     int a[]={2,4,5,6,7,8,9,11,12,13,14,15,15};
28     Del_s_t(a, 13, 3, 10);
29     return 0;
30 }

3.从顺序表中删除其值在给定值s与t之间(包括s和t,要求s<t)的所有元素,如果s或者t不合理或者顺序表为空则显示出错信息并退出运行(注意与上题的区别是无序的)。

(满足要求的数放在第k位上)

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 void print(int a[], int n){
 6     for(int i = 0; i < n; i++){
 7         printf("%d ", a[i]);
 8     }
 9     puts("");
10 }
11 /*对于无序的顺序表,将数分成两类,一个在区间一个不在区间,然后计数不在区间的数为k
12 碰到在区间的数应该在结果的第k个位置上,最后总长度为k*/ 
13 void Del_s_t2(int a[], int n, int s, int t){
14     if(s >= t || n == 0)
15     return;
16     int k = 0;
17     for(int i = 0; i < n; i++) {
18         if(a[i] < s || a[i] > t)
19             a[k++] = a[i];
20     } 
21     n = k;
22     print(a, n);
23 }
24 int main()
25 {
26     int a[] = {7,2,9,4, 5,1,3,14};
27     //sort(a, a + 8);
28     print(a, 8);
29     Del_s_t2(a, 8, 3, 7);
30     return 0;
31 }
View Code

4.从有序的顺序表中删除相同的元素,使得表中每个元素都不同。(满足要求的数放在第k位上)

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 void print(int a[], int n){
 6     for(int i = 0; i < n; i++){
 7         printf("%d ", a[i]);
 8     }
 9     puts("");
10 }
11 /*从有序表中删除相同的元素,只需将于之前不同的数放在第k个位置上即可*/ 
12 void Del_diffe(int a[], int n){
13     int k = 1;
14     for(int i = 1; i < n; i++){
15         if(a[i] != a[i - 1])
16             a[k++] = a[i];
17     } 
18     n = k;
19     print(a, k);
20 } 
21 int main()
22 {
23     int a[] = {1,1,2,2,2,4,4,5,5,5,5,6,6};
24     Del_diffe(a, 13);
25     return 0;
26 }
View Code

5.合并两个有序表。

 1 #include <cstdio>
 2 /*合并两个有序表,依次比较,然后添加剩余*/
 3 const int lmax = 50;
 4 int c[lmax];
 5 bool merge(int a[], int la, int b[], int lb){
 6     if(la + lb >= lmax)
 7         return false;
 8     int i = 0,j = 0,k = 0;
 9     while(i < la && j < lb){
10         if(a[i] <= b[j])
11             c[k++] = a[i++];
12         else
13             c[k++] = b[j++];
14     }
15     while(i < la){
16         c[k++] = a[i++];
17     }
18     while(j < lb){
19         c[k++] = b[i++];
20     }
21     return true;
22     
23     for(i = 0; i < k; i++){
24         printf("%d ", c[i]);
25     }
26     puts("");
27 } 
28 
29 int main()
30 {
31     int a[]={1,5,6,8,9,11,12,15,17},la = 9;
32     int b[]={2,3,4,6,7,9,10}, lb = 7;
33     merge(a,la,b,lb);
34     return 0;
35 } 

6.将一个顺序表中的两个顺序表互换位置。(矩阵逆置)

#include <cstdio>
void print(int a[], int n){
    for(int i = 0; i < n; i++){
        printf("%d ", a[i]);
    }
    puts("");
}
/*逆置数组某一区间的方法
数组及其长度,逆置的起始位置和终止位置
中间位置等于起始位置加上终止位置除以2 
*/
void Reverse(int a[],int n, int s, int t)
{
    if(s >= t || t >= n)
        return; 
    int mid = (s + t)/2;
    for(int i = 0; i <= (mid - s); i++){
        int temp = a[s + i];
        a[s + i] = a[t - i];
        a[t - i] = temp;
    }
} 
/*
sc表示交换次数 
*/
void Reverse2(int a[], int n, int s, int t){
    if(s >= t || t >= n)
        return;
    int sc = (t - s + 1)/2;
    for(int i = 0; i < sc;i ++){
        int temp = a[s + i];
        a[s + i] = a[t - i];
        a[t - i] = temp;
    }
}
int main()
{
    int a[] = {1,2,3,4, 5,6,7,8};
    print(a, 8);
    Reverse2(a, 8, 0, 7);
    Reverse2(a, 8, 0, 3);
    Reverse2(a, 8, 4, 7);
    print(a, 8);
    return 0;
}

6.用最少的时间在有序表中查找数值为x的元素。(折半查找法)

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 void print(int a[], int n){
 6     for(int i = 0; i < n; i++){
 7         printf("%d ", a[i]);
 8     }
 9     puts("");
10 }
11 /*折半查找法,选定上界和下届,分三种情况,找到,大了,往左半边找,小了,往右半边找*/
12 bool B_Search(int a[], int n, int x){
13     int l = 0, h = n - 1, mid;//low 和 high 分别是顺序表的上界和下届
14     int flag = 0;
15     while(l <= h){
16         mid = (l + h) / 2;
17         if(a[mid] == x)    {
18             flag = 1;
19             break;
20         }
21         if(a[mid] < x)    l = mid + 1;
22         else h = mid - 1;    
23     } 
24     //如果查找失败,插入x到此前h + 1的位置上,因为 
25     if(l > h){
26         int i;
27         for(i = n - 1; i > h; i--)
28             a[i + 1] = a[i];
29         a[i + 1] = x; 
30     } 
31     if(flag == 1)
32         return true;
33     return false;
34 } 
35 int main()
36 {
37     int a[] = {1,2,3,4,5,6,7};
38     B_Search(a, 7, 2);
39     print(a, 7);
40     return 0;
41 }
View Code

 7.设计一个将含有n(n>=1)整数的数组实现循环左移的算法,要求时间和空间复杂度尽可能的高效。(借助矩阵逆运算)

 1 #include <cstdio>
 2 
 3 void print(int a[], int n){
 4     for(int i = 0; i < n; i++){
 5         printf("%d ", a[i]);
 6     }
 7     puts("");
 8 }
 9 void Reverse(int a[], int from, int to){
10     int sc = (to - from + 1) / 2;
11     for(int i = 0; i < sc; i++) {
12         int temp = a[from + i];
13         a[from + i] = a[to - i];
14         a[to - i] = temp;
15     }
16 }
17 /*借助矩阵逆运算,ab->ba,即ab->a逆b->a逆b逆->(a逆b逆)逆=ba*/
18 void Rotate_left(int a[], int n, int p){
19     Reverse(a, 0, p - 1);
20     Reverse(a, p, n - 1);
21     Reverse(a, 0, n - 1);
22 }
23 
24 int main()
25 {
26     int a[] = {1,2,3,4,5,6,7,8,9};
27     for(int i = 1; i <= 9; i++){
28         Rotate_left(a, 9, i);
29         print(a, 9);
30     }
31     return 0;
32 }
View Code

 8.找出两个等长、升序数组中的中位数。中位数:升序排列后为与中间位置的数叫做中位数。(每次取两数组中的中位数比较,等于就是中位数,不等于舍弃不可能存在的区间)

 1 #include <cstdio>
 2 /*有种折半查找的意味,每次去两个中位数,相等就说明一样,
 3         大于或者小于表示中位数在各自区域的另一半,不同的是
 4         每次舍弃时要舍弃一样的长度,需要分情况讨论。 
 5 */
 6 int slove(int a[], int b[], int n){
 7     int s1 = 0,d1 = n - 1,m1, s2 = 0, d2 =  n - 1, m2;
 8     while(s1 != d1 || s2 != d2){//知道两个数组都遍历完 
 9         m1 = (s1 + d1) / 2;
10         m2 = (s2 + d2) / 2;
11         if(a[m1] == b[m2])
12             return a[m1];
13         if(a[m1] < b[m2]){
14             if((s1 + d1) % 2 == 0)//若a的元素的个数为奇数个 
15             {
16                 s1 = m1;//舍弃a中间点之前的部分且保留中间结点 
17                 d2 = m2;//舍弃b中间点之后的部分且保留中间结点 
18             }
19             else//若a的元素的个数为偶数个 
20             {
21                 s1 = m1 + 1;//舍弃a中间点以及中间点之前的部分
22                 d2 = m2; 
23             } 
24         }
25         else{
26             if((s2 + d2) % 2 == 0)//若b的元素的个数为奇数个 
27             {
28                 d1 = m1;//舍弃b中间点之后的部分且保留中间结点
29                 s2 = m2;//舍弃a中间点之前的部分且保留中间结点  
30             }
31             else//若b的元素的个数为偶数个 
32             {
33                 d1 = m1;
34                 s2 = m2 + 1;//舍弃b中间点以及中间点之前的部分
35             } 
36         } 
37     }
38     return a[s1] < b[s2] ? a[s1] : a[s2];//返回较小的那个数为中位数 
39 }
40 int main()
41 {
42     int a[] = {1,3,5,7,9,11};
43     int b[] = {0,2,4,6,8,10};
44     int mid = slove(a, b, 6);
45     printf("%d\n", mid); 
46     return 0;
47 }
View Code

 9.寻找一个数组中的是否存在主元素,存在输出主元素,不存在输出-1。(排序后遍历找出个数最大,最后判断即可)

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 //先排序后将等值元素集中在一起,然后集中遍历,记录个数最多的元素最后判断即可 
 6 int slove(int a[], int n){
 7     sort(a, a + n);
 8     int rs = a[0], max = 1;
 9     int temp = 1;
10     for(int i = 1; i < n; i++){
11         if(a[i] == a[i - 1])
12             temp++;
13         else{
14             if(temp > max){
15                 rs = a[i - 1];
16                 max = temp;
17             }
18             temp = 1;
19         }    
20     }
21     if(max > n/2)
22         return rs;
23     return -1;
24 }
25 int main()
26 {
27     int i, c, cnt = 1;
28     int a[] = {1, 2, 2, 2, 4, 2,};
29     printf("%d\n", slove(a, 6));
30     int b[] = {1, 2, 3, 4, 5, 6,};
31     printf("%d\n", slove(b, 6));
32     return 0;
33 }
View Code

 10.顺序表的原地逆置,循环左移和循环右移

 1 #include<cstdio>
 2 /*关于顺序表中基本操作中使用到矩阵运算的总结
 3 1.实现顺序表中两个顺序子表的原地逆置
 4 2.循环左移k位
 5 3.循环右移k位 
 6 */
 7 void Reverse(int a[], int fr, int to){
 8     int i, mid = (to - fr + 1)/2, temp;
 9     for(i = 0; i < mid; i++){
10         temp = a[fr + i];
11         a[fr + i] = a[to - i];
12         a[to - i] = temp;
13     }
14 }
15 
16 void Solve2(int a[], int k)
17 {
18     /*欲循环左移k位,先将后k位逆置,再将前n-k位逆置,最后整体逆置*/
19     int n = 9;
20     Reverse(a, k, n-1);
21     Reverse(a, 0, k-1);    
22     Reverse(a, 0, n-1);
23     printf("接着循环左移4位:");
24     for(int i = 0; i < n; i++){
25         printf("%d ", a[i]);
26     }puts("");
27 } 
28 void Solve3(int a[], int k)
29 {
30     /*欲循环右移k位,先将前k位逆置,再将后n-k位逆置,最后整体逆置*/
31     int n = 9;
32     Reverse(a, 0, k-1);
33     Reverse(a, k, n-1);
34     Reverse(a, 0, n-1);
35     printf("接着循环右移5位:");
36     for(int i = 0; i < n; i++){
37         printf("%d ", a[i]);
38     }puts("");
39 } 
40 /*欲ab->ba,则(a逆b逆)逆 = ba*/
41 void Solve1(int a[], int fr1, int to1, int fr2, int to2){
42     Reverse(a, fr1, to1);
43     Reverse(a, fr2, to2);
44     Reverse(a, fr1, to2);
45     printf("原地逆置:");
46     for(int i = fr1; i <= to2; i++){
47         printf("%d ", a[i]);
48     }puts("");
49 }
50 int main()
51 {
52     int a[]={5,6,7,8,9,1,2,3,4};
53     //目标是 {1,2,3,4,5,6,7,8,9};
54     printf("原数组:");
55     for(int i = 0; i <9; i++){
56         printf("%d ", a[i]);
57     }puts("");
58     
59     Solve1(a,0,4,5,8);
60     
61     Solve2(a,4);
62     
63     Solve3(a,5);
64     /*
65     原数组:5 6 7 8 9 1 2 3 4
66     原地逆置:1 2 3 4 5 6 7 8 9
67     接着循环左移4位:5 6 7 8 9 1 2 3 4
68     接着循环右移5位:1 2 3 4 5 6 7 8 9
69     */
70     return 0;    
71 } 

 

posted @ 2019-09-20 19:49  Reqaw  阅读(976)  评论(0编辑  收藏  举报