实验五

  实验结论

  • Part1   二分查找

先来考虑下为什么要用二分查找。显而易见我们可以将查找元素和数组里每个元素进行比较,这样的查找方式时间复杂度是O(n),而二分查找在复杂度上是远低于n的,考虑每次都只查找一半的元素,如果你是循环了k次的话,那么最后查找进行在n/2^k个元素间,取n/2^k=1可得k=log2n,即时间复杂度是O(log2n),这远低于O(n).

// 练习:使用二分查找,在一组有序元素中查找数据项
// 形参是数组,实参是数组名
#include <stdio.h>
const int N = 5;
int binarySearch(int x[], int n, int item);
int main() {
    int a[N] = { 1,3,9,16,21 };
    int i, index, key;
    printf("数组a中的数据:\n");
    for (i = 0;i < N;i++)
        printf("%d ", a[i]);
    printf("\n");
    printf("输入待查找的数据项: ");
    scanf_s("%d", &key);
    // 调用函数binarySearch()在数组a中查找指定数据项item,并返回查找结果给index
    // 补足代码①
    index = binarySearch(a, N, key);
    if (index >= 0)
        printf("%d在数组中,下标为%d\n", key, index);
    else
        printf("%d不在数组中\n", key);
    return 0;
}
//函数功能描述:
//使用二分查找算法在数组x中查找特定值item,数组x大小为n
// 如果找到,返回其下标
// 如果没找到,返回-1
int binarySearch(int x[], int n, int item) {
    int low, high, mid;
    low = 0;
    high = n - 1;
    while (low <= high) {
        mid = (low + high) / 2;
        if (item == x[mid])
            return mid;
        else if (item<x[mid])
            high = mid - 1;
        else
            low = mid + 1;
    }
    return -1;
}

请注意,由于本次使用vs2019,所以scanf经提示更改为scanf_s.

运行结果如下:

利用指针变量的代码如下:

// 练习:使用二分查找,在一组有序元素中查找数据项
// 形参是指针变量,实参是数组名
#include <stdio.h>
const int N = 5;
int binarySearch(int* x, int n, int item);
int main() {
    int a[N] = { 1,3,9,16,21 };
    int i, index, key;
    printf("数组a中的数据:\n");
    for (i = 0;i < N;i++)
        printf("%d ", a[i]);
    printf("\n");
    printf("输入待查找的数据项: ");
    scanf_s("%d", &key);
    // 调用函数binarySearch()在数组a中查找指定数据项item,并返回查找结果
    // 补足代码①
    index = binarySearch(a, N, key);
    if (index >= 0)
        printf("%d在数组中,下标为%d\n", key, index);
    else
        printf("%d不在数组中\n", key);
    return 0;
}
//函数功能描述:
//使用二分查找算法在x指向的数据项开始的n个数据中,查找item
// 如果找到,返回其位置
// 如果没找到,返回-1
int binarySearch(int* x, int n, int item)
{
    int low, high, mid;
    low = 0;
    high = n - 1;
    while (low <= high) {
        mid = (low + high) / 2;
        if (item == *(x + mid))
            return mid;
        else if (item < *(x + mid))
            high = mid - 1;
        else
            low = mid + 1;
    }
    return -1;
}
  • Part2 选择排序法

  

// 练习:使用选择法对字符串按字典序排序
#include <stdio.h>
#include <string.h>
void selectSort(char str[][20], int n); // 函数声明,形参str是二维数组名
int main() {
    char name[][20] = { "John", "Alex", "Joseph", "Candy", "Geoge" };
    int i;
    printf("输出初始名单:\n");
    for (i = 0; i < 5; i++)
        printf("%s\n", name[i]);
    selectSort(name, 5); // 调用选择法对name数组中的字符串排序
    printf("按字典序输出名单:\n");
    for (i = 0; i < 5; i++)
        printf("%s\n", name[i]);
    return 0;
}
// 函数定义
// 函数功能描述:使用选择法对二维数组str中的n个字符串按字典序排序
void selectSort(char str[][20], int n) {
    // 补足代码
    int i, j, k;
    char temp[20];
    for (i = 0;i < n - 1;i++)
    {
        k = i;
        for (j = i + 1;j < n;j++)
        {
            if (strcmp(str[k], str[j]) > 0)
                k = j;
        }
        if (k != i)
        {
            strcpy_s(temp, str[i]);
            strcpy_s(str[i], str[k]);
            strcpy_s(str[k], temp);
        }
    }
}

运行结果如下:

由于使用的是vs2019,所以strcpy经提示修改成strcpy_s.

现在我们来考量这串代码。

selectSort的循环体,从思路着手,将a[0]与其后所有元素比较,找到最小的放在a[0];然后将a[1]与其后所有比较,找到最小的放在a[1];以此类推,外层循环是从0开始到n-2结束,而内层循环从1开始到n-1结束。而中间变量k的出现则是因为,如果a[0]>a[1]那么此时a[1]就是目前的最小数,就要将a[1]和之后的去比较,如果没有变量k,那么始终都是a[0]在和后面的比较,这是不合理的。

接着我们考虑为什么调用strcmp函数作为if语句,这是因为两个字符串里,可能会出现前面几个字母都相同的情况,比如ABL,ABH,单纯使用if(str[k][0]>str[j][0])是不合适的,如果非要如此使用那么便会是一个循环比较,从str[k][0]一直比较到str[k][20],那就和strcmp无太大区别而更麻烦于strcmp。

接着我们考虑为什么调用strcpy,这里直接引用另一篇博文的内容来解释。

字符串常量"hello"出现在一个表达式中时,"hello"表达式使用的值就是这些字符所存储的地址(在常量区),而不是这些字符本身。

所以,可以把字符串赋值给指向字符的指针p,而不能把字符串赋值给一个字符数组。 

char a[10] = “hello”; //这样可以,这种情况是c语言初始化所支持的

如果写成char a[10]

然后 a = “hello” 这样就错误了。  

同样是a数组,char a[10] = “hello”;这种是数组的初始化,和a[0] = ‘h’ a[1] = ‘e’…是一个道理

但是换成char a [10]

然后a = “hello”就不行了 “hello”赋值的值是一个地址,而a虽然也有地址,但是这与指针是不一样的,指针的值是地址,而数组的值虽然也是地址,但是却是一个常量,所以不能给常量赋值。

  • Part3 

之所以在结尾添加'\0',我认为是因为字符串是以\0结尾的,但是中间的过程让字符串的长度减小了,虽然在字符串s中仍有一个\0,但是它是一个孤立的存在,因此要在s删去星号后的实际长度之后再加一个\0.

其次我们来说明下ex3-3中line25-69的含义:

25-44不过多解释,只需对照注释即可理解;46将s赋给了p,然后将head之前的字符保持不变,此时i和p的位置都指向了中间位置的第一个非*字符,接着的循环while(p<tail)实际是从head位置开始到tail结束,这个循环的作用就是讲head与tail之间的非*字符赋给s,也就是删除了*,此循环结束后i和p指向了tail,接着的一个循环便是将tail之后的字符赋给s,结束后p指向\0,i指向了一个不知名地址,因此要再赋值\0作为字符串的结束。

实验总结和体会

这一部分学的并不是很扎实,还要多看书多练习来巩固。

转载于:https://www.cnblogs.com/radius1/p/10906742.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值