算法导论6:排序小结和最值取法 2016.1.6

今天想做测试各个排序算法运行时间比较的程序,来对这几天学的排序算法小结一下。所以我先生成了1000000个1~150之间的随机数存到文件里。然后做了一个测试运行时间的程序。想看一下结构。但是结果效果并不太好。实践中,自己做的qsort函数和mergesort函数并没有理想中的那么快。

结果是这样:(可能并不准确,但却是是运行结果)

库函数快速排序:0.139000 seconds
自制快速排序:0.375000 seconds
归并排序:0.358000 seconds
堆排序:0.525000 seconds
计数排序:0.032000 seconds
插入+归并排序:0.313000 seconds

显然,除了线性复杂度的计数排序,其他的都比系统自带的库函数运行的慢。

因此得出以下结论:

1.懂了算法思想并不一定能做出最棒的程序。

2.以后排序首选系统自带库函数和计数排序,其他的排序算法可以当作思想来借鉴。

那么排序算法大体就到这里。下一节一开始讲的是最值的选法。

从n个数里选出最小值。复杂度下界是n

从n个数里选出最大值。复杂度下界也是n

但是,从n个数里同时选出最小值和最大值,算法导论给出了复杂度(3/2)n的优化算法。

就是通过一个一个的比较改成一对一对的比较

每次找两个数,先比较这两个数,然后让较大值与当前的最大值比较,让较小值与当前最小值比较。这样优化之后,原来每两个数要比较4次,现在只需要比较3次,所以复杂度优化成了原来的3/2 。

代码今天就先不打了,这个问题比较简单。可能需要分n为奇数还是偶数讨论一下。

PS:下面是测试排序时用到的生成随机数和测试时间的代码。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int *makerandom(int n,int x)
{
    int *a=(int *)malloc((n+1)*sizeof(int));
    srand(time(0));
    int i;
    for (i=1;i<=n;i++) {
        a[i]=rand()%x+1;
    }
    return a;
}
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

int main()
{
    long i=100000000L;
    clock_t start,finish;
    double duration;
    start=clock();
    /*while (i--);*/  //测试时间的代码
    finish=clock();
    duration=(double)(finish-start)/CLOCKS_PER_SEC;
    printf("%lf seconds\n",duration);
    return 0;
}
时间: 2024-10-07 10:39:58

算法导论6:排序小结和最值取法 2016.1.6的相关文章

算法导论--------------计数排序and基数排序

计数排序假设n个输入元素中的每一个都介于0和k之间的整数,k为n个数中最大的元素.当k=O(n)时,计数排序的运行时间为θ(n).计数排序的基本思想是:对n个输入元素中每一个元素x,统计出小于等于x的元素个数,根据x的个数可以确定x在输出数组中的最终位置.此过程需要引入两个辅助存放空间,存放结果的B[1...n],用于确定每个元素个数的数组C[0...k].算法的具体步骤如下: (1)根据输入数组A中元素的值确定k的值,并初始化C[1....k]= 0: (2)遍历输入数组A中的元素,确定每个元

算法导论 计数排序

计数排序的关键就在于如何处理每个元素的最终位置.在计数排序中,我们可以通过维护一个数组C[i]来记录键值为i的元素所属的位置.每次输入一个A[i],首先记录每个A[i]出现的次数C[i],然后从前向后C[i]=C[i-1]+C[i],这样可以得出值为i所在排序后新数组中的最后一个重复数的位置.计数排序的一个显然问题就是C[]数组的大小确定的问题.下面贴上我自己理解写出的代码. #include<iostream> using namespace std; int main() { int n,

算法导论——拓扑排序

package org.loda.graph; import org.loda.structure.Stack; import org.loda.util.In; /** * * @ClassName: Topological * @Description: 拓扑排序是所有节点dfs的逆后序,也就是每个节点任务完成的时间的逆序排序 * @author minjun * @date 2015年5月24日 下午7:17:53 * */ public class Topological { /** *

算法导论------------桶排序算法之研究

举个来说明桶排序的过程,假设现在有A={0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.68},桶排序如下所示: 研究过计数排序我们知道了----计数排序是假设输入是由一个小范围内的整数构成,而桶排序则假设输入由一个随机过程产生的,该过程将元素均匀而独立地分布在区间[0,1)上.当桶排序的输入符合均匀分布时,即可以线性期望时间运行.桶排序的思想是:把区间[0,1)划分成n个相同大小的子区间,成为桶(bucket),然后将n个输入数分布到各个桶中去,对

算法导论读后小结(一)

一.分治法(递归算法) 说明:许多算法在结构上是递归的,为了解决某一问题,算法需要一次或多次递归的调用自身以解决紧密相关的若干子问题,这些算法遵循分治法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题然后在合并这些子问题的解来建立原问题的解. 分治模式在每层递归时都有三个步骤: 1)分解,分解原问题为若干子问题,这些子问题是原问题规模较小的实例. 2)解决,解决这些子问题,递归的求解这些子问题.当子问题的规模足够小则直接求解. 3)合并,这些子问题的解构成原问题的解

[算法导论]拓扑排序 @ Python

class Graph: def __init__(self): self.V = [] class Vertex: def __init__(self, x): self.key = x self.color = 'white' self.d = 10000 self.f = 10000 self.pi = None self.adj = [] self.next = None class Solution: def Dfs(self, G): for u in G.V: u.color =

算法导论--图的存储(邻接表与邻接矩阵)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51888031 图的存储方法有邻接表.邻近矩阵.邻接多重表.十字链表等.本篇文章介绍两种简单且比较常用的两种方法:邻接表与邻接矩阵方法. 以下面的无向图为例,介绍两种存储方法.有向图的存储方法类似,只是边是单方向,无向图的边可以看做双向. 1.邻接链表法 邻接链表表示法对图中的每个顶点建立一个带头的边链表:第i条链表代表依附于顶点vi所有边信息,若为有向图,则表示

算法导论学习之插入排序+合并排序

最近准备花时间把算法导论详细的看一遍,强化一下算法和数据结构的基础,将一些总结性的东西写到博客上去. 一.插入排序 算法思想:如果一个数组A,从A[1–n-1]都是有序的,然后我们将A[n]插入到A[1–n-1]的某个合适的位置上去那么就可以保证A[1–n]都是有序的.这就是插入排序的思想:具体实现的时候我们将数组的第一个元素看出有序,然后从第二个元素开始按照上面的步骤进行插入操作,直到插入最后一个元素,然后整个数组都是有序的了. 时间复杂度分析:代码中有两重for循环,很容易看出时间复杂度是n

算法导论—排序之插入排序

void insertion_sort(vector<int> &num){ for(int i = 1; i < num.size(); i++){ int j = i-1; int val = num[i]; while(j>=0 && num[j] >= val){ num[j+1] = num[j]; j--; } num[j+1] = val; } } 每次迭代时,将num[i] 作为key值,且前子数组[0,i-1] 构成已排好序,每次与左