算法导论专题一--排序算法

排序算法作为许多程序的中间步骤,是计算机科学中的一个基本操作。

一、问题描述

排序算法输入的是n个数的一个序列<a1,a2…..an>,输出为输入的一个排列<a1’,…..an’>,满足a1’<a2’<….<an’

简言之就是输入一个序列,输出的是这个数组元素从小到大排列的另一序列。

二、方法思想综述

从算法导论这本书上根据算法的复杂度可以将排序算法分为三种,这两种方法都需要数据间的比较,而不需要。

其中有三种为选择,冒泡,插入。

选择排序:最直观,简单但是时间复杂度高,其比较次数多。思想是首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

冒泡排序:也是相对简单的方法,其交换次数多。思想是比较序列的相邻两个元素,如果递减,后小于前,那么交换两元素。让小的元素不断的向上浮到第一个位置,然后从剩余的元素里在浮出最小的元素到第二个位置,以此类推。

插入排序:适用用于少量元素的排序(通常为8个或以下)。思想是在已排好序的序列中找到位置,插入,初始时默认第一张是已经排好序的。这就相当于我们玩斗地主的时候,从底牌里不断抽牌,整理手牌的过程。

其中有三种为归并,堆,快速。其中归并和快速排序都采用了分治的思想,而堆排序使用了特殊的数据结构堆进行管理。分治策略里的关键是递归,要想实现递归就要将原问题分解成类似于原问题但规模更小的子问题。

其中有三种为计数,基数,桶。这些排序算法的特点是不需要比较操作,利用的是序列的序号和序列值之间的操作

三、过程代码分析

选择排序:输入一个length=n的数组,从0到n-2,对于未排序的找出最小的与当前的交换。

void selection_sort(int *a, int len)
{
     int i, j, min, t;
    for(i = 0; i < len - 1; i ++)
    {
        min = i;
        //查找最小值
        for(j = i + 1; j < len; j ++)
            if(a[j]> a[min])
               min = j;
        //交换
        if(min != i)
        {
            t = a[min];
            a[min] = a[i];
            a[i] = t;
        }
    }
}

注意点1.外层循环是从0-n-2,确定了n-1个数的序列,最后一个数的也就确定了。

2.没有记录最小元素,而是记录最小元素的下标。可以改为记录最小元素。

3.是在第二重循环,找到最小元素后而且最小元素不是当前元素情况下才进行交换的。

例子如[3 5 8 9 10 2 1 25]

[1 5 8 9 10 2 3 25]

.....   [1 2 3 5 8 9 10 25]

初始定最小元素下标为0,从1-n-1,如果元素值比最小元素的小,记录其下标使其而为最小元素。这里先是5后是6,循环结束后,把这个最小的和下标0这个位置的元素交换。这样经过第一次后,最小的元素就到第一个位置了。接着就定最小的元素下标为1,类推。

冒泡排序:不断把最小元素上浮,类似也可以把最大元素下沉。

void bubble_sort(int *a, int len)
{

int i, j, t;

for(i = 0; i < len - 1; i ++)

{

for(j = len-1; j > i; j --)

if(a[j]<a[j-1])

{

t = a[j];

a[j] = a[j-1];

a[j-1] = t;

}

}

}

注意点1.外层循环是从0-n-2,确定了n-1个数的序列,最后一个数的也就确定了。

2.内层循环里是从n-1-i,最后一个元素到未排序的第一个元素即第i个元素。

例子如[3 5 8 9 10 2 1 25]

[1 3 5 8 9 10 2 25]

.....   [1 2 3 5 8 9 10 25]

首先指向最后一个元素len-1,25,25<1,不交换,然后向上指向len-2,1,1<2,交换。不断的向上直到未排序的那个。这样最小元素就到了i的位置。

插入排序:

一堆牌,牌面朝下在桌面,取出第一张,一张就认为是排好序的,再从其中取出第二张,第二张跟手中已有排好序的比较,小于就继续,直到大于或者是元素超出手上的牌了。

void insertion_sort(int *a, int len)
 {
      int i, j, key;
    for(i = 1; i < len ; i ++)
    {
        key=a[i];
        j=i-1;
        while(j>=0&&a[j]>key)
        {
            a[j+1]=a[j];
            j--;
        }
        a[j+1]=key;
    }
 }

注意点1.默认第一张是排好序的,所以从第二个元素开始。

2.在比较过程中,while循环用来实现把比key小的元素向后移动

例子如[3 5 8 9 10 2 1 25],5 8 9 10都比3大,不符合while条件元素都不移动,所以在i=5的时候,我们已经有排好序的[5 8 9 10]手牌,这时key=2<a[j]=10,于是把10元素赋值到2的位置,而2我们已经用key来保存不会丢失。接着向上移动一个位置比较9<2,符合,赋值到后面一个位置,直到不小于key后者到顶的时候。出循环,把key值插入到正确位置。

四、算法分析

选择排序:

选择排序的交换操作介于次之间。选择排序的比较操作次之间。选择排序的赋值操作介于次之间。

比较次数,比较次数与关键字的初始状态无关,总的比较次数。交换次数,最好情况是,已经有序,交换0次;最坏情况是,逆序,交换次。交换次数比冒泡排序较少,由于交换所需CPU时间比比较所需的CPU时间多,值较小时,选择排序比冒泡排序快。

原地操作几乎是选择排序的唯一优点,实际适用的场合非常罕见。

冒泡排序:

个项目需要O()的比较次数,且可以原地排序。尽管这个算法是最简单了解和实作的排序算法之一,但它对于少数元素之外的数列排序是很没有效率的。

冒泡排序是与插入排序拥有相等的执行时间,但是两种法在需要的交换次数却很大地不同。在最好的情况,冒泡排序需要次交换,而插入排序只要最多交换。冒泡排序的实现(类似下面)通常会对已经排序好的数列拙劣地执行(),而插入排序在这个例子只需要个运算。

插入排序:

如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数减去(n-1)次。平均来说插入排序算法复杂度为O(n2)

参考资料:http://zh.wikipedia.org/wiki/

下节分析:归并,堆,快速

算法导论专题一--排序算法

时间: 2024-10-11 22:35:47

算法导论专题一--排序算法的相关文章

算法导论专题一--排序算法(2)

上节分析了O(n^2)的算法,这节就分析O(nlgn)的算法-归并,快速和堆排序. 一:综述 O(nlgn) 的算法可以分为两大类,两者所用的技术差别较大.归并和快速排序采用的是分治策略,这两者相当于一个对称的过程,一个是自顶向上合并子问题,另一个则自上向下分解子问题.而堆排序利用堆这一数据结构元素间的特殊关系来排序一个序列,另外采用二叉树的方式组织数据使其效率大大提高. 二:分治策略排序算法 1.为什么使用分治? 在上节算法的分析中,不管是冒泡.选择还是插入都不适用于大规模的数据,因为数据一大

算法导论之所有排序算法的Python实现

最近一段时间学习了算法导论第二版书的第一部分和第二部分的内容,自己编写了其中排序相关的几乎全部算法,包括冒泡排序(bubble sort).选择排序( selection sort).插入排序(insertion sort).希尔排序(shell sort).归并排序(merge sort).快速排序(quick sort).计数排序(count sort).基数排序(radix sort).桶排序(bucket sort).期望线性时间的第k个顺序统计量选择.最坏情况线性时间的中位数选择,并给

算法导论三剑客之 分治算法 合并排序

1 #include "iostream" 2 #include "windows.h" 3 #define MAX 0x7fffffff 4 using namespace std; 5 6 void merge(int s,int q,int e,int A[]){ 7 int i,j,k; 8 int B[100],C[100]; 9 for(i=s;i<=q;i++) 10 B[i-s+1]=A[i]; 11 for(j=q+1;j<=e;j++

算法导论——lec 13 贪心算法与图上算法

之前我们介绍了用动态规划的方法来解决一些最优化的问题.但对于有些最优化问题来说,用动态规划就是"高射炮打蚊子",采用一些更加简单有效的方法就可以解决.贪心算法就是其中之一.贪心算法是使所做的选择看起来是当前最佳的,期望通过所做的局部最优选择来产生一个全局最优解. 一. 活动选择问题 [问题]对几个互相竞争的活动进行调度:活动集合S = {a1, a2, ..., an},它们都要求以独占的方式使用某一公共资源(如教室),每个活动ai有一个开始时间si和结束时间fi ,且0 ≤ si &

基本算法研究1-冒泡排序算法测试

基本算法研究1-冒泡排序算法测试 1.经典冒泡排序法基本原理 先看一个动态图,感觉比较形象: 冒泡排序(Bubble Sort)是一种简单的排序算法.默认是从小到大排序,即把最大的数据排在最后,相当于每次把最大数据像气泡一样浮到水面一样.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换. 基本步骤: 1.比较相邻的元素.如果第一个比第二个大,就交换他们两个.        2.对每一对相邻元素作同样的工作,从开始第一对

【JavaScript】【算法】JavaScript版排序算法

JavaScript版排序算法:冒泡排序.快速排序.插入排序.希尔排序(小数据时,希尔排序会比快排快哦) 1 //排序算法 2 window.onload = function(){ 3 var array = [0,1,2,44,4, 4 324,5,65,6,6, 5 34,4,5,6,2, 6 43,5,6,62,43, 7 5,1,4,51,56, 8 76,7,7,2,1, 9 45,4,6,7,8]; 10 //var array = [4,2,5,1,0,3]; 11 array

链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述

关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学习过算法的系统性的课程,现在还是处于不断摸索的阶段,好多算法题目根本就没有什么思路,导致自己对好多题目都很是头疼,就算是自己做过的一些算法的题目,再次遇到也还是不一定会做出来,他给出的建议就是,看懂别人的程序,然后自己去敲,一定会出错,然后调试,有错误接着调试,一直到没有错误为止,并且要时常的去复习

冒泡排序算法和简单选择排序算法的js实现

之前已经介绍过冒泡排序算法和简单选择排序算法和原理,现在有Js实现. 冒泡排序算法 let dat=[5, 8, 10, 3, 2, 18, 17, 9]; function bubbleSort(data) { for(let i=0;i<data.length-1;i++){ for(let j=0;j<data.length-1-i;j++){ if(data[j]>data[j+1]){ [data[j],data[j+1]]=[data[j+1],data[j]]; } } }

python数据结构与算法第八天【排序算法】

1.排序算法的稳定性 稳定排序算法会让原本有相同键值的记录维持相对次序 例如:对以下元组按照元组的第一个元素升序排列,元组如下: (4,1) (3,1) (3,7) (5,6) 若要满足条件,则可能的排序有: 情况一: (3,1) (3,7) (4,1) (5,6) 情况二: (3,7) (3,1) (4,1) (5,6) 虽然情况一和情况二都是满足条件的,但是情况二在满足条件下打破了原本无需改变的顺序 原文地址:https://www.cnblogs.com/liuzhiqaingxyz/p/