CS50X week3 学习笔记

week 3 Algorithms

回顾前面所用到的算法耗费的时间:在电话本一次一页、一次两页、半分法

搜索算法
  • 线性搜索 O ( n l o g n ) O(nlogn) O(nlogn)

    通过 7 个箱子里面放的纸币,志愿者查找需要的面额进行演示

    伪代码:
    For each dorr from left to right
    	If 50 is behind the door
    		Return Ture
    Return False
    
    转化:
    For i from 0 to n-1
    	if 50 is behind door[i]
    		Return Ture
    Return False
    
    错误的伪代码:
    For each dorr from left to right
    	If 50 is behind the door
    		Return Turn
    	Else
    		Return False
    查找到第一个不符合的时候会直接返回 False
    
  • 二分算法(前提:数组是有序的) O ( l o g n ) O(logn) O(logn)

    伪代码:
    If no doors left
    	Return false
    If 50 is behind the door
    	Return ture
    Else if 50 is < middle door
    	Search left half
    Else if 50 is > middle door
    	Search right half
    	
    转化:
    If no doors left
    	Return false
    If 50 is behind doors[middle]
    	Return ture
    Else if 50 < doors[middle]
    	Search doors[0] to doors[middle - 1]
    Else if 50 > doors[middle]
    	Search doors[middle + 1] to doors[n - 1]
    	
    注意:doors[middle] 已经比较过了,所以从这个数的两边开始;n 是数组的长度,数组最后一个是 n-1
    
算法所用的时间

算法所用的大致时间(最糟糕的情况 upper bound),从慢到快:

  • $ O (n^{2} )$
  • O ( n l o g n ) O(nlogn) O(nlogn)
  • O ( n ) O(n) O(n):线性搜索
  • O ( l o g n ) O(logn) O(logn):二分算法
  • O ( 1 ) O(1) O(1)

算法所用的大致时间(最好的情况 lower bound),从慢到快:

  • $\Omega (n^{2}) $
  • $\Omega (nlogn) $
  • $\Omega (n) $
  • $\Omega (logn) $
  • $\Omega (1) $:线性搜索、二分算法

当 upper bound = lower bound,用 $\Theta $ 表示,大小同上

将上述的线性搜索伪代码转换成实际代码

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    int numbers[] = {20, 1, 100, 15, 50, 10, 200};

    int num = get_int("Number: ");

    for (int i = 0; i < 7; i++)
    {
        if (numbers[i] == num)
        {
            printf("Found\n");
            return 0; // 是必须的,不返回会使得循环继续执行
            // break 使用这个可以停止循环,但还是会继续执行后面的打印操作
        }
    }

    printf("Not found\n");
    return 1;
}

实际应用的代码:

#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    string names[] = {"Cater", "David"};
    string nums[] = {"138-111-1256", "153-256-4859"};

    string name = get_string("Name: ");

    for (int i = 0; i < 2; i++)
    {
        if (strcmp(names[i], name) == 0)
        {
            printf("%s\n", nums[i]);
            return 0;
        }
    }

    printf("Not found\n");
    return 1;
}

这个代码中可能存在的问题:

  • 数字 2 ,如果添加或删除了数据,需要手动改变,容易漏掉
  • 可能会出现输入了名字,但是忘记输入号码的情况,这时代码会出错
  • 目前是假设名字和号码的顺序是相对应的,如果号码的顺序改变,也会出错
构造数据结构

解决办法:C 语言可以自行构造数据结构

typedef struct // 标准写法
{
    // 中间的内容可以自行定义
    string name;
    string number;
}
person; // 新的数据类型的名字

修改后的代码如下:

#include <cs50.h>
#include <stdio.h>
#include <string.h>

typedef struct
{
    string name;
    string number;
}
person;


int main(void)
{
    person people[2];

    people[0].name = "Cater";
    people[0].number = "138-111-1256";

    people[1].name = "David";
    people[1].number = "153-256-4859";


    string name = get_string("Name: ");

    for (int i = 0; i < 2; i++)
    {
        if (strcmp(people[i].name, name) == 0)
        {
            printf("%s\n", people[i].number);
            return 0;
        }
    }

    printf("Not found\n");
    return 1;
}

排序方法
  • 排序——选择排序 $ \Theta (n^{2} )$

    用一个变量来记录最小的数,并和需要去的位置进行交换

    伪代码如下:

    For i from 0 to n-1
    	Find smallest number between numbers[i] and numbers[n-1]
    	Swap smallest number with numbers[i]
    
  • 排序——冒泡排序 $ O (n^{2} )$ $\Omega (n) $

    当需要排序的数组已经是处于大部分已排序的状态,这个方法更节省时间

    每次比较两个数的大小,较大的那个数往后移动,一直到没有需要交换为止

    伪代码如下:

    Repeat n times
    	For i from 0 to n-2 // 为什么是 n-2 ,因为最后一个是 n-1 而这个需要两个数字比较,如果到 n-1 ,那么会超出数组的边界
    		If numbers[i] and numbers[i+1] out of order
    			Swap them
    		If no swap
    			Quit
    
递归 recursion

迭代方式:

#include <cs50.h>
#include <stdio.h>

void draw(int n);

int main(void)
{
    int height = get_int("Height: ");
    draw(height);
}

void draw(int n)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < i + 1; j++)
        {
            printf("#");
        }
        printf("\n");
    }
}

递归方式:

#include <cs50.h>
#include <stdio.h>

void draw(int n);

int main(void)
{
    int height = get_int("Height: ");
    draw(height);
}

void draw(int n)
{
    // 传入的参数小于等于 0 时,返回
    if (n <= 0)
    {
        return;
    }

    // 画 n 层 = 画 n-1 层 + 自身的一层
    // 画 n-1 层
    draw(n - 1);

    // 自身的一层
    for (int i = 0; i < n; i++)
    {
        printf("#");
    }
    printf("\n");
}

1701921926451

利用递归的特性产生的排序方法——归并排序

这个方法会占用更多的内存,速度会更快 $\Theta(n logn) $

伪代码:

If only one number
	Quit
Else
	Sort left half of number
	Sort right half of number
	Merge sorted halves

1701923131665

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值