经典排序算法分析(附源码)

No.1 冒泡排序

关于冒泡排序相信大家学排序算法的时候,老师肯定会讲这一个,因为这个便于理解。记得当时我的老师说,冒泡排序就像是从水底涌出的气泡,慢慢地向上升,越来越大。也就是说最大的元素往后排列。感觉这个比喻有点冷啊!

假设数组的长度为N,可以用下面的步骤实现冒泡排序:

1. 比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交 换。

2. 这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就上升到数组第N-1个位置。

3. N=N-1,如果N不为0就重复前面二步,否则排序完成。

下面给出源码实现:

void bubbleSort(int A[],int len)
{
for(int i = 0;i < len;i++)
for(int j = 0;j < len-i-1;j++)
{
if(A[j]>A[j+1])
swap(A[j],A[j+1]);
}
}

No.2 直接插入排序

直接插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成 为止。 设数组为 a[0…n-1]。

1. 初始时, a[0]自成 1 个有序区,无序区为 a[1..n-1]。 令 i=1

2. 将 a[i]并入当前的有序区 a[0…i-1]中形成 a[0…i]的有序区间。

3. i++并重复第二步直到 i==n-1。排序完成。

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

No.3 希尔排序

该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序, 待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插 入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是 很高的,因此希尔排序在时间效率上比前两种方法有较大提高。

void shellSort(int A[],int n)
{
int grap,i,j;
for(grap = n/2;grap > 0;grap /=2)
for(i = grap;i < n;i++)
for(j = i-grap;j>=0 && A[j]>A[j+grap];j -= grap)
swap(A[j+grap],A[j]);

}

No.4  直接选择排序

直接选择排序和直接插入排序类似,都将数据分为有序区和无序区,所不同的是 直接插入排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有 序区,而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后。

设数组为 a[0…n-1]。

1. 初始时, 数组全为无序区为 a[0..n-1]。 令 i=0

2. 在无序区 a[i…n-1]中选取一个最小的元素,将其与 a[i]交换。交换之后 a[0…i] 就形成了一个有序区。

3. i++并重复第二步直到 i==n-1。排序完成。

void selectSort(int A[],int len)
{
for(int i = 0;i < len;i++)
{
int min = i;
for(int j = i+1;j<len;j++)
if (A[min] > A[j])
{
min = j;
}
swap(A[min],A[i]);
}
}

No.5  归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的 第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较, 如果有数列为空,那直接将另一个数列的数据依次取出即可。

void merge(int A[],int p,int mid,int q)
{
int i = p, j = mid + 1;
int m = mid, n = q;
int k = 0;
int *temp = new int[q-p+1];

while (i <= m && j <= n)
{
if (A[i] <= A[j])
temp[k++] = A[i++];
else
temp[k++] = A[j++];
}

while (i <= m)
temp[k++] = A[i++];

while (j <= n)
temp[k++] = A[j++];

for (i = 0; i < k; i++)
A[p + i] = temp[i];
delete []temp;
}
void mergeSort(int A[],int p,int q)
{
if(p<q)
{
int m = (p+q)/2;
mergeSort(A,p,m);
mergeSort(A,m+1,q);
merge(A,p,m,q);
}
}

No.6 快速排序

它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

int partition(int A[],int p,int q)
{
int key = A[p];
while(p<q)
{
while (p<q && A[q]>=key)
q--;
A[p] = A[q];
while(p<q && A[p]<=key)
p++;
A[q] = A[p];
}
A[p] = key;
return p;
}
void quickSort(int A[],int p,int q)
{
int pos;
if(p<q)
{
pos = partition(A,p,q);
quickSort(A,p,pos);
quickSort(A,pos+1,q);
}
}

No.7 堆排序

先介绍一下堆的定义:

堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]

即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。

堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

堆排序的思想

利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。

其基本思想为(大顶堆):

1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;

2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];

3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

操作过程如下:

1)初始化堆:将R[1..n]构造为堆;

2)将当前无序区的堆顶元素R[1]同该区间的最后一个记录交换,然后将新的无序区调整为新的堆。

因此对于堆排序,最重要的两个操作就是构造初始堆和调整堆,其实构造初始堆事实也是调整堆的过程,只不过构造初始堆是对所有的非叶节点都进行调整。

void HeapAdjust(int A[],int i,int len)
{
int lchild = 2*i+1;
int rchild = 2*i+2;
int parentPos = i;//临时变量存放当前父节点
if(i<=(len-1)/2)//如果i不是叶节点就不用进行调整
{
if(lchild<=len-1 && A[lchild]>A[parentPos])
parentPos = lchild;
if(rchild<=len-1 && A[rchild]>A[parentPos])
parentPos = rchild;
if(parentPos!=i)
{
swap(A[i],A[parentPos]);
HeapAdjust(A,parentPos,len);//避免调整之后parentPos为父节点的子树不是堆
}
}

}

void buildHeap(int A[],int len)//建立堆
{
int i = (len-1)/2;
while(i>=0)
{
HeapAdjust(A,i,len);
i--;
}
}

void heapSort(int A[],int len)
{
int i;
buildHeap(A,len);
for(i = len;i>=1;i--)//调整排序,即每次将剩余元素中最大的元素放到最后面
{
HeapAdjust(A,0,i);
swap(A[0],A[i-1]);
}
}

以上是七种基本的排序算法,另外还有基数排序,计数排序,桶排序等排序算法,就不做介绍了。

基础最重要,不要轻视基础,要重视它,打牢它,才能取得更大的成绩。

时间: 2024-10-12 04:58:14

经典排序算法分析(附源码)的相关文章

Android应用经典主界面框架之一:仿QQ (使用Fragment, 附源码)

最近反复研究日常经典必用的几个android app,从主界面带来的交互方式入手进行分析,我将其大致分为三类.今天记录第一种方式,即主界面下面有几个tab页,最上端是标题栏,tab页和tab页之间不是通过滑动切换的,而是通过点击切换tab页.早期这种架构一直是使用tabhost+activitygroup来使用,随着fragment的出现及google官方也大力推荐使用fragment,后者大有代替前者之势.本文也使用fragment进行搭建,标题中的"经典"指这种交互经典,非本文的代

iOS二十种超酷时尚艺术滤镜汇总【附源码】

本文总结了20种ios滤镜都是基于GPUImage的,有3种滤镜是GPUImage库中包含的,还有17种是Instagram中的经典滤镜,集成在一个项目中.使用GPUImage可以非常容易创建我们自己的滤镜效果总会有你想要的效果吧.在文章下面附源码下载 相信你也在使用滤镜吧,今天就让你见识一下滤镜实现其实也不是一件特别难的技术,下面附一些效果图.由于几种滤镜最主要的实现是一段片段着色程序,所以会进行展示 Amaro滤镜,通过FWAmaroFilter类来实现.它是Instagram应用中的经典滤

ANDROID自定义视图——仿瀑布布局(附源码)

简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3.绘制--onDraw():如何绘制这个View. 第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到1,2两个步骤就中好了. 第一步的测量,可以参考:(ANDROID自定义视图--onMeasure,MeasureSpec源码 流程 思路详解) 第二步的布局,可以参考:(AN

从零开始编写自己的C#框架(6)——SubSonic3.0插件介绍(附源码)

原文:从零开始编写自己的C#框架(6)--SubSonic3.0插件介绍(附源码) 前面几章主要是概念性的东西为主,向初学者们介绍项目开始前的一些知识与内容,从本章开始将会进入实操阶段,希望跟着本系统学习的朋友认真按说明做好每一步操作(对于代码最好是直接照着文档内容在你的IDE中打一次出来,而不是使用复制粘贴),这样对你理解后面的章节会有较好的帮助,如果你对我这种书写方式有什么建议或支持,也希望在评论中留言,谢谢你的支持. SubSonic3.0简介 SubSonic是Rob Conery用c#

30种奇妙的鼠标悬停效果【附源码下载】

Web 界面上交互的方式很多,只要你去探索,你会发现很多让你眼前一亮的想法.Codrops 最近发布了一组悬停效果,总共分为两组,多达30种不同的风格.为了让效果尽可能的平滑,最好不要在元素上使用变换以免影响布局.第二组效果中采用了 SVG 动画,这也是目前比较流行的方式. 温馨提示:为保证最佳的效果,请在 IE10+.Chrome.Firefox 和 Safari 等现代浏览器中浏览. 在线演示      源码下载 您可能感兴趣的相关文章 网站开发中很有用的 jQuery 效果[附源码] 分享

实用图片滑块,传送带,幻灯片效果【附源码】

图片是网站功能的重要组成部分,这里集合了10个图片滑块,传送带,幻灯片效果,相信你在项目中肯定会用到.这些分享的效果大部分都是实用 jQuery 实现的,使用起来很简单.看看下面这些惊人的功能和效果,我相信你会发现一些很有用的东西. 适合电子商务网站的图片滑块 Sequence.js 是一个非常现代的图片滑动效果,特别适合电子商务网站或者企业产品展示功能.带有图片缩率图,能够呈现全屏图片浏览效果.结合 CSS3 Transition 实现响应式的滑块效果. 效果演示     插件下载 经典的 j

C#中的WinFrom技术实现串口通讯助手(附源码)

C#中的WinFrom技术实现串口通讯助手(附源码) ??实现的功能: 1.实现自动加载可用串口. 2.打开串口,并且使用C#状态栏显示串口的状态. 3.实现了串口的接收数据和发送数据功能. 4.串口使用定时器进行定时发送数据. 5.可以打开文件夹,选择文件进行发送,并且将发送文件的内容显示在发送文本框中. 6.可以清空发送和接收文本框中的内容. 7.可以实时计算发送和接收的字节数. 8.实现打开文件夹保存发送和接收的文件内容(目前只支持.txt文件). 9.实时显示当前时间. ??功能演示 1

一组网页边栏过渡动画,创意无限!【附源码下载】

今天我们想与大家分享另一套过渡效果.这一次,我们将探讨如何实现侧边栏的过渡动画,就像我们已经在多级推出菜单中使用的.我们的想法是,以细微的 过渡动画显示一些隐藏的侧边栏,其余的内容也是.通常侧边栏滑入,把其他内容推到一边.这个可过程中可以加入很多微妙而奇特的效果,而今天这篇文章能够给 你一些启示. 温馨提示:为保证最佳的效果,请在 IE10+.Chrome.Firefox 和 Safari 等现代浏览器中浏览. 立即下载      在线演示 因为我们希望能够在一个页面上展现所有的效果,因此我们示

创意无限!一组网页边栏过渡动画【附源码下载】

今天我们想与大家分享另一套过渡效果.这一次,我们将探讨如何实现侧边栏的过渡动画,就像我们已经在多级推出菜单中使用的.我们的想法是,以细微的过渡动画显示一些隐藏的侧边栏,其余的内容也是.通常侧边栏滑入,把其他内容推到一边.这个可过程中可以加入很多微妙而奇特的效果,而今天这篇文章能够给你一些启示. 温馨提示:为保证最佳的效果,请在 IE10+.Chrome.Firefox 和 Safari 等现代浏览器中浏览. 立即下载      在线演示 因为我们希望能够在一个页面上展现所有的效果,因此我们示例的