常见排序算法
冒泡排序
核心思想:将待排序序列从前往后,一次比较相邻元素的值,逆序则交换(如果一次循环中没有发生一次交换则序列有序,结束排序),使较大(或较小)的值逐渐往后移。
public static void bubbleSort(int[] num) {
for(int i=0;i<num.length;i++ ) {
boolean flag = false;
for(int j=0;j<num.length-1-i;j++ ) {
if(num[j]>num[j+1]) {
int temp = num[j];
num[j]=num[j+1];
num[j+1]=temp;
}
}
if(!flag){
break;
}
}
}
选择排序
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。重复第二步,直到所有元素均排序完毕。
public static void selectSort(int[] num) {
for(int i=0;i<num.length;i++ ) {
int index=i;
for(int j=i+1;j<num.length;j++ ) {
if(num[index]>num[j]) {
index = j;
}
}
if(index!=i) {
int temp = num[index];
num[index]=num[i];
num[i]=temp;
}
}
}
插入排序
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
public static void insertSort(int[] num) {
for(int i = 1;i<num.length;i++) {
int temp = num[i];
int index=i;
for(int j = i-1;j>=0;j--) {
if(num[j]>temp) {
num[index]=num[j];
index--;
}
}
num[index]=temp;
}
}
希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
public static void shellSort(int[] num) {
for(int gap = num.length/2;gap>0;gap=gap/2) {
for(int i = gap;i<num.length;i++) {
int index = i;
int temp = num[i];
for(int j=i-gap;j>=0;j=j-gap) {
if(num[j]>temp) {
num[index]=num[j];
index-=gap;
}
}
num[index]=temp;
}
}
}
快速排序
public static void quickSort(int first, int end, int[] num) {
if(first>end) {
return;
}
int temp = num[first] ;
int st = first ;
int en = end;
while(st!=en) {
while(en>st&&num[en]>=temp) {
en--;
}
while(en>st&&num[st]<=temp) {
st++;
}
if(st<en) {
int t = num[st];
num[st]= num[en];
num[en]=t;
}
}
num[first]= num[en];
num[en]=temp;
quickSort(0,st-1, num);
quickSort(st+1,end, num);
}
归并排序
/**
* 归并排序: Java
*
* @author skywang
* @date 2014/03/12
*/
public class MergeSort {
/*
* 将一个数组中的两个相邻有序区间合并成一个
*
* 参数说明:
* a -- 包含两个有序区间的数组
* start -- 第1个有序区间的起始地址。
* mid -- 第1个有序区间的结束地址。也是第2个有序区间的起始地址。
* end -- 第2个有序区间的结束地址。
*/
public static void merge(int[] a, int start, int mid, int end) {
int[] tmp = new int[end-start+1]; // tmp是汇总2个有序区的临时区域
int i = start; // 第1个有序区的索引
int j = mid + 1; // 第2个有序区的索引
int k = 0; // 临时区域的索引
while(i <= mid && j <= end) {
if (a[i] <= a[j])
tmp[k++] = a[i++];
else
tmp[k++] = a[j++];
}
while(i <= mid)
tmp[k++] = a[i++];
while(j <= end)
tmp[k++] = a[j++];
// 将排序后的元素,全部都整合到数组a中。
for (i = 0; i < k; i++)
a[start + i] = tmp[i];
tmp=null;
}
/*
* 归并排序(从上往下)
*
* 参数说明:
* a -- 待排序的数组
* start -- 数组的起始地址
* endi -- 数组的结束地址
*/
public static void mergeSortUp2Down(int[] a, int start, int end) {
if(a==null || start >= end)
return ;
int mid = (end + start)/2;
mergeSortUp2Down(a, start, mid); // 递归排序a[start...mid]
mergeSortUp2Down(a, mid+1, end); // 递归排序a[mid+1...end]
// a[start...mid] 和 a[mid...end]是两个有序空间,
// 将它们排序成一个有序空间a[start...end]
merge(a, start, mid, end);
}
/*
* 对数组a做若干次合并: 数组a的总长度为len,将它分为若干个长度为gap的子数组;
* 将"每2个相邻的子数组" 进行合并排序。
*
* 参数说明:
* a -- 待排序的数组
* len -- 数组的长度
* gap -- 子数组的长度
*/
public static void mergeGroups(int[] a, int len, int gap) {
int i;
int twolen = 2 * gap; // 两个相邻的子数组的长度
// 将"每2个相邻的子数组" 进行合并排序。
for(i = 0; i+2*gap-1 < len; i+=(2*gap))
merge(a, i, i+gap-1, i+2*gap-1);
// 若 i+gap-1 < len-1,则剩余一个子数组没有配对。
// 将该子数组合并到已排序的数组中。
if ( i+gap-1 < len-1)
merge(a, i, i + gap - 1, len - 1);
}
/*
* 归并排序(从下往上)
*
* 参数说明:
* a -- 待排序的数组
*/
public static void mergeSortDown2Up(int[] a) {
if (a==null)
return ;
for(int n = 1; n < a.length; n*=2)
mergeGroups(a, a.length, n);
}
public static void main(String[] args) {
int i;
int a[] = {80,30,60,40,20,10,50,70};
System.out.printf("before sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
mergeSortUp2Down(a, 0, a.length-1); // 归并排序(从上往下)
//mergeSortDown2Up(a); // 归并排序(从下往上)
System.out.printf("after sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
}
}
堆排序
最大堆进行升序排序的基本思想: ① 初始化堆: 将数列a[1…n]构造成最大堆。 ② 交换数据: 将a[1]和a[n]交换,使a[n]是a[1…n]中的最大值;然后将a[1…n-1]重新调整为最大堆。 接着,将a[1]和a[n-1]交换,使a[n-1]是a[1…n-1]中的最大值;然后将a[1…n-2]重新调整为最大值。 依次类推,直到整个数列都是有序的。
public class HeapSort {
/*
* (最大)堆的向下调整算法
*
* 注: 数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
* 其中,N为数组下标索引值,如数组中第1个数对应的N为0。
*
* 参数说明:
* a -- 待排序的数组
* start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
* end -- 截至范围(一般为数组中最后一个元素的索引)
*/
public static void maxHeapDown(int[] a, int start, int end) {
int c = start; // 当前(current)节点的位置
int l = 2*c + 1; // 左(left)孩子的位置
int tmp = a[c]; // 当前(current)节点的大小
for (; l <= end; c=l,l=2*l+1) {
// "l"是左孩子,"l+1"是右孩子
if ( l < end && a[l] < a[l+1])
l++; // 左右两孩子中选择较大者,即m_heap[l+1]
if (tmp >= a[l])
break; // 调整结束
else { // 交换值
a[c] = a[l];
a[l]= tmp;
}
}
}
/*
* 堆排序(从小到大)
*
* 参数说明:
* a -- 待排序的数组
* n -- 数组的长度
*/
public static void heapSortAsc(int[] a, int n) {
int i,tmp;
// 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。
for (i = n / 2 - 1; i >= 0; i--)
maxHeapDown(a, i, n-1);
// 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
for (i = n - 1; i > 0; i--) {
// 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
tmp = a[0];
a[0] = a[i];
a[i] = tmp;
// 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
// 即,保证a[i-1]是a[0...i-1]中的最大值。
maxHeapDown(a, 0, i-1);
}
}
/*
* (最小)堆的向下调整算法
*
* 注: 数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
* 其中,N为数组下标索引值,如数组中第1个数对应的N为0。
*
* 参数说明:
* a -- 待排序的数组
* start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
* end -- 截至范围(一般为数组中最后一个元素的索引)
*/
public static void minHeapDown(int[] a, int start, int end) {
int c = start; // 当前(current)节点的位置
int l = 2*c + 1; // 左(left)孩子的位置
int tmp = a[c]; // 当前(current)节点的大小
for (; l <= end; c=l,l=2*l+1) {
// "l"是左孩子,"l+1"是右孩子
if ( l < end && a[l] > a[l+1])
l++; // 左右两孩子中选择较小者
if (tmp <= a[l])
break; // 调整结束
else { // 交换值
a[c] = a[l];
a[l]= tmp;
}
}
}
/*
* 堆排序(从大到小)
*
* 参数说明:
* a -- 待排序的数组
* n -- 数组的长度
*/
public static void heapSortDesc(int[] a, int n) {
int i,tmp;
// 从(n/2-1) --> 0逐次遍历每。遍历之后,得到的数组实际上是一个最小堆。
for (i = n / 2 - 1; i >= 0; i--)
minHeapDown(a, i, n-1);
// 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
for (i = n - 1; i > 0; i--) {
// 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最小的。
tmp = a[0];
a[0] = a[i];
a[i] = tmp;
// 调整a[0...i-1],使得a[0...i-1]仍然是一个最小堆。
// 即,保证a[i-1]是a[0...i-1]中的最小值。
minHeapDown(a, 0, i-1);
}
}
public static void main(String[] args) {
int i;
int a[] = {20,30,90,40,70,110,60,10,100,50,80};
System.out.printf("before sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
heapSortAsc(a, a.length); // 升序排列
//heapSortDesc(a, a.length); // 降序排列
System.out.printf("after sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
}
}
链接:原文
桶排序
public class BucketSort {
/*
* 桶排序
*
* 参数说明:
* a -- 待排序数组
* max -- 数组a中最大值的范围
*/
public static void bucketSort(int[] a, int max) {
int[] buckets;
if (a==null || max<1)
return ;
// 创建一个容量为max的数组buckets,并且将buckets中的所有数据都初始化为0。
buckets = new int[max];
// 1. 计数
for(int i = 0; i < a.length; i++)
buckets[a[i]]++;
// 2. 排序
for (int i = 0, j = 0; i < max; i++) {
while( (buckets[i]--) >0 ) {
a[j++] = i;
}
}
buckets = null;
}
public static void main(String[] args) {
int i;
int a[] = {8,2,3,4,3,6,6,3,9};
System.out.printf("before sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
bucketSort(a, 10); // 桶排序
System.out.printf("after sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
}
}
基数排序
public class RadixSort {
private static int getMax(int[] a) {
int max;
max = a[0];
for (int i = 1; i < a.length; i++)
if (a[i] > max)
max = a[i];
return max;
}
/*
* 对数组按照"某个位数"进行排序(桶排序)
*
* 参数说明:
* a -- 数组
* exp -- 指数。对数组a按照该指数进行排序。
*
* 例如,对于数组a={50, 3, 542, 745, 2014, 154, 63, 616};
* (01) 当exp=1表示按照"个位"对数组a进行排序
* (02) 当exp=10表示按照"十位"对数组a进行排序
* (03) 当exp=100表示按照"百位"对数组a进行排序
* ...
*/
private static void countSort(int[] a, int exp) {
//int output[a.length]; // 存储"被排序数据"的临时数组
int[] output = new int[a.length]; // 存储"被排序数据"的临时数组
int[] buckets = new int[10];
// 将数据出现的次数存储在buckets[]中
for (int i = 0; i < a.length; i++)
buckets[ (a[i]/exp)%10 ]++;
// 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
for (int i = 1; i < 10; i++)
buckets[i] += buckets[i - 1];
// 将数据存储到临时数组output[]中
for (int i = a.length - 1; i >= 0; i--) {
output[buckets[ (a[i]/exp)%10 ] - 1] = a[i];
buckets[ (a[i]/exp)%10 ]--;
}
// 将排序好的数据赋值给a[]
for (int i = 0; i < a.length; i++)
a[i] = output[i];
output = null;
buckets = null;
}
/*
* 基数排序
*
* 参数说明:
* a -- 数组
*/
public static void radixSort(int[] a) {
int exp; // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
int max = getMax(a); // 数组a中的最大值
// 从个位开始,对数组a按"指数"进行排序
for (exp = 1; max/exp > 0; exp *= 10)
countSort(a, exp);
}
public static void main(String[] args) {
int i;
int a[] = {53, 3, 542, 748, 14, 214, 154, 63, 616};
System.out.printf("before sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
radixSort(a); // 基数排序
System.out.printf("after sort:");
for (i=0; i<a.length; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");
}
}
|