排序就是将一组对象按照某种逻辑顺序重新排列的过程。十种排序的算法一般分为两大类:
算法分类
算法复杂度
相关术语
时间复杂度:只算法需要消耗的时间资源,一般来说,计算机的算法是问题规模n的函数f(n),算法的时间复杂度记作 T(n) = O(f(n)),常见的时间复杂度有:常数阶O(1),对数阶O(logn),线性阶O(n),线性对数阶O(nlogn),平方阶O(n2).....K次方阶O(nk),指数阶O(2^n).随着问题n的不断增大,上述时间复杂度不断的增大,算法的执行效率越低。
空间复杂度: 指算法需要消耗的空间资源,就是运行时占的算机的内存。
稳定:如果在排序前,r[i]=r[j] 且r[i]在r[j]之前,在排序后,r[i]仍在r[j]之前。
不稳定: 如果在排序前,r[i]=r[j] 且r[i]在r[j]之前,在排序后,r[i]在r[j]之后。
冒泡排序(英语:Bubble Sort)又称为泡式排序,是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
1.1 算法运作过程
1.2 动图展示
1.3 伪代码的实现
function bubble_sort (array, length) {
var i, j;
for(i from 0 to length-1){
for(j from 0 to length-1-i){
if (array[j] > array[j+1])
swap(array[j], array[j+1])
}
}
}
1.4 java代码实现
public static int[] bubbleSort(int[] array){
int temp;
for (int i = 0; i < array.length-1 ; i++) {
for (int j = 0; j < array.length-1-i ; j++) {
// 进行比较,完成数的交换
if(array[j]> array[j+1]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
选择排序是一种简单直观的排序算法。主要优点是与数据的移动有关,如果某个元素在正确的位置上就不会被移动。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。
2.1 算法运作过程
2.2 动图展示
2.3 java代码实现
public static void selectSort(Comparable[] array){
for (int i = 0; i < array.length-1; i++) {
int min = i;
// 1.寻找最小元素
for (int j = i+1; j < array.length ; j++) {
if(less(array[j],array[min])) min = j;
}
// 2.将最小元素放到已排序的队尾
exch(array,i,min);
i++;
}
}
//=====================辅助方法============================
// 元素的交换
private static void exch(Comparable[] array, int i, int min) {
Object temp = array[i];
array[i] = array[min];
array[min] = (Comparable) temp;
}
// 元素的比较
private static boolean less( Comparable i, Comparable j) {
return i.compareTo(j) < 0;
}
是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
3.1 算法运作过程
3.2 动图展示
3.3 java代码实现
public static void insertSort(Comparable[] array){
for (int i = 0; i < array.length ; i++) {
for (int j = i; j>0 && less(array[j],array[j-1]); j++) {
exch(array,j,j-1);
}
}
}
//=================辅助方法============================
// 元素的交换
private static void exch(Comparable[] array, int i, int min) {
Object temp = array[i];
array[i] = array[min];
array[min] = (Comparable) temp;
}
// 元素的比较
private static boolean less( Comparable i, Comparable j) {
return i.compareTo(j) < 0;
}
也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
4.1 基于插入排序的两种改进方法
4.2 动图展示
4.3 java代码实现
public static void shellSort(Comparable[] array){
int n = array.length;
int h = 1;
while(h < n/4) h = 4*h+1;
while(h >=1){
for (int i = h; i < n ; i++) {
for (int j = i; j >= h && less(array[j],array[j-h]) ; j-=h) {
exch(array,j,j-h);
}
}
// 步长为4
h /= 4;
}
}
归并排序是创建在归并操作上的一种有效的排序算法,效率为 O(n\log n)(大O符号)该算法是采用分治法的一个非常典型的应用,且各层分治递归可以同时进行。
5.1 算法运作过程
5.2 动图展示
5.3 java代码实现
// 归并排序的实现,使用的递归
public static void mergeSort(Comparable[] array){
Comparable[] aux = new Comparable[array.length];
mergeSort(array,aux,0,array.length-1);
}
// 归并排序的实现
public static void mergeSort(Comparable[] array,Comparable[] tempArr,int lo,int hi){
if(lo >= hi) return;
int mid = (lo+hi)/2;
mergeSort(array,tempArr,lo,mid);
mergeSort(array,tempArr,mid+1,hi);
merge(array,tempArr,lo,hi);
}
//====================================辅助方法================================
// 原地归并的抽象方法
private static void merge(Comparable[] array, Comparable[] tempArr, int lo, int hi) {
// 将 array[lo....mid] 和array[mid+1....hi]归并
int mid = (lo+hi)/2;
// 将array[lo..hi] 复制到tempArr[lo..hi]中
for (int i = 0; i < array.length ; i++) {
tempArr[i] = array[i];
}
// 归并回到原数组array[lo....hi]
int i = lo,j = mid+1;
for (int k = lo; k <= hi ; k++) {
if(i > mid) array[k] = tempArr[j++];
else if(j > hi) array[k] = tempArr[i++];
else if(less(array[j],array[i])) array[k] = tempArr[j++];
else array[k] = tempArr[i++];
}
}
// 元素的交换
private static void exch(Comparable[] array, int i, int min) {
Object temp = array[i];
array[i] = array[min];
array[min] = (Comparable) temp;
}
// 元素的比较
private static boolean less( Comparable i, Comparable j) {
return i.compareTo(j) < 0;
}
又称划分交换排序,简称快排,一种排序算法。在平均状况下,排序n个项目要 O(n\log n)次比较。在最坏状况下则需要 O(n^2)次比较,但这种状况并不常见。
6.1 算法运作过程
6.2 动图展示
6.3 伪代码的实现
function quicksort(q)
{
var list less, pivotList, greater
if length(q) ≤ 1
return q
else
{
select a pivot value pivot from q
for each x in q except the pivot element
{
if x < pivot then add x to less
if x ≥ pivot then add x to greater
}
add pivot to pivotList
return concatenate(quicksort(less), pivotList, quicksort(greater))
}
}
6.4 java代码实现
public static void sort(Comparable[] array, int lo, int length) {
if(length <= lo) return;
// 找出基准值的索引
int j = partition(array,lo,length);
// 使用递归前部部分排序
sort(array,lo,j-1);
// 后半部分排序
sort(array,j+1,length);
}
// 找出基准值的方法
private static int partition(Comparable[] array, int lo, int length) {
int i = lo,j = length+1;
Comparable temp = array[lo];
// 实现左右的扫描找出这个数
while(true) {
while(less(array[++i],temp)) if(i == length) break;
while(less(temp,array[--j])) if(j == lo) break;
if(i >= j) break;
// 将左边大于中间值的与右边小于中间值进行交换
exch(array,i,j);
}
// 将j放入到相应的位置
exch(array,lo,j);
return j;
}
// 元素的交换
private static void exch(Comparable[] array, int i, int min) {
Object temp = array[i];
array[i] = array[min];
array[min] = (Comparable) temp;
}
堆排序是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
7.1 算法运作过程
7.2 动图展示
7.3 java代码实现
public static void sort(Comparable[] array){
int n = array.length;
// 实现堆化
for (int k =n/2; k > 0 ; k--) {
sink(array,k,n);
}
int k = n;
// 实现排序
while (k > 1){
exch(array,1,k--);
sink(array,1,k);
}
}
// 元素的下沉
private static void sink(Comparable[] array, int k, int n) {
while(2*k <= n){
int j = 2*k;
if(j<n && less(array,j,j+1)) j++;
if(!less(array,k,j)) break;
exch(array,k,j);
k = j;
}
}
private static void exch(Comparable[] array, int k, int j) {
Object temp = array[k-1];
array[k-1] = array[j-1];
array[j-1] = (Comparable) temp;
}
private static boolean less(Comparable[] array, int i, int j) {
return array[i-1].compareTo(array[j-1]) < 0 ;
}
计数排序是一种稳定的线性时间排序算法。计数排序使用一个额外的数组 C ,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组 C 来将A中的元素排到正确的位置。
8.1 算法运作过程
8.2 动图展示
8.3 java代码实现
public static int[] countingSort(int[] A) {
int[] B = new int[A.length];
// 假设A中的数据a‘有,0<=a‘ && a‘ < k并且k=100
int k = 100;
countingSort(A, B, k);
return B;
}
private static void countingSort(int[] A, int[] B, int k) {
int[] C = new int[k];
// 计数
for (int j = 0; j < A.length; j++) {
int a = A[j];
C[a] += 1;
}
// 求计数和
for (int i = 1; i < k; i++) {
C[i] = C[i] + C[i - 1];
}
// 整理
for (int j = A.length - 1; j >= 0; j--) {
int a = A[j];
B[C[a] - 1] = a;
C[a] -= 1;
}
}
桶排序(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。桶排序是鸽巢排序的一种归纳结果。当要被排序的数组内的数值是均匀分配的时候,桶排序使用线性时间O(n)。但桶排序并不是比较排序,他不受到 O(n\log n)下限的影响。
9.1 算法运作过程
9.2 动图展示
9.3 java代码实现
public void bucketSort(int[] arr) {
int max = arr[0], min = arr[0];
for (int a : arr) {
if (max < a)
max = a;
if (min > a)
min = a;
}
// 该值根据实际情况选择
int bucketNum = max / 10 - min / 10 + 1;
List buckList = new ArrayList<List<Integer>>();
// 创建桶
for (int i = 1; i <= bucketNum; i++) {
buckList.add(new ArrayList<Integer>());
}
// 向桶内装入数据
for (int i = 0; i < arr.length; i++) {
int index = indexFor(arr[i], min, 10);
((ArrayList<Integer>) buckList.get(index)).add(arr[i]);
}
ArrayList<Integer> bucket = null;
int index = 0;
for (int i = 0; i < bucketNum; i++) {
bucket = (ArrayList<Integer>) buckList.get(i);
insertSort(bucket);
for (int k : bucket) {
arr[index++] = k;
}
}
}
// 把桶內元素插入排序
private void insertSort(List<Integer> bucket) {
for (int i = 1; i < bucket.size(); i++) {
int temp = bucket.get(i);
int j = i - 1;
for (; j >= 0 && bucket.get(j) > temp; j--) {
bucket.set(j + 1, bucket.get(j));
}
bucket.set(j + 1, temp);
}
}
private int indexFor(int a, int min, int step) {
return (a - min) / step;
}
是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
10.1 算法运作过程
10.2 动图展示
10.3 java代码实现
public void radixSort(int[] array,int d ) {
int n=1; //代表位数对应的数:1,10,100...
int k=0;//保存每一位排序后的结果用于下一位的排序输入
int length=array.length;
int[][] bucket=new int[10][length];//排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
int[] order=new int[length];//用于保存每个桶里有多少个数字
while(n<d)
{
for(int num:array) //将数组array里的每个数字放在相应的桶里
{
int digit=(num/n)%10;
bucket[digit][order[digit]]=num;
order[digit]++;
}
for(int i=0;i<length;i++)//将前一个循环生成的桶里的数据覆盖到原数组中用于保存这一位的排序结果
{
if(order[i]!=0)//这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中
{
for(int j=0;j<order[i];j++)
{
array[k]=bucket[i][j];
k++;
}
}
order[i]=0;//将桶里计数器置0,用于下一次位排序
}
n*=10;
k=0;//将k置0,用于下一轮保存位排序结果
}
}
参考博客
注: 以上的部分动图和内容摘抄自下面两个博客,如若侵权,可联系删除。
参考资料
原文:https://www.cnblogs.com/chentang/p/12593313.html