大二暑假《算法导论》学习笔记-第一天

今天主要学习了第二章“算法基础”。
主要包括以下几个方面:

  • 插入排序

  • 分析算法的方法

  • 分治法设计算法

  • 归并排序

下面逐条进行归纳和总结。


一.插入排序

在编程解决问题的过程中,排序使我们经常会遇到的一个不可或缺的步骤,但是这个步骤虽然看起来很简单,但是由于方法多样,他们的差异很大,因此选择不同的排序方法,对运算的成本可能会造成很大的影响。插入排序就是其中的一个效率比较低的一种方法,但是优点是易于理解。

算法导论》中举了一个十分生动的例子来介绍插入排序。

插入排序类似于我们将我们手中的扑克牌排序,刚开始时候我们手中没有牌,之后每拿一张牌,我们就把他按大小顺序放在正确的位置上,为此我们需要从右到左一次比较,直到找到合适的位置,然后把这张牌插进去。

插入排序的工作原理与此类似,当我们拿到一组数,就把其中的第一个数拿出来,之后按次序拿剩下的数,每拿一个数出来就和已经拿出来的数从右向左依次进行比较,把他放在合适的位置上,直到将所有的数拿完,现在我们就得到了有序的数列。

c++代码实现如下:

#include<iostream>
using namespace std;

void insertionSort(int a[],int n) {
    for (int i = 0; i < n; i++) {
        int key = a[i];//取出第一个数
        int j = i - 1;
        while (j >= 0 && a[j] > key) {//已经排好序的数依次与该数进行比较
            a[j + 1] = a[j];
            j--;
        }
        a[j + 1] = key;
    }
}

int main() {
    int n;
    cout << "please input the number of your array\n";
    cin >> n;
    int *array = new int[n];
    cout << "please input " << n << " numbers\n";
    for (int i = 0; i < n; i++) {
        cin >> array[i];
    }
    insertionSort(array, n);
    for (int i = 0; i < n; i++)
        cout << array[i] << " ";
    cout << endl;
    return 0;
}

二.以插入排序为例进行算法分析

对一个算法的分析,我认为主要包括以下两个方面:

  1. 算法的正确性
  2. 算法的效率

对于第一点,其实非常重要,一个算法,不管效率如何,首先要保证正确,但是我原来在学习的时候总是默认他们都是正确的,直到今天才学到了如何证明一个算法的正确性。

在此之前,我们首先要引入一个概念,叫做循环不变式

在上述插入排序的例子中,我们在每次拿一张牌之后,会把他插入到手中已有的牌堆中,我们手中已有的牌堆,是已经排好序的牌,我们把这些牌也就是a[0..i-1]称为循环不变式

循环不变式可以帮助我们理解算法的正确性。对于循环不变式,我们要证明三条性质:

  1. 初始化:确保循环开始之前,它为真
  2. 保持:确保每次循环后,他仍然为真
  3. 终止:循环结束时不变式可以为我们提供一个有用的性质,帮助我们证明算法的正确性

下面我们以插入排序为例,用循环不变式的方法,证明其正确性

初始化: 第一次执行循环之前,我们手中只拿到一张牌,他已经是有序的,所以此时为真

保持:每次我们摸到一张牌,都会和手中已经排好序的牌从右向左一次比较,直到找到合适的位置才把他插进去,这时候手中的牌多了一张,但仍然是有序的,所以此时仍然为真,循环不变式保持。

终止:当牌堆中没有牌,也就是我们把所有牌都摸完了,那么循环结束,此时我们手中的牌仍然是原来排队中的牌,但已经经过排序,所以结果正确,算法的正确性得到证明。

ps:你有可能会觉得这不是废话吗,那估计是我说的不够有逻辑,参考《算法导论》第三版11页。

对于第二点,算法的效率,其实就是我们常说的时间复杂度
对于时间复杂度的计算方法,因人而异,我们平常只需要大致的估算出他的数量级就可以了,不需要进行太精确的逐步计算,关于逐步计算时间复杂度,请参考《算法导论》第三版14页,这里我贴一张图:
这里写图片描述

上图是一段关于插入排序的伪代码,每一行的末尾标出了执行此代码的代价和执行次数,把他们分别相乘再相加,然后进行化简,就可以得出插入排序的时间复杂度,是O(n^2),我们这里指的是最坏情况或者说平均情况的时间复杂度。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值