7-1 数组循环左移

本题要求实现一个对数组进行循环左移的简单函数:一个数组a中存有n(>)个整数,在不允许使用另外数组的前提下,将每个整数循环向左移m(≥)个位置,即将a中的数据由(a​0​​a​1​​⋯a​n−1​​)变换为(a​m​​⋯a​n−1​​a​0​​a​1​​⋯a​m−1​​)(最前面的m个数循环移至最后面的m个位置)。如果还需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

输入格式:

输入第1行给出正整数n(≤)和整数m(≥);第2行给出n个整数,其间以空格分隔。

输出格式:

在一行中输出循环左移m位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

输入样例:

8 3

1 2 3 4 5 6 7 8

输出样例:

4 5 6 7 8 1 2 3

 1 #include <stdio.h>
 2 #define N 100
 3 int main()
 4 {
 5     int i, n, k, arr[N] = {0}; 
 6     scanf("%d%d",&n,&k);
 7     /* 输入数组 */
 8     for(int i=0; i<n; ++i){
 9         scanf("%d,",&arr[i]);        
10     }  
11     /* 输出 */
12     for(i=0; i<n-1; ++i){
13         printf("%d ",arr[(i+k)%n]);
14     } 
15     printf("%d",arr[(i+k)%n]);
16     return 0;
17 }

7-2 装箱问题

假设有N项物品,大小分别为s​1​​、s​2​​、…、s​i​​、…、s​N​​,其中s​i​​为满足1的整数。要把这些物品装入到容量为100的一批箱子(序号1-N)中。装箱方法是:对每项物品, 顺序扫描箱子,把该物品放入足以能够容下它的第一个箱子中。请写一个程序模拟这种装箱过程,并输出每个物品所在的箱子序号,以及放置全部物品所需的箱子数目。

输入格式:

输入第一行给出物品个数N(≤);第二行给出N个正整数s​i​​(1,表示第i项物品的大小)。

输出格式:

按照输入顺序输出每个物品的大小及其所在的箱子序号,每个物品占1行,最后一行输出所需的箱子数目。

输入样例:

8

60 70 80 90 30 40 10 20

输出样例:

60 1

70 2

80 3

90 4

30 1

40 5

10 1

20 2

5

 1 #include <stdio.h>
 2 #define N 1000
 3 struct node{
 4     int c;
 5     int cnt;
 6 };
 7 int main()
 8 {
 9     struct node a[N];
10     int n, capacity = 100, count = 1;
11     scanf("%d", &n);
12     for(int i=0; i<n; ++i){
13         scanf("%d",&a[i].c);
14         a[i].cnt = 0;
15     }
16     for(int i= 0; i<n; ++i)
17     {
18         if(a[i].cnt) continue;
19         int sum = a[i].c;
20         a[i].cnt = count;
21         for(int j=i+1; j<n; ++j){
22             if(!a[j].cnt && sum+a[j].c <= capacity){
23                 sum += a[j].c;
24                 a[j].cnt = count;
25             }        
26         }
27         count++;
28     }
29     for(int i=0; i<n; ++i){
30         printf("%d %d\n", a[i].c, a[i].cnt);
31     }
32     printf("%d\n", count-1);    
33     return 0;
34 }

7-3 两个有序序列的中位数

已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列,的中位数指A​(N−1)/2​​的值,即第⌊个数(A​0​​为第1个数)。

输入格式:

输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的并集序列的中位数。

输入样例1:

5

1 3 5 7 9

2 3 4 5 6

输出样例1:

4

输入样例2:

6

-100 -10 1 1 1 1

-50 0 2 3 4 5

输出样例2:

1

 1 /* 算法1
 2 3个静态数组, 2个序列全部并入第3个序列 */
 3 #include <stdio.h>
 4 #define N 100000
 5 
 6 int main()
 7 {
 8     int a1[N], a2[N], c[2*N], cnt1=0, cnt2=0, cnt=0;
 9     int n;
10     scanf("%d",&n);
11     for(int i=0; i<n; ++i)
12         scanf("%d",&a1[i]);
13     for(int i=0; i<n; ++i)
14         scanf("%d",&a2[i]);
15     for(int i=0; cnt1<n && cnt2<n; ++i)
16     {
17         if(a1[cnt1]<=a2[cnt2]){
18             c[cnt++] = a1[cnt1++];
19         }
20         else{
21             c[cnt++] = a2[cnt2++];
22         }
23     }
24     while(cnt1<n) c[cnt++] = a1[cnt1++];
25     while(cnt2<n) c[cnt++] = a2[cnt2++];
26     printf("%d\n", c[(2*n-1)/2]);    
27     return 0;
28 }
 1 /*算法2
 2 三个动态数组, 2个序列并入第3个序列n个元素 
 3  */
 4 #include <stdio.h>
 5 #include <malloc.h>
 6 int main()
 7 {
 8     int* a1, *a2, *c;
 9     int cnt1=0, cnt2=0, cnt=0;
10     int n;
11     scanf("%d",&n);
12     a1 = (int*)malloc(sizeof(int)*n);
13     a2 = (int*)malloc(sizeof(int)*n);
14     c = (int*)malloc(sizeof(int)*n);
15     
16     for(int i=0; i<n; ++i)
17         scanf("%d",&a1[i]);
18     for(int i=0; i<n; ++i)
19         scanf("%d",&a2[i]);
20     
21     for(int i=0; i<n; ++i)
22     {
23         if(a1[cnt1]<=a2[cnt2]){
24             c[cnt++] = a1[cnt1++];
25         }
26         else{
27             c[cnt++] = a2[cnt2++];
28         }
29     }    
30     
31     printf("%d\n", c[n-1]);    
32     return 0;
33 }
 1 /*算法3
 2 二个动态数组, 2个序列并入第3个序列n个元素 
 3  */
 4 #include <stdio.h>
 5 #include <malloc.h>
 6 int main()
 7 {
 8     int* a, *c;
 9     int cnt1=0, cnt2=0;
10     int n;
11     scanf("%d",&n);
12     a = (int*)malloc(sizeof(int)*n*2);
13     c = (int*)malloc(sizeof(int)*n);
14     
15     for(int i=0; i<n*2; ++i)
16         scanf("%d",&a[i]);
17     
18     for(int i=0; i<n; ++i)
19     {
20         if(a[cnt1]<=a[n+cnt2]){
21             c[i] = a[cnt1++];
22         }
23         else{
24             c[i] = a[n+cnt2++];
25         }
26     }    
27     
28     printf("%d\n", c[n-1]);    
29     return 0;
30 }
 1 /* 算法4
 2 2个动态数组, 不并, 通过下标计算中位数
 3  */
 4 #include <stdio.h>
 5 #include <malloc.h>
 6 int main()
 7 {
 8     int* a1, *a2;
 9     int cnt1=0, cnt2=0;    
10     int n;
11     scanf("%d",&n);
12     a1 = (int*)malloc(sizeof(int)*n);
13     a2 = (int*)malloc(sizeof(int)*n);
14     
15     for(int i=0; i<n; ++i)
16         scanf("%d",&a1[i]);
17     for(int i=0; i<n; ++i)
18         scanf("%d",&a2[i]);
19     
20     while(cnt1+cnt2<(2*n-1)/2)
21     {
22         if(a1[cnt1]<=a2[cnt2]){
23             cnt1++;
24         }
25         else{
26             cnt2++;
27         }
28     }    
29     printf("%d\n", a1[cnt1]>a2[cnt2]?a2[cnt2]:a1[cnt1]);    
30     return 0;
31 }
7-4 求链式线性表的倒数第K项 

给定一系列正整数,请设计一个尽可能高效的算法,查找倒数第K个位置上的数字。

输入格式:

输入首先给出一个正整数K,随后是若干正整数,最后以一个负整数表示结尾(该负数不算在序列内,不要处理)。

输出格式:

输出倒数第K个位置上的数据。如果这个位置不存在,输出错误信息NULL

输入样例:

4 1 2 3 4 5 6 7 8 9 0 -1 

输出样例:

7
 1 #include <stdio.h>
 2 #include <malloc.h>
 3 
 4 struct Node {
 5     int number;
 6     struct Node* next;
 7 };
 8 
 9 int main()
10 {    
11     int k;
12     scanf("%d",&k);
13     
14     struct Node *p = NULL, *t = NULL; //p新结点, t当前结点
15     int x;
16     scanf("%d", &x);
17     while(x >= 0)
18     {        
19         p = (struct Node*)malloc(sizeof(struct Node));
20         p->number = x;
21         p->next = NULL;    
22        
23         p->next = t, t = p;//头部插入\更新当前t            
24         scanf("%d",&x);
25     }
26     
27     while(--k && p)
28     {
29         p = p->next;
30     }
31     
32     if(p == NULL)
33         printf("NULL\n");
34     else
35         printf("%d\n", p->number);
36     
37     return 0;
38 }
7-5 两个有序链表序列的交集 

已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。

输入格式:

输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−表示序列的结尾(−不属于这个序列)。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL

输入样例:

1 2 5 -1
2 4 5 8 10 -1

输出样例:

2 5
 1 #include <stdio.h>
 2 #include <malloc.h>
 3 
 4 struct Node {
 5     int number;
 6     struct Node* next;
 7 };
 8 
 9 struct Node* CreatLinkList()
10 {
11     struct Node *h = NULL, *r = NULL, *p = NULL; 
12     int x, flag = 1;
13     while(scanf("%d", &x) && x >=0)
14     {        
15         p = (struct Node*)malloc(sizeof(struct Node));
16         p->number = x;
17         p->next = NULL;    
18         if(flag) h = r = p;
19         else r->next = p, r = p;//尾插
20         flag = 0;
21     }
22     return h; 
23 }
24 
25 int main()
26 {  
27     int flag = 1;
28     struct Node *s1, *s2;
29     s1 = CreatLinkList(), s2 = CreatLinkList();
30     
31     while(s1 && s2)
32     {
33         if(s1->number > s2->number)
34             s2 = s2->next;            
35         else if(s1->number < s2->number)
36             s1 = s1->next;
37         else{                             
38             if(!flag)
39                 printf(" ");
40             printf("%d", s1->number);    
41             s1 = s1->next;
42             s2 = s2->next;
43             flag = 0;
44         }        
45     }
46     
47     if(flag) printf("NULL\n");
48     
49     return 0;
50 }

7-6 符号配对

请编写程序检查C语言源程序中下列符号是否配对:/*与*/、(与)、[与]、{与}。

输入格式:

输入为一个C语言源程序。当读到某一行中只有一个句点.和一个回车的时候,标志着输入结束。程序中需要检查配对的符号不超过100个。

输出格式:

首先,如果所有符号配对正确,则在第一行中输出YES,否则输出NO。然后在第二行中指出第一个不配对的符号:如果缺少左符号,则输出?-右符号;如果缺少右符号,则输出左符号-?。

输入样例1

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) /*/
        A[i] = i;
}
.

输出样例1:

NO

/*-?

输入样例2:

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) /**/
        A[i] = i;
}]
.

输出样例2:

NO

?-]

输入样例3:

void test()
{
    int i
    double A[10];
    for (i=0; i<10; i++) /**/
        A[i] = 0.1*i;
}
.

输出样例3:

YES

 1 #include <stdio.h>
 2 #define N 100
 3 
 4 void printLeft(char ch) {//左字符打印
 5     if(ch == '<') printf("NO\n/*-?\n");
 6     else printf("NO\n%c-?\n", ch);
 7 }
 8 
 9 void printRight(char ch) {//右字符打印
10     if(ch == '<') printf("NO\n?-*/\n");    
11     else  printf("NO\n?-%c\n",ch);
12 }
13 
14 int charMatch(char ch1,char ch2)//字符匹配
15 {    
16     return ch1=='(' && ch2==')' 
17             || ch1=='[' && ch2==']'
18             ||ch1=='{' && ch2=='}'
19             ||ch1 == ch2;    
20 }
21 
22 int MatchOrPrint(char ch1, int* top, int flag, char ch2)
23 {
24     if(*top != -1 && charMatch(ch1,ch2)){
25         (*top)--;  //栈有字符且匹配出栈
26     }     
27     else //栈无字符或不匹配
28     {                    
29         flag = 0; //栈无字符或不匹配
30         if(*top == -1) {//1.栈无字符(缺左打右)
31             printRight(ch2);
32         }
33         else { //2.栈有字符(缺右打左)
34             printLeft(ch1);
35         }
36     }
37     return flag;
38 }
39 
40 int main() 
41 {
42     char str[10*N];//字符串
43     char stack[N]; //
44     int i, top = -1, flag = 1;//flag匹配标志
45 
46     while(gets(str) && str[0] != '.')//按行读入
47     {        
48         for( i = 0; str[i]; i++) //逐行处理 
49         {   
50             if(str[i] == '(' || str[i] == '[' || str[i] == '{') 
51             {
52                 stack[++top] = str[i]; //左符号入栈
53             }
54             else if(str[i] == '/' && str[i + 1] == '*') 
55             {
56                 stack[++top] = '<'; //左符号入栈
57                 i++;
58             }            
59             else if(str[i] == '*' && str[i + 1] == '/') 
60             {                  
61                 flag = MatchOrPrint(stack[top], &top, flag, '<');
62                 i++; // 处理右*/避免'/'再次处理, for循环再次++
63             }
64             else if(str[i] == ')'||str[i] == ']'||str[i] == '}')
65             {   //处理右 ')', ']', '}'
66                 flag = MatchOrPrint(stack[top], &top, flag, str[i]);
67             }
68             if(flag == 0) break;//栈无字符或不匹配
69         }
70         if(flag == 0) break; //栈无字符或不匹配
71     }
72     
73     if(flag && top == -1) printf("YES\n");//栈空且左右匹配
74     else if(flag) { //即使左右匹配栈不空(缺右打左)
75         printLeft(stack[top]);
76     } 
77     return 0;
78 }

7-7 整型关键字的散列映射

给定一系列整型关键字和素数P,用除留余数法定义的散列函数将关键字映射到长度为P的散列表中。用线性探测法解决冲突。

输入格式:

输入第一行首先给出两个正整数N(≤)和P(≥的最小素数),分别为待插入的关键字总数、以及散列表的长度。第二行给出N个整型关键字。数字间以空格分隔。

输出格式:

在一行内输出每个整型关键字在散列表中的位置。数字间以空格分隔,但行末尾不得有多余空格。

输入样例:

4 5

24 15 61 88

输出样例:

4 0 1 3

 1 #include <stdio.h>
 2 #include <malloc.h>
 3 int main() 
 4 {
 5     int n, p;
 6     scanf( "%d%d", &n, &p );
 7     int* table = (int*)calloc(p, sizeof(int)); //散列表    
 8     int x;
 9     for( int i = 0; i < n; i++ ) 
10     {
11         scanf( "%d", &x );     
12         int index = x % p;
13         while( table[index] ){    
14             if(table[index] == x)//重复数字
15                 break;
16            index = (index+1)%p;            
17         }
18         table[index] = x;//在散列表的index位置记录x      
19         if( i == 0 ) printf( "%d", index );
20         else printf( " %d", index );
21     } 
22     return 0;
23 }

7-8 树的遍历

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

7

2 3 1 5 7 6 4

1 2 3 4 5 6 7

输出样例:

4 1 6 3 5 7 2

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdbool.h>
  4 #include <malloc.h>
  5 #define ERROR -1
  6 #define N 31
  7 
  8 /* 二叉树结点 */
  9 typedef struct TreeNode *BinTree;
 10 struct TreeNode{
 11     int Data;
 12     BinTree Left;
 13     BinTree Right;
 14 };
 15 
 16 /* 创建树结点 */
 17 BinTree NewNode( int V )
 18 { 
 19     BinTree T = (BinTree)malloc(sizeof(struct TreeNode));
 20     T->Data = V;
 21     T->Left = T->Right = NULL;
 22     return T;
 23 }
 24 
 25 /* 建树 */
 26 BinTree  BuildTree(int a[],int b[],int i,int j,int s,int e) 
 27 {   /* i,j树的后序序列的起止, s,e树的中序序列的起止 */
 28     int k; 
 29     BinTree p;
 30     if( i > j )    return NULL;//递归终止
 31     
 32     p = NewNode(a[j]); //后序的根a[j]创建结点
 33     
 34     k = s;  /* 寻找树根位置 */
 35     while( ( k <= e ) && ( b[k] != a[j] ) )    k++; 
 36     
 37     if( k > e )    exit(ERROR); 
 38     
 39     p->Left  = BuildTree(a, b, i, i+(k-s)-1, s, k-1); /* 左子树 */   
 40     p->Right = BuildTree(a, b, i+(k-s), j-1, k+1, e); /* 右子树 */    
 41     return p;
 42 }
 43 
 44 /* 顺序循环队列*/
 45 typedef struct QNode *Queue; /* 队列指针 */
 46 struct QNode {
 47     BinTree* Data;     /* 存储元素的数组 */
 48     int Front, Rear;  /* 队列的头、尾指针 */
 49     int MaxSize;           /* 队列最大容量 */
 50 };
 51 
 52  /* 建队列 */
 53 Queue CreateQueue( int MaxSize )
 54 {
 55     Queue Q = (Queue)malloc(sizeof(struct QNode));
 56     Q->Data = (BinTree*)malloc(MaxSize * sizeof(BinTree));
 57     Q->Front = Q->Rear = 0;
 58     Q->MaxSize = MaxSize;
 59     return Q;
 60 }
 61 
 62 /* 队满 */
 63 bool IsFull( Queue Q )
 64 {
 65     return ((Q->Rear+1)%Q->MaxSize == Q->Front);
 66 }
 67 
 68 /* 队空 */
 69 bool IsEmpty( Queue Q )
 70 {
 71     return (Q->Front == Q->Rear);
 72 }
 73 
 74 /* 入队 */
 75 bool AddQ( Queue Q, BinTree X )
 76 {
 77     if ( IsFull(Q) ) {
 78         return false;
 79     }
 80     else {
 81         Q->Rear = (Q->Rear+1)%Q->MaxSize;
 82         Q->Data[Q->Rear] = X;
 83         return true;
 84     }
 85 }
 86 
 87 /* 出队 */
 88 BinTree DeleteQ( Queue Q )
 89 {    
 90     if ( IsEmpty(Q) )
 91         return NULL;
 92     Q->Front =(Q->Front+1)%Q->MaxSize;
 93     return  Q->Data[Q->Front];   
 94 }
 95 
 96 /* 层序遍历 */
 97 void LevelorderTraversal ( BinTree BT )
 98 { 
 99     Queue Q; 
100     BinTree T;
101  
102     if ( !BT ) return; /* 若是空树则直接返回 */
103      
104     Q = CreateQueue(N); /* 创建空队列Q */
105     AddQ( Q, BT ); /* 树根入队 */
106     
107     int flag = 0;  /* 控制输出空格 */
108     
109     while ( !IsEmpty(Q) ) 
110     {
111         T = DeleteQ( Q );
112         if(flag) printf(" ");
113         flag = 1;
114         printf("%d", T->Data); /* 访问取出队列的结点 */
115         if ( T->Left )   AddQ( Q, T->Left );  /* 左子树入队 */
116         if ( T->Right )  AddQ( Q, T->Right ); /* 右子树入队 */
117     }
118 }
119 int main()
120 {    
121     int a[N] = {0}, b[N] = {0};
122     int n;
123     scanf("%d", &n);
124     /* 输入树的后序遍历\中序遍历序列 */
125     for(int i=0; i<n; ++i)
126     {
127         scanf("%d", &a[i]);
128     }
129     for(int i=0; i<n; ++i)
130     {
131         scanf("%d", &b[i]);
132     }
133     /* 恢复树 */
134     BinTree root = BuildTree(a, b , 0, n-1 , 0,  n-1); 
135     /* 层序遍历输出 */
136     LevelorderTraversal(root);
137     
138     return 0; 
139 }

7-9 根据后序和中序遍历输出先序遍历

本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果。

输入格式:

第一行给出正整数N(≤30),是树中结点的个数。随后两行,每行给出N个整数,分别对应后序遍历和中序遍历结果,数字间以空格分隔。题目保证输入正确对应一棵二叉树。

输出格式:

在一行中输出Preorder:以及该树的先序遍历结果。数字间有1个空格,行末不得有多余空格。

输入样例:

7

2 3 1 5 7 6 4

1 2 3 4 5 6 7

输出样例:

Preorder: 4 1 3 2 6 5 7

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <stdbool.h>
 4 #include <malloc.h>
 5 #define ERROR -1
 6 #define N 31
 7 
 8 /* 二叉树结点 */
 9 typedef struct TreeNode *BinTree;
10 struct TreeNode{
11     int Data;
12     BinTree Left;
13     BinTree Right;
14 };
15 
16 typedef BinTree Stack; /* 栈类型 */
17 
18 /* 创建树结点 */
19 BinTree NewNode( int V )
20 { 
21     BinTree T = (BinTree)malloc(sizeof(struct TreeNode));
22     T->Data = V;
23     T->Left = T->Right = NULL;
24     return T;
25 }
26 
27 /* 建树 */
28 BinTree  BuildTree(int a[],int b[],int i,int j,int s,int e) 
29 {   /* i,j树的后序序列的起止, s,e树的中序序列的起止 */
30     int k; 
31     BinTree p;
32     if( i > j )    return NULL;//递归终止
33     
34     p = NewNode(a[j]); //后序的根a[j]创建结点
35     
36     k = s;  /* 寻找树根位置 */
37     while( ( k <= e ) && ( b[k] != a[j] ) )    k++; 
38     
39     if( k > e )    exit(ERROR); 
40     
41     p->Left  = BuildTree(a, b, i, i+(k-s)-1, s, k-1); /* 左子树 */   
42     p->Right = BuildTree(a, b, i+(k-s), j-1, k+1, e); /* 右子树 */    
43     return p;
44 }
45 
46 /* 非递归先序遍历 */
47 void PreorderTraversal( BinTree BT )
48 { 
49     BinTree T = BT;
50     Stack S[N]; /* 建栈 */
51     int top = -1;
52     while( T || top != -1 )/* 树不空或栈不空 */
53     {
54         while(T)/*一直向左并将沿途结点压入堆栈*/
55         { 
56             S[++top] = T;  /* 结点压栈(第一次遇到结点) */
57             printf(" %d", T->Data); /*(访问)打印结点*/
58             T = T->Left;/* 一直向左 */
59         }
60         if(top != -1) /* 栈不空 */
61         {
62             T = S[top--];  /*结点弹出堆栈(第二次遇到结点)*/            
63             T = T->Right;/*转向右子树*/
64         }
65     }
66 }
67 
68 int main()
69 {    
70     int a[N] = {0}, b[N] = {0};
71     int n;
72     scanf("%d", &n);
73     /* 输入树的后序遍历\中序遍历序列 */
74     for(int i=0; i<n; ++i)
75     {
76         scanf("%d", &a[i]);
77     }
78     for(int i=0; i<n; ++i)
79     {
80         scanf("%d", &b[i]);
81     }
82     /* 恢复树 */
83     BinTree root = BuildTree(a, b , 0, n-1 , 0,  n-1); 
84     /* 先序遍历输出 */
85     printf("Preorder:");
86     PreorderTraversal(root);
87     
88     return 0; 
89 }

7-10 是否完全二叉搜索树

将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果。

输入格式:

输入第一行给出一个不超过20的正整数N;第二行给出N个互不相同的正整数,其间以空格分隔。

输出格式:

将输入的N个正整数顺序插入一个初始为空的二叉搜索树。在第一行中输出结果树的层序遍历结果,数字间以1个空格分隔,行的首尾不得有多余空格。第二行输出YES,如果该树是完全二叉树;否则输出NO。

输入样例1:

9

38 45 42 24 58 30 67 12 51

输出样例1:

38 45 24 58 42 30 12 67 51

YES

输入样例2:

8

38 24 12 45 58 67 42 51

输出样例2:

38 45 24 58 42 12 67 51

NO

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdbool.h>
  4 
  5 /* 树结点 */
  6 typedef struct TreeNode *BinTree;
  7 typedef struct TreeNode TreeNode;
  8 struct TreeNode{
  9     int Data, ID;
 10     BinTree Left;
 11     BinTree Right;
 12 };
 13 
 14 /* 顺序循环队列*/
 15 #define MAXSIZE  21 //最大队列长度 N 
 16 typedef struct QNode *Queue; 
 17 struct QNode {
 18     BinTree* Data;    /* 存储元素的数组 */
 19     int Front, Rear;  /* 队列的头、尾指针 */
 20     int MaxSize;      /* 队列最大容量 */
 21 };
 22 
 23 BinTree Insert( BinTree BST, int X );     /* 插入 */
 24 void LevelorderTraversal ( BinTree BT );  /* 层次遍历 */
 25 Queue CreateQueue( );                /*  建队 */
 26 bool IsFull( Queue Q );              /* 队满 */
 27 bool IsEmpty( Queue Q );             /* 队空 */
 28 bool AddQ( Queue Q, BinTree X );     /* 入队 */
 29 BinTree DeleteQ( Queue Q );             /* 出队 */
 30 
 31 int main()
 32 {
 33     int N, i, X;   
 34     scanf("%d", &N);
 35     
 36     BinTree BST = NULL;
 37     for ( i=0; i<N; i++ ) {
 38         scanf("%d", &X);
 39         BST = Insert(BST, X);
 40     }
 41     LevelorderTraversal(BST);
 42     return 0;
 43 }
 44 
 45 BinTree Insert( BinTree BST, int X )
 46 {
 47     if(!BST)
 48     {  
 49         BST = (BinTree)malloc(sizeof(TreeNode));
 50         BST->Data = X;
 51         BST->Left = NULL;
 52         BST->Right = NULL;
 53     }
 54     else
 55     {
 56         if(X > BST->Data)
 57             BST->Left = Insert(BST->Left,X);
 58         else if(BST->Data > X)
 59             BST->Right = Insert(BST->Right,X);
 60     }
 61     return BST; 
 62 }
 63 
 64 void LevelorderTraversal ( BinTree BT )
 65 { 
 66     Queue Q; 
 67     BinTree T;
 68     
 69     bool flag = true, ans = true;
 70     int order = 0; /* 顺序 */
 71     
 72     if ( !BT ) return; /* 若是空树则直接返回 */
 73     
 74     Q = CreateQueue(); /* 创建空队列Q */ 
 75     
 76     
 77     AddQ( Q, BT ); /* 树根入队 */
 78     BT->ID = 1;
 79     
 80     while ( !IsEmpty(Q) ) 
 81     {
 82         T = DeleteQ( Q ); /* 出队 */
 83         order++;
 84         
 85         if(T->ID != order)
 86             ans = false; /* 顺序不同 */
 87         if(flag)  /* 输出格式 */
 88         {
 89             printf("%d", T->Data);
 90             flag = false;
 91         }
 92         else printf(" %d", T->Data);
 93               
 94         if ( T->Left ){
 95             T->Left->ID = 2 * T->ID;  /* 左儿子顺序 */
 96             AddQ( Q, T->Left );       /* 左儿子入队 */
 97         }   
 98         if ( T->Right ){
 99             T->Right->ID = 2 * T->ID + 1;/* 右儿子顺序 */
100             AddQ( Q, T->Right );         /* 右儿子入队 */
101         }  
102     }
103     
104     if(ans)  /* 顺序相同 */
105         printf("\nYES");
106     else
107         printf("\nNO"); 
108 }
109 
110  /* 建队列 */
111 Queue CreateQueue( )//返回队列指针
112 {
113     Queue Q = (Queue)malloc(sizeof(struct QNode));
114     Q->Data = (BinTree*)malloc(MAXSIZE * sizeof(BinTree));
115     Q->Front = Q->Rear = 0;
116     Q->MaxSize = MAXSIZE;
117     return Q;
118 }
119 
120 /* 队满 */
121 bool IsFull( Queue Q )
122 {
123     return ((Q->Rear+1)%Q->MaxSize == Q->Front);
124 }
125 
126 /* 队空 */
127 bool IsEmpty( Queue Q )
128 {
129     return (Q->Front == Q->Rear);
130 }
131 
132 /* 入队 */
133 bool AddQ( Queue Q, BinTree X )
134 {
135     if ( IsFull(Q) ) {
136         return false;
137     }
138     else {
139         Q->Rear = (Q->Rear+1)%Q->MaxSize;
140         Q->Data[Q->Rear] = X;
141         return true;
142     }
143 }
144 
145 /* 出队 */
146 BinTree DeleteQ( Queue Q )
147 {    
148     if ( IsEmpty(Q) )
149         return NULL;
150     Q->Front =(Q->Front+1)%Q->MaxSize;
151     return  Q->Data[Q->Front];   
152 }

7-11 修理牧场

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li的总和。但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。

请编写程序帮助农夫计算将木头锯成N块的最少花费。

输入格式:

输入首先给出正整数N(≤104),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。

输出格式:

输出一个整数,即将木头锯成N块的最少花费。

输入样例:

8

4 5 1 2 1 3 1 1

输出样例:

49

  1 /* 
  2     建一个最小堆, 堆插入树结点, 形成树结点森林;
  3     每次从堆中取2个最小树结点, 建中间树结点并插入堆;
  4     (最后堆中森林形成一棵Huffman树)
  5     打印Huffman树的WPL; 
  6 */
  7 
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 
 11 /* 二叉树结点 */
 12 typedef struct TreeNode* Tree;
 13 struct TreeNode {
 14     int Weight;
 15     Tree Left, Right;
 16 };
 17 
 18 /* 堆(优先队列) */
 19 #define MAXSIZE 10001 
 20 typedef struct HeapNode* Heap;
 21 struct HeapNode {   
 22     struct TreeNode Data[MAXSIZE];/* 完全二叉树顺序存储 */
 23     int Size;
 24 };
 25  
 26  /* 建树结点 */
 27 Tree NewTreeNode() {
 28     Tree T;
 29     T = (Tree)malloc(sizeof(struct TreeNode));
 30     T->Weight = 0;
 31     T->Left = T->Right = NULL;    
 32     return T;
 33 }
 34 
 35  /* 建空堆 */
 36 Heap CreatHeap() {
 37     Heap H;
 38     H = (Heap)malloc(sizeof(struct HeapNode));
 39     H->Size = 0;            /* 空堆 */
 40     H->Data[0].Weight = -1; /* 哨兵 */
 41     return H;
 42 }
 43  
 44  /* 堆插入 */
 45 void Insert(Heap H, struct TreeNode T) {
 46     int i = ++H->Size;  /* ++堆, 从堆的最后开始寻找插入结点位置 */
 47     for( ; T.Weight < H->Data[i/2].Weight; i /= 2)
 48         H->Data[i] = H->Data[i/2]; /* 父结点下滤 */
 49     H->Data[i] = T; /* 插入结点 */
 50 }
 51 
 52  /* 堆删除 */
 53 Tree Delete(Heap H) 
 54 {    /* 提取堆最后一个树结点, 从堆的第一个结点开始比较,上滤, 堆-- */
 55     int parent, child;
 56     struct TreeNode Temp = H->Data[H->Size--]; /* 提取堆最后一个树结点 */
 57     Tree T = NewTreeNode(); /* 创建树结点 */
 58     *T = H->Data[1];        /* 从堆中提取第一个树结点 */
 59     for(parent = 1; 2*parent <= H->Size; parent = child) 
 60     {
 61         child = 2 * parent; /* 从父结点找左孩子 */
 62         if(child != H->Size && H->Data[child].Weight > H->Data[child+1].Weight) 
 63             child++;        /* 有右孩子且比左孩子小, 选右孩子 */
 64         if(Temp.Weight < H->Data[child].Weight) 
 65             break;  /* 原堆最后一个树结点找到位置 */
 66         H->Data[parent] = H->Data[child]; /* 孩子结点上滤, 孩子结点覆盖父结点 */
 67     }
 68     H->Data[parent] = Temp; /* 原堆最后一个树结点归位 */
 69     return T; /* 返回原堆第一个树结点 */
 70 }
 71 
 72 /* 建Huffman树 */
 73 Tree Huffman(Heap H) 
 74 {   
 75     Tree T = NewTreeNode(); /* 临时树结点 */
 76     while(H->Size != 1) 
 77     {    /* 每次取堆中2个最小值建中间树结点 */
 78         T->Left = Delete(H);  
 79         T->Right = Delete(H);
 80         T->Weight = T->Left->Weight + T->Right->Weight;
 81         
 82         Insert(H, *T); /* 复制创建的中间树结点(传参)插入堆 */
 83     }
 84     free(T); /* 释放临时结点 */
 85     T = Delete(H); /* 取出堆中的树 */
 86     return T;
 87 }
 88  
 89 int WPL(Tree T, int Depth) { /* 整棵树的WPL */
 90     if(!T->Left && !T->Right) {  return Depth*T->Weight; }
 91     else return WPL(T->Left, Depth+1) + WPL(T->Right, Depth+1);
 92 }
 93  
 94 int main() 
 95 {
 96     int N, Weight;
 97    
 98     Heap H = CreatHeap(); /* 建空堆 */
 99     Tree T = NewTreeNode();  /* 建临时树结点 */
100     
101     scanf("%d", &N);  /* 树结点个数 */
102     for(int i = 0; i < N; i++) 
103     {      
104         scanf("%d", &Weight);        
105         T->Weight = Weight;
106         H->Data[H->Size].Left = H->Data[H->Size].Right = NULL;       
107         Insert(H, *T); /* 复制创建的树结点(传参), 插入堆, 形成树森林 */
108     }
109     
110     free(T); /* 释放临时结点 */
111     
112     T = Huffman(H);   /* 建Huffman树  */
113     
114     printf("%d\n", WPL(T, 0)); /* 输出Huffman树的WPL */
115     
116     return 0;
117 }

7-12 地下迷宫探索

地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式。地道网是房连房、街连街、村连村的地下工事,如下图所示。

 

我们在回顾前辈们艰苦卓绝的战争生活的同时,真心钦佩他们的聪明才智。在现在和平发展的年代,对多数人来说,探索地下通道或许只是一种娱乐或者益智的游戏。本实验案例以探索地下通道迷宫作为内容。

假设有一个地下通道迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关。请问你如何从某个起点开始在迷宫中点亮所有的灯并回到起点?

 

输入格式:

输入第一行给出三个正整数,分别表示地下迷宫的节点数N(1<N≤1000,表示通道所有交叉点和端点)、边数M(≤3000,表示通道数)和探索起始节点编号S(节点从1到N编号)。随后的M行对应M条边(通道),每行给出一对正整数,分别是该条边直接连通的两个节点的编号。

输出格式:

若可以点亮所有节点的灯,则输出从S开始并以S结束的包含所有节点的序列,序列中相邻的节点一定有边(通道);否则虽然不能点亮所有节点的灯,但还是输出点亮部分灯的节点序列,最后输出0,此时表示迷宫不是连通图。

由于深度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以节点小编号优先的次序访问(点灯)。在点亮所有可以点亮的灯后,以原路返回的方式回到起点。

输入样例1:

6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5

输出样例1:

1 2 3 4 5 6 5 4 3 2 1

输入样例2:

6 6 6
1 2
1 3
2 3
5 4
6 5
6 4

输出样例2:

6 4 5 4 6 0
 1 #include <stdio.h>
 2 
 3 #define MAXN 1010  /* 最大结点数 */
 4 int AdjMatrix[MAXN][MAXN] = {0}; /* 邻接矩阵 */
 5 int visited[MAXN] = {0}; /* 访问标记 */
 6 int flag = 0;
 7 int count = 1; /* 入口1 */
 8 int n;  /* 结点数 */
 9  
10 void DFS(int s)
11 {
12     if(flag)
13         printf(" ");
14     flag++;
15     printf("%d", s);  /* 访问 */
16     visited[s] = 1;
17     for(int i = 1;i<=n;i++) /* 结点序号从1开始到n */
18         if(!visited[i]&&AdjMatrix[s][i]) /* 结点没访问且有边 */
19         {
20             count++;         /* 访问结点计数 */
21             DFS(i);             /* 递归调用 */
22             printf(" %d",s); /* 返回 */
23         }
24 }
25  
26 int main()
27 {
28     int m,s;  
29     scanf("%d%d%d", &n, &m, &s); /* 结点数 边数 入口 */
30     for(int i = 0;i<m;i++)
31     {
32         int a,b;        /* 边的两个结点编号 */
33         scanf("%d%d", &a, &b); 
34         AdjMatrix[a][b] = AdjMatrix[b][a] = 1;
35     }
36     DFS(s);     /* 深度搜索 */
37     if(count<n) /* 迷宫不连通 */
38         printf(" 0");
39     return 0;
40 }

7-13 畅通工程之局部最小花费问题

某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出“畅通工程”的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通过快速路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建快速路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全地区畅通需要的最低成本。

输入格式:

输入的第一行给出村庄数目N (1≤N≤100);随后的N(N−1)/2行对应村庄间道路的成本及修建状态:每行给出4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态 — 1表示已建,0表示未建。

输出格式:

输出全省畅通需要的最低成本。

输入样例:

4
1 2 1 1
1 3 4 0
1 4 1 1
2 3 3 0
2 4 2 1
3 4 5 0

输出样例:

3
 1 #include <stdio.h>
 2 
 3 #define inf 65535
 4 #define MAXN 200
 5 int map[MAXN][MAXN],w[MAXN],visit[MAXN];
 6 int N;
 7 
 8 void init() 
 9 {
10     for(int i = 1; i<=N; i++) {
11         for(int j = 1; j<=N; j++) {
12             map[i][j] = inf;
13         }
14     }
15     int start,end,cost,state,k = N*(N-1)/2;
16     for(int i = 0; i<k; i++) 
17     { /* 两个村庄start,end,村庄之间路的花费cost,是否已修建state */
18         scanf("%d%d%d%d",&start,&end,&cost,&state);
19         if(state == 0) {
20             map[start][end] = cost;
21             map[end][start] = cost;
22         } else {
23             map[start][end] = 0;
24             map[end][start] = 0;
25         }
26     }
27 }
28 
29 void prim() 
30 {    /* 从1顶点出开始生成最小生成树 */
31     for(int i = 1; i<=N; i++){
32         visit[i] = 0;
33         if(i != 1)
34             w[i] = map[1][i];
35     }
36     visit[1] = 1;
37     int pos = 0,MIN = inf;
38     for(int i = 0; i<N; i++) 
39     {
40         MIN = inf,pos = 0;
41         for(int j = 1; j<=N; j++) 
42         {/* 从没有访问过的顶点中找到下一个距离最短的边 */
43             if(!visit[j] && MIN>w[j]) {
44                 MIN = w[j];
45                 pos = j;
46             }
47         }
48         visit[pos] = 1;
49         for(int j = 1; j<=N; j++) 
50         {  /* 用这个最小的顶点的邻接边的权值更新w[]的值 */
51             if(!visit[j] && map[pos][j]<w[j]) {
52                 w[j] = map[pos][j];
53             }
54         }
55     }
56 }
57 
58 int main() 
59 {
60     scanf("%d",&N);
61     init();
62     prim();
63 
64     int sum = 0;
65     /* 最低成本 */
66     for(int i = 1; i<=N; i++) {
67         sum += w[i];
68     }
69     printf("%d\n",sum);
70     return 0;
71 }

7-14 奥运排行榜

每年奥运会各大媒体都会公布一个排行榜,但是细心的读者发现,不同国家的排行榜略有不同。比如中国金牌总数列第一的时候,中国媒体就公布“金牌榜”;而美国的奖牌总数第一,于是美国媒体就公布“奖牌榜”。如果人口少的国家公布一个“国民人均奖牌榜”,说不定非洲的国家会成为榜魁…… 现在就请你写一个程序,对每个前来咨询的国家按照对其最有利的方式计算它的排名。

输入格式:

输入的第一行给出两个正整数N和M(≤224,因为世界上共有224个国家和地区),分别是参与排名的国家和地区的总个数、以及前来咨询的国家的个数。为简单起见,我们把国家从0 ~ N−1编号。之后有N行输入,第i行给出编号为i−1的国家的金牌数、奖牌数、国民人口数(单位为百万),数字均为[0,1000]区间内的整数,用空格分隔。最后面一行给出M个前来咨询的国家的编号,用空格分隔。

输出格式:

在一行里顺序输出前来咨询的国家的排名:计算方式编号。其排名按照对该国家最有利的方式计算;计算方式编号为:金牌榜=1,奖牌榜=2,国民人均金牌榜=3,国民人均奖牌榜=4。输出间以空格分隔,输出结尾不能有多余空格。

若某国在不同排名方式下有相同名次,则输出编号最小的计算方式。

输入样例:

4 4
51 100 1000
36 110 300
6 14 32
5 18 40
0 1 2 3

输出样例:

1:1 1:2 1:3 1:4
#include <stdio.h>

#define MAXN 225  /* 224个国家 */
struct country
{
    int gold;  /* 金牌 */
    int medal; /* 奖牌 */
    int pop;   /* 人口数population */
} cts[MAXN];   /* 城市数 */

int main()
{
    int m,n;
    scanf("%d %d",&n,&m);   /* 参与总数n,咨询总数m */
    for(int i = 0; i < n; i++) /* 参与 */
    {
        scanf("%d %d %d",&cts[i].gold,&cts[i].medal,&cts[i].pop);
    }
    for(int i = 0; i < m; i++)  /* m个国家咨询 */
    {
        int num;
        scanf("%d",&num); /* 咨询国家编号num */
        int rank[4] = {0};        /* 4种计算名次方法 */
        
        for(int i = 0; i < n; i++) /* 计算名次 */
        {
            if(cts[i].gold > cts[num].gold)
                rank[0]++;
            if(cts[i].medal > cts[num].medal)
                rank[1]++;
            if(cts[i].gold*cts[num].pop > cts[num].gold*cts[i].pop)
                rank[2]++;
            if(cts[i].medal*cts[num].pop > cts[num].medal*cts[i].pop)
                rank[3]++;
        }
      
        int sum = rank[0];
        int index = 0; 
        for(int i = 1;i < 4;i++)
        {
            if(rank[i] < sum)
            {
                sum = rank[i];
                index = i;
            }
        }
        if(i) printf(" ");            
        printf("%d:%d",sum+1,index+1); /* 某国的排名  */            
    }
    printf("\n");
}

7-15 寻找大富翁

胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。

输入格式:

输入首先给出两个正整数N(≤106)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。

输出格式:

在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。

输入样例:

8 3
8 12 7 3 20 9 5 18

输出样例:

20 18 12
 1 #include <stdio.h>
 2 
 3 #define N 1000000
 4 int key[N] = {0};
 5 
 6 int main()
 7 {
 8     int n,m,x,count=0,flag=0;
 9     scanf("%d%d",&n,&m); 
10     for(int i=0; i<n; ++i){
11         scanf("%d",&x);
12         key[x]++;
13     }
14     for(int j=N-1; j>=0 && count<m; --j){
15         if(key[j]){
16             if(flag) printf(" ");
17             printf("%d",j);
18             flag = 1;
19             count++;
20             if(key[j]>1){
21                 key[j]--;
22                 j++;
23             }
24         }        
25     }
26 }