1.冒泡排序
思想:同过比较相邻两个的值,一趟排序后将最大值max放在最右端,再经过一趟排序将次大值排在max左边,依此数次排序后得到一个有序数组。
算法平均复杂度:O(n2)。
是否稳定:稳定。
public class BubbleSort { public static void sort(int []arr){ for(int i=0;i<arr.length-1;i++){//外部循环控制排序趟数 for(int j = 0;j<arr.length-1-i;j++){//内部循环决定每一趟比较次数 if(arr[j]>arr[j+1]){ //升序 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } } public static void main(String[] args) { int[] arr = {8,2,1,6,7,3,4,0}; sort(arr); System.out.println(Arrays.toString(arr)); } }
2.快速排序
思想:采用分治的思想。首先选取一个基准元素,经过一趟排序之后,将比基准元素小的放在其左边,比基准元素大的放在其右边,将数组分成两部分。对于左边的部分,再选取一个基准元素将棋再分为两部分,右边同样如此。如此,多躺排序之后得到一个有序数列。
算法平均复杂度:O(NlogN)
是否稳定:不稳定
public class QuickSort { public static void main(String[] args) { int a[]={1,4,3,8,5,9,6}; QuickSort(a, 0, 6); for (int i : a) { System.out.println(i); } } public static void QuickSort(int a[],int p,int r){ if(p<r){ int q = Partition(a, p, r); QuickSort(a, p, q-1); QuickSort(a, q+1, r); } } public static int Partition(int a[],int p,int r){ int i = p,j =r+1; int x = a[p]; while(true){ while(a[++i]<x &&i<r ); while(a[--j]>x); if(i>=j) break; Swap(a,i,j); } a[p] = a[j]; a[j] = x; return j; } public static void Swap(int a[],int i, int j){ int temp; temp = a[i]; a[i] = a[j]; a[j] = temp; } }
3.堆排序
思想:将数组元素构造成大顶推或小顶堆,然后将堆定元素与堆尾元素交换,再重构大顶堆,将堆顶元素与堆尾交换。重复数次后形成有序数列。
算法平均复杂度:O(nlogn)
是否稳定:不稳定。
public class Heapsort { public static void main(String []args){ int []arr = {0,8,7,6,9,10,3,2,1}; sort(arr); System.out.println(Arrays.toString(arr)); } public static void sort(int []arr){ //1.构建大顶堆 for(int i=arr.length/2-1;i>=0;i--){ //从第一个非叶子结点从下至上,从右至左调整结构 adjustHeap(arr,i,arr.length); } //2.调整堆结构+交换堆顶元素与末尾元素 for(int j=arr.length-1;j>0;j--){ swap(arr,0,j);//将堆顶元素与末尾元素进行交换 adjustHeap(arr,0,j);//重新对堆进行调整 } } public static void adjustHeap(int []arr,int i,int length){ int temp = arr[i];//先取出当前元素i for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始 if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点 k++; } if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换) arr[i] = arr[k]; i = k; }else{ break; } arr[i] = temp;//将temp值放到最终的位置 } }
//从最后一个父节点出发,找到子节点,比较子节点大小,将其与子节点大的进行交换。依次重复,直到构建成大顶堆后完毕。 public static void swap(int []arr,int a ,int b){ int temp=arr[a]; arr[a] = arr[b]; arr[b] = temp; } }
4.插入排序
思想:从待排序的序列中选择一个元素,将其插入到已排序好的元素序列中 ,重复上述步骤直到待排序序列中没有元素为止。
复杂度:O(n2)
是否稳定:稳定
public class InsertSort {
//直接插入排序
//a为待排序数组,n代表数组长度
public void insertSort(int a[],int n){
for(int i = 1;i<n;i++){
for(int j = 0;j<i;j++){
if(a[j]>a[i]){//升序排序
//交换 a[j] a[i]
a[j] = a[i] +a[j];
a[i] = a[j] - a[i];
a[j] = a[j] - a[i];
}
}
}
}
public static void main(String[] args) {
InsertSort insertSort = new InsertSort();
int a[] = {3,4,1,2,6,7,9,8};
insertSort.insertSort(a,a.length);
System.out.println(Arrays.toString(a));
}
}
5.选择排序
思想:在未排序的序列中选择最小的元素,放在已排序的队列首部,然后再从未排序的序列中选择最小的放到以排序的队列中去。以此重复,知道未排序的序列没有元素为止。
平均复杂度:O(n2)
是否稳定:不稳定
function selectionSort(arr) { var len = arr.length; var minIndex, temp; for (var i = 0; i < len - 1; i++) { minIndex = i; //每次都从已排序序列的末尾后一位开始 for (var j = i + 1; j < len; j++) { if (arr[j] < arr[minIndex]) { //寻找最小的数 minIndex = j; //将最小数的索引保存 } } //放到已排序序列的末尾(即交换),该操作很有可能把稳定性打乱,所以选择排序是不稳定的排序算法 temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } return arr; }
6.归并排序
思想:归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
public class MergeSort { public static void main(String []args){ int []arr = {9,8,7,6,5,4,3,2,1}; sort(arr); System.out.println(Arrays.toString(arr)); } public static void sort(int []arr){ int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间 sort(arr,0,arr.length-1,temp); } private static void sort(int[] arr,int left,int right,int []temp){ if(left<right){ int mid = (left+right)/2; sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序 sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序 merge(arr,left,mid,right,temp);//将两个有序子数组合并操作 } } private static void merge(int[] arr,int left,int mid,int right,int[] temp){ int i = left;//左序列指针 int j = mid+1;//右序列指针 int t = 0;//临时数组指针 while (i<=mid && j<=right){ if(arr[i]<=arr[j]){ temp[t++] = arr[i++]; }else { temp[t++] = arr[j++]; } } while(i<=mid){//将左边剩余元素填充进temp中 temp[t++] = arr[i++]; } while(j<=right){//将右序列剩余元素填充进temp中 temp[t++] = arr[j++]; } t = 0; //将temp中的元素全部拷贝到原数组中 while(left <= right){ arr[left++] = temp[t++]; } } }
总结