排序算法大全
一、冒泡排序
思路:每两个相邻的元素进行比较,直至最大(最小)的元素沉到底下,经过多轮之后这样的操作,从而使得完成排序。
特点:稳定
平均时间复杂度:O(n2)
最佳时间复杂度:O(n)
最坏时间复杂度:O(n2)
空间复杂度:O(1)
动画演示:
代码如下:
public class BubbleSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
bubbleSort(arr);
// 遍历数组
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+" ");
}
}
/**
* 冒泡排序
* @param arr 数组
*/
public static void bubbleSort(int[] arr) {
int len=arr.length;
for(int i=0;i<len-1;i++) {
for(int j=0;j<len-i-1;j++) {
if(arr[j]>arr[j+1]) {
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}//end if
}// end for
}// end for
}// end method
}
二、选择排序
思路:每次从位置 i 之后选择一个最小的数(升序)和 i 进行交换,经过n轮之后数组得到有序。
注意:选择排序是不稳定的排序,举个例子:数组 6、7、6、2、8,在对其进行第一遍循环的时候,会将第一个位置的6与后面的2进行交换。此时,就已经将两个6的相对前后位置改变了。因此选择排序不是稳定性排序算法。
平均时间复杂度:O(n2)
最快时间复杂度:O(n2)
最坏时间复杂度:O(n2)
空间复杂度:O(1)
动画演示:
代码如下:
public class SelectionSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
selectionSort(arr);
// 遍历数组
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+" ");
}
}
public static void selectionSort(int[] arr) {
int len=arr.length;
for(int i=0;i<len-1;i++) {
int k=i;
for(int j=i+1;j<len;j++) {
if(arr[k]>arr[j]) {
k=j;
}// end if
}//end for
int temp=arr[i];
arr[i]=arr[k];
arr[k]=temp;
}
}
}
三、插入排序
思路:首先找到一个最小的元素(升序)放到起始位置。然后从剩余元素中找到下一个最小的数放到已经起始位置的后面,之后继续从剩余元素中找下一个最小的数放到上一个数的后面。循环n次这样的操作,从而达到数组有序。
特点:稳定
平均时间复杂度:O(n2)
最快时间复杂度:O(n)
最坏时间复杂度:O(n2)
空间复杂度:O(1)
动画演示:
代码如下:
public class InsertionSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
insertionSort(arr);
// 遍历数组
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+" ");
}
}
/**
* 插入排序
* @param arr 要排序的数组
*/
public static void insertionSort(int[] arr) {
int len=arr.length;
for(int i=0;i<len-1;i++) {
int cur=arr[i+1];
int pre=i;
while(pre>=0 && cur<arr[pre]) {
arr[pre+1]=arr[pre];
pre--;
}//end while
arr[pre+1]=cur;
}//end for
}
}
四、希尔排序
思路:希尔排序其实是插入排序的一种改进方法,将一组数据分成了若干组,然后组内进行插入排序,然后继续细分,细分到每一个元素一组,这个时候数组已经基本有序,再进行插入排序就只需要微调数组的顺序。
特点:不稳定
平均时间复杂度:O(nlog2n)
最佳时间复杂度:O(nlog2n)
最坏时间复杂度:O(nlog2n)
空间复杂度:O(1)
动画演示:
代码如下:
public class ShellSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
shellSort(arr);
// 遍历数组
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+" ");
}
}
/**
* 希尔排序
* @param arr 要排序的数组
*/
public static void shellSort(int[] arr) {
int len=arr.length;
int group=len/2;
while(group>0) {
for(int i=group;i<len;i++) {
int cur=arr[i];
int preIndex=i-group;
while(preIndex>=0 && cur<arr[preIndex]) {
arr[preIndex+group]=arr[preIndex];
preIndex=preIndex-group;
}//end while
arr[preIndex+group]=cur;
}//end for
group/=2;
}//end while
}
}
五、归并排序
思路:把数组平均分成左右两份,然后再分别对左右两边进行平分,循环这样的操作,直至左右两边都成一个元素。最后一层一层往上归并直至完成排序。
特点:稳定
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)
空间复杂度:O(n)
图片演示:
动画演示:
代码如下:
public class MergeSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
int[] resultArr=new int[arr.length];
resultArr=mergeSort(arr);
// 遍历数组
for(int i=0;i<resultArr.length;i++) {
System.out.print(resultArr[i]+" ");
}
}
public static int[] mergeSort(int[] arr){
if(arr.length<2)
return arr;
int len=arr.length;
int mid=len/2;
int[] left=Arrays.copyOfRange(arr, 0, mid);
int[] right=Arrays.copyOfRange(arr, mid, len);
int[] leftArr=mergeSort(left);
int[] rightArr=mergeSort(right);
return merge(leftArr,rightArr);
}
private static int[] merge(int[] leftArr, int[] rightArr) {
// TODO Auto-generated method stub
int leftLen=leftArr.length;
int rightLen=rightArr.length;
int[] resultArr=new int[leftLen+rightLen];
int i=0,j=0,k=0;
while(i<leftLen && j<rightLen) {
if(leftArr[i] < rightArr[j]) {
resultArr[k++]=leftArr[i];
i++;
}else{
resultArr[k++]=rightArr[j];
j++;
}
}
while(i<leftLen) resultArr[k++]=leftArr[i++];
while(j<rightLen) resultArr[k++]=leftArr[j++];
return resultArr;
}
}
六、快速排序
思路:从序列中找一个基准值(这里令序列第一个数为基准值),定义左右两个指针,右指针从右边开始寻找第一个小于基准值的数,左指针从左边开始寻找第一个大于基准值的数,然后将左右指针对应的数进行交换,当左右两指针相遇时,把基准值和左(或右)指针进行交换,然后再将左右两边分别进行这样的操作,最终使得数组有序。
特点:不稳定
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(nlogn)
最差时间复杂度:O(n2)
图片演示:
代码如下:
public class QuickSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
quick_sort(arr,0,arr.length-1);
System.out.print(Arrays.toString(arr));
}
public static void quick_sort(int[] arr,int left,int right) {
if(left>right)
return;
int baseValue=arr[left];
int l=left;
int r=right;
while(l!=r) {
// 注意:当设置最左边元素为基准值时,必须从右边开始找。
// 因为最后i、j 停留的位置的值肯定是要 小于 基准值 的 此时交换索引 j 和最左边元素(基准值) 符合将小于基准值的值放到基准值的左边这一条件
while(arr[r]>=baseValue && l<r) r--; // 找到第一个小于基准值的
while(arr[l]<=baseValue && l<r) l++; // 找到第一个大于基准值的
if(l<r) {
int temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
}
}
arr[left]=arr[l];
arr[l]=baseValue;
quick_sort(arr,left,l-1);
quick_sort(arr,l+1,right);
}
}
七、堆排序
思路:首先将数组建立成大顶堆,然后将大顶堆的第一个元素和最后一个元素交换,最后一个元素就固定了,不再参与排序。继续调整堆,使得堆再一次变成大顶堆,将这一次大顶堆的第一个元素和这一次大顶堆的最后一个元素交换。通过这样循环n次达成数组有序。
特点:不稳定
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(nlogn)
最坏时间复杂度:O(nlogn)
动画演示:
代码如下:
public class HeapSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
heapSort(arr);
// 遍历数组
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+" ");
}
}
public static void heapSort(int[] arr) {
int len=arr.length;
int n=len;
buildHeap(arr);
for(int i=0;i<len;i++) {
//交换
swap(arr, 0, n-1);
n--;
adjustHeap(arr, 0, n);
}
}
/**
* 建立大顶堆
* @param arr 数组
*/
private static void buildHeap(int[] arr) {
int len=arr.length;
for(int i=len/2-1;i>=0;i--) {
adjustHeap(arr,i,len);
}//end for
}
/**
* 调整堆
* @param arr 数组
* @param i 位置i
* @param len 数组未排序的元素长度
*/
private static void adjustHeap(int[] arr, int i,int len) {
int maxIndex=i;
if(2*i+1 < len && arr[2*i+1]>arr[maxIndex]) {
maxIndex=2*i+1;
}//end if
if(2*i+2 < len && arr[2*i+2]>arr[maxIndex]) {
maxIndex=2*i+2;
}
//交换
if(i!=maxIndex) {
swap(arr,i,maxIndex);
adjustHeap(arr,maxIndex,len);
}
}
/**
* 交换位置
* @param arr 数组
* @param i 位置i
* @param maxIndex 位置maxIndex
*/
private static void swap(int[] arr, int i, int maxIndex) {
int temp=arr[i];
arr[i]=arr[maxIndex];
arr[maxIndex]=temp;
}
}
八、计数排序
思路:将数组A中的元素作为一个索引存入另一个数组B中,最后遍历数组B,输出数组B元素不为0的索引。
特点:稳定
平均时间复杂度:O(n+k)
最佳时间复杂度:O(n+k)
最坏时间复杂度:O(n+k)
动画演示:
代码如下:
public class CountingSort {
public static void main(String[] args) {
int[] arr= {10,9,8,7,6,5,4,3,2,1};
countingSort(arr);
}
/**
* 计数排序
* @param arr 数组
*/
private static void countingSort(int[] arr) {
int len=arr.length;
int max=arr[0],min=arr[0];
for(int i=1;i<len;i++) {
if(max<arr[i]) {
max=arr[i];
}//end if
if(min>arr[i]) {
min=arr[i];
}//end if
}//end for
int[] bucket=new int[max-min+1];
Arrays.fill(bucket, 0);
for(int i=0;i<len;i++) {
bucket[arr[i]-min]++;
}
for(int i=0;i<max-min+1;) {
if(bucket[i]!=0) {
System.out.print(i+min+" ");
bucket[i]--;
}else {
i++;
}
}
}
}
九、桶排序
内容后期更新
十、基数排序
内容后期更新