『算法导论』第二章

栏目: 编程工具 · 发布时间: 5年前

内容简介:本书介绍的第一个算法是利用本节以上面介绍的插入排序为例,展示如何分析算法的运行时间。用常数$c_i$表示计算机模型中基本操作所耗费的时间,推导出整个算法所需时间关于输入规模$n$的函数$T(n)$。算法分析一般只考察

本书介绍的第一个算法是 插入排序 算法。插入 排序 的工作机理和很多人打牌时,整理手中牌时的做法差不多。根据 排序算法 的伪代码,给出如下的 C语言 实现:

void sort(int nums[], int n)
{
    for (int i = 1; i < n; i++) {
        int key = num[i];
        int j;
        for (j = i - 1; key < num[j] && j >= 0; j--) {
            num[j+1] = num[j];
        }
        num[j+1] = key;
    }
}

利用 循环不变式 可以证明排序算法的正确性。

分析算法

本节以上面介绍的插入排序为例,展示如何分析算法的运行时间。用常数$c_i$表示计算机模型中基本操作所耗费的时间,推导出整个算法所需时间关于输入规模$n$的函数$T(n)$。算法分析一般只考察 最坏情况运行时间 ,这是算法运行时间的上界。

当$n$很大时,$T(n)$的低阶项相对来说不太重要,高阶项的常系数也不重要。忽略它们后,只剩下最重要项的因子。例如,对于插入排序,只剩下$n^2$。我们记插入排序的最坏情况时间代价为$\Theta(n^2)$。

算法设计

本节介绍一种常用设计策略,叫做 分治法 (divide and conquer)。 归并排序 算法遵循分治模式,直观上其操作如下:

  • 分解:将$n$个元素分成各含$n/2$个元素的子序列
  • 合并:合并两个已排序的子序列以得到排序结果

当待排序的序列长度为1时,递归“开始回升”,在这种情况下不做任何工作,因为长度为1的每个序列已排好序。

为完成算法,需要一个完成合并的辅助过程。由于两个子序列是已经排序好的,所以合并步骤的时间复杂度仅为$\Theta(n)$。它的代码如下:

void merge(int nums[], int aux[], int left, int mid, int right)
{
    // 将原数组nums中的元素拷贝到预先分配的辅助数组aux中
    for (int k = left; k <= right; k++) {
        aux[k] = nums[k];
    }

    int i = left;
    int j = mid + 1;
    for (int k = left; k <= right; k++) {
        if (i > mid) {
            nums[k] = aux[j++];
        } else if (j > right) {
            nums[k] = aux[i++];
        } else if (aux[j] < aux[i]) {
            nums[k] = aux[j++];
        } else {
            nums[k] = aux[i++];
        }
    }
}

下面便是递归调用过程的代码, merge_sort 也是辅助过程, sort 是最终的接口函数:

void merge_sort(int nums[], int aux[], int left, int right)
{
    if (left < right) {
        int mid = left + (right - left)/2;
        merge_sort(nums, aux, left, mid);       // 递归排序左边
        merge_sort(nums, aux, mid + 1, right);  // 递归排序右边
        merge(nums, aux, left, mid, right);     // 合并已排序好的两个数组
    }
}

void sort(int nums[], int n)
{
    // 开辟动态内存,作为参数传入
    int *aux = malloc(n * sizeof(int));
    if (aux != NULL) {
        merge_sort(nums, aux, 0, n - 1);
        free(aux);
    } else {
        printf("Error: malloc() failed!\n");
    }
}

当算法包含对其自身的递归调用时,要利用 递归方程递归式 来描述其运行时间。对于上述的归并排序,算法分解成两个子问题加上一个合并过程,所以递归方程如下:

$$

T(n) =

\begin{cases}

c, & \mbox{若} n=1 \\

2T(n/2)+cn, & \mbox{若} n>1

\end{cases}

$$

根据上面的递归公式,可以计算出归并排序算法的时间复杂度为$\Theta(n \log n)$。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web 2.0界面设计模式

Web 2.0界面设计模式

黄玮 / 电子工业出版社 / 2013-9-1 / 59

本书集Web 2.0的发展及特点、Web 2.0界面设计模式基本理论、实际模式实践及代码实现等诸多内容于一身,具有很强的实用性。这些内容不是简单的顺序堆砌,而是以Web 2.0界面设计模式和应用为主线,其中完美地穿插了各种与之相关的Web 2.0设计理念、用户行为模式、用户体验及基于Dojo的实现方式等相关知识,真正做到将Web 2.0界面设计模式所需要的方方面面的知识有机地融为一个整体。实现不需......一起来看看 《Web 2.0界面设计模式》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具