算法之经典排序算法小归纳
Posted chen_zhang_yu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法之经典排序算法小归纳相关的知识,希望对你有一定的参考价值。
前言
数据结构和算法是写代码的基础。基本功很重要,所谓根基深度决定成长高度。以前没吃好的饭,总有一天要回来吃的。这段时间项目不忙,回来吃饭,决定花一段时间捋一捋数据结构和算法的基础知识。
当然,能捋多少捋多少吧,这些知识的深度,也不是朝夕之间就能有所成的,本身就是一件需要潜心花费大量时间来学习巩固的东西。夯实基础,越坚实越好。
正文
这篇博客简要总结了七个算法:冒泡排序,选择排序,插入排序,希尔排序,快速排序,归并排序和堆排序。本文所有的描述都是根据自己的理解手打的,为的是方便读懂,示例代码可以实现算法,但是不敢保证就是最优的。如描述内容有误,请指正。
好了开始吧..
1.冒泡排序
从数组的一端开始两两比较,依次将当前最值移动到数组另一端端的排序方法。经实测,在这几个算法中速度是最慢的。
代码:
/**
* 冒泡排序(由小到大)
*
* @param array
* @return
*/
private static void bubbleSequence(int[] array) {
if (null != array) {
long ts = System.currentTimeMillis();
int length = array.length;
for (int i = 0; i < length; i++) {
for (int j = 0; j < length - 1 - i; j++) {
if (array[j] > array[j + 1])
exchange(array, j, j + 1);
}
}
long te = System.currentTimeMillis();
System.out.println("冒泡排序 time cost(ms):" + (te - ts));
}
}
2.选择排序
从数组的一端开始选取元素依次和其他所有元素对比,将最值依次交换到目标位置 的排序方法。
代码:
/**
* 选择排序(由小到大)
*
* @param array
* @return
*/
private static void selectSequence(int[] array) {
if (null != array) {
long ts = System.currentTimeMillis();
int length = array.length;
for (int i = 0; i < length; i++) {
for (int j = i + 1; j < length; j++) {
if (array[j] < array[i])
exchange(array, j, i);
}
}
long te = System.currentTimeMillis();
System.out.println("选择排序 time cost(ms):" + (te - ts));
}
}
3.插入排序
把数组中的无序序列元素依次插入到有序序列中的排序方法,对于部分有序序列效率很高。如果是完全无序序列,则初始有序序列长度为1.
代码:
/**
* 插入排序 由小到大
*
* @param array
* @return
*/
private static void insertSequence(int[] array) {
long ts = System.currentTimeMillis();
if (null != array) {
int length = array.length;
int temp = 0;
// 开始插入排序,第i位依次在前i-1位中找位置
for (int i = 1; i < length; i++) {
if (array[i] > array[i - 1]) {// 被比较值比前面都大
continue;
}
for (int j = 0; j < i - 1; j++) {// 前i位依次对比
if (array[i] < array[j]) {
temp = array[i];
for (int k = i; k > j; k--) {
array[k] = array[k - 1];// 被插入位置之后的元素依次后挪
}
array[j] = temp;// 插入值
break;
}
}
}
long te = System.currentTimeMillis();
System.out.println("插入排序 time cost(ms):" + (te - ts));
}
}
4.希尔排序
相比而言,前三种都是比较基础的排序方法,容易理解。从这里开始,要费点脑子了。希尔排序用到了基础排序方法中的插入排序,它的基本思想是:将数组按照一定的步长分成若干个子数组,(通俗的举个例子,就像让一排人报数,循环报1、2、3,报完过后喊1的人为一组,喊2的人为一组,喊3的人为一组,这一队人就被分成了三个小组。)然后对子数组进行插入排序,使之有序。然后缩小步长,继续分组,排序。等到步长为1时,排序完成。经实测希尔排序的效率是很高的,比前面三种算法速度快十几到几十倍不等。
代码:
/**
* 希尔排序
*
* @param array
* @return
*/
private static void shellSequence(int[] array) {
if (null != array) {
long ts = System.currentTimeMillis();
int length = array.length;
int stepLength = 1;// 步长
// 计算初始步长
while (stepLength < length / 3) {
stepLength = stepLength * 3 + 1;
}
while (stepLength >= 1) {
// 使间隔为h的数组变为有序
for (int i = 0; i < stepLength; i++) // 直接插入排序
{
for (int j = i + stepLength; j < length; j += stepLength)
if (array[j] < array[j - stepLength]) {
int temp = array[j];
int k = j - stepLength;
while (k >= 0 && array[k] > temp) {
array[k + stepLength] = array[k];
k -= stepLength;
}
array[k + stepLength] = temp;
}
}
stepLength /= 3;// 步长缩短
}
long te = System.currentTimeMillis();
System.out.println("希尔排序 time cost(ms):" + (te - ts));
}
}
5.归并排序
归并排序依赖归并操作,即将两个已经排序的序列合并成一个序列的操作,归并排序的过程是:将一个数组拆分成两个子数组,再对子数组进行拆分......直到最后子数组的长度为1,然后子数组按顺序合并,两两合并,两两合并,直到恢复到原数组长度,排序完成。有一个生动的动图:
代码递归实现:
/**
* 归并排序
*
* 先将数组拆分为子序列,递归进行,直至分为所有子序列长度都为1,然后将两两子序列合并排序,合并完成后,排序完成.
*
* @param array
* 待排序数组
* @param result
* 作为挪动空间的辅助数组
* @return
*/
private static void mergeSequence(int[] array, int result[], int start, int end) {
// 参考维基百科的动图,先拆再合,递归执行
if (start >= end)
return;
if (null != array) {
int length = end - start;
int middle = (length >> 1) + start;
int start1 = start, end1 = middle;
int start2 = middle + 1, end2 = end;
mergeSequence(array, result, start1, end1);
mergeSequence(array, result, start2, end2);
int k = start;
while (start1 <= end1 && start2 <= end2) // 挨个比较值,合并排序
result[k++] = array[start1] < array[start2] ? array[start1++] : array[start2++];
while (start1 <= end1) // 合并1的尾巴
result[k++] = array[start1++];
while (start2 <= end2) // 合并2的尾巴
result[k++] = array[start2++];
for (k = start; k <= end; k++)// 合并后的值赋回原数组
array[k] = result[k];
}
}
6.快速排序
快速排序的过程是,1.选一个元素作为基准值,将大于基准值的元素放到一边,小于基准值的元素放到另一边,形成左右两个子序列。然后对子序列继续进行这样的操作,直到子序列长度为1,排序完成。
代码:
/**
* 快速排序
* 按照某个基准值,将数组分为大于该值和小于该值的两个子序列,然后递归的对子序列继续按此方法排序,直到最终子序列长度为1时,排序完成.
* 小规模实验测得,排序效率并不稳定,时快时慢,与具体数组有关.
* @param array 待排序数组
* @param start
* @param end
*/
private static void quickSequence(int[] array,int start, int end) {
if (start >= end)
return;
int mid = array[end];//将最后一位元素作为基准值
int left = start, right = end - 1;
//设定:左边序列小于基准值,右边序列大于基准值
//从左右两边向中间分别搜索小于和大于基准值的元素,将两边不符合条件的元素相互交换
while (left < right) {
while (array[left] < mid && left < right)
left++;
while (array[right] >= mid && left < right)
right--;
exchange(array,left, right);
}
//搜索完毕后,如果左边的元素还大于基准值,则将其与基准值交换,这种情况一股出现在基准值恰好选成了序列中的最小值
if (array[left] >= array[end])
exchange(array,left, end);
else
left++;
//递归操作左边序列
quickSequence(array,start, left - 1);
//递归操作右边序列
quickSequence(array,left + 1, end);
}
7.堆排序
以上是关于算法之经典排序算法小归纳的主要内容,如果未能解决你的问题,请参考以下文章