编程珠玑--------第二章习题笔记

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

把灯泡按入水中直至完全浸没,溢出的水就是灯泡的容积。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值