2.1
我的思路是遍历字典,提取每个单词的标识,顺序建立一个对应字典索引位置的标志集合,根据这个集合建立一个二维数组,一维数组里第一个位置存放标识,依次遍历标识,将相同的标识追加进对应的一维数组,不同的标识添加进新的一维数组,然后根据标识排序二维数组(以一维数组为单位)。
2.2
2 的32次=4 294 967 296 <4 300 000 000,所以必然存在一个数重复两次,又因为是顺序文件,二分法查找,比较中间值就行了
2.3
例如:abcde n = 5 i = 3 和 abcdef n = 6 i = 2
第一个:a bc d e a b cd e ab c de a bcde,一趟访问了所有字母,也就是所有字母完成了旋转。
第二个:a b c d e f a bcdef,这一趟再次访问到a的时候还有一半没有访问到。我们继续:a b c d e f a b cdef,这样共用了两趟。(此处参考了Z.Y. ☯ Cosmos前辈的思路)
2.4
#include <stdio.h>
#include "stdlib.h"
#include <time.h>
void rorate_method1 (int *arr,int index, int length);
void rorate_method2 (int *arr,int index, int count);
void acrobat(int *str, int len, int excursion);
int gcd(int a, int b);
int main(void) {
int arr[8] = {'a','b','c','d','e','f','g','h'};
for (int j = 0; j < 100000000; j ++){
//rorate_method1(arr, 2, 8); // 7.789s
//rorate_method2(arr, 8, 2); // 2.203s
acrobat(arr, 8, 2);// 6.159s
}
rorate_method2(arr, 8, 2);
for(int i = 0; i < 8; i++) {
printf("%c", *(arr + i));
}
return 0;
}
void rorate_method1 (int *arr,int index, int length){
int i = 0,j = 0,k = 0;
int* middle = (int *) malloc(index * sizeof(int));
for(;i < index;i ++){
*(middle + i) = *(arr + i);
}
for(; j < length-index;j++){
*(arr + j) = *(arr + j + index);
}
for(; k < index;k++){
*(arr + j + k) = *(middle + k);
}
}
void rorate_method2 (int *arr, int length,int count){
int i = 0;
int middle = 0;
middle = *(arr + 0);
for(; i < length-1;i++){
*(arr + i) = *(arr + i + 1);
}
*(arr + i) = middle;
}
int gcd(int a, int b){
return (a % b ? gcd(b, a % b) : b);
}
void acrobat(int *str, int len, int excursion){
int rot = excursion, temp, j, k;
for(int i = 0; i < gcd(rot, len); i++){
temp = *(str+i);
j = i;
while(1){
k = j + rot;
if(k >= len)
k -= len; //equal to k %= len
if(k == i) //find the same alpha
break;
*(str+j) = *(str+k);
j = k;
}
*(str+j) = temp;
}
}
2.5
CBA=(ArBrCr)r
所以可以重用之前书中的reverse代码
#include <stdio.h>
void reverse(int *arr, int start,int end);
int main(void){
// 假设a=0-2 b=2-5 c=6-7
int arr[8] = {'a','b','c','d','e','f','g','h'};
reverse(arr, 0, 2);
reverse(arr, 2, 5);
reverse(arr, 6, 7);
reverse(arr, 0, 7);
for (int i = 0; i <= 7; i++){
printf("%c,", *(arr+i));
}
return 0;
}
void reverse(int *arr, int start,int end) {
int i = start, j = end;
for (; i <= j; i++, j--){
int temp = *(arr+i);
*(arr+i) = *(arr + j);
*(arr + j) = temp;
}
return;
}
2.6
首先创建一个表格对应名字-名字按键,遍历名字文件的每一条信息,给每一条信息以名字按键标识,将相同编码的存放在一起,然后根据名字按键排序,查找可以采取二分法查找。
2.7
为每条记录插入列号(可选?+行号),然后调用系统的磁带排序程序按列排序,最后使用另一个程序删除列号和行号(这里我不了解磁盘的数据存储格式,我看其他答案是按列排序再按行排序,我的理解是假如原矩阵是线性存储的,那么插入列号后根据列号排序时可以将同一列的数据连接在一起,然后顺序读取出来的就是转置后的结果了)。
2.8
分析题意,最小的k元子集和最大的k元子集,这两个集合各自的合是这个n元实数集合的k元子集之合的边界,所以这里只需要排序确定即可,最简单的就是冒泡了,如果数据集大而k小,可以2k次排序(k次冒泡出最大k个数,k次冒泡出最小k个数)。
2.9
假设使用冒泡排序,时间复杂度为n²,所以二分法搜索的时间复杂度为n²+log2 n * x,线性搜索的时间复杂度为n * x,x为搜索的次数计算不等式即可得出结果。
2.10
把灯泡按入水中直至完全浸没,溢出的水就是灯泡的容积。