常见的排序算法分为四类:插入排序(直接插入,希尔),选择排序(选择,堆),交换排序(冒泡,快速),归并排序
1.直接插入排序:
**public static void insertsort(int[] nums){ for(int i=1; i<nums.length;i++){ int key=nums[i]; int j=i-1; for(;j>=0&&nums[j]>key;j--){ nums[j+1]=nums[j]; } nums[j+1]=key; } }
时间复杂度
| 最好 | 平均 | 空间复杂度 稳定
| O(n) | O(n^2)| O(1)
2.希尔排序
排序思想:先选定一个整数,把待排序文件中所有记录分成组,所有距离相同的记录分在同一组内,并对每一组内的记录进行排序。然后,重复上述分组和排序的工作。当到达n=1时,所有记录在统一组内排好序。
public static void shellsort(int[] nums){
int gap=nums.length;
while(gap>1){
insertGap(nums,gap);
gap=gap/3+1;
}
insertGap(nums,1);
}
private static void insertGap(int[] nums, int gap) {
for(int i=1;i<nums.length;i++){
int key=nums[i];
int j=i-gap;
for(;j>=0&&nums[j]>key;j-=gap){
nums[j+gap]=nums[j];
}
nums[j+gap]=key;
}
}
时间复杂度
| 最好 | 平均 |空间复杂度
|-O(n)-|-O(n^1.3)-|O(1)
稳定性:不稳定
3.选择排序
排序思想:每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元
素排完 。
public static void selectSort(int[] nums){
for(int i=0;i<nums.length;i++){
int min=i;
for(int j=i+1;j<nums.length;j++){
if(nums[min]>nums[j]){
min=j;
}
swap(nums,min,i);
}
}
}
private static void swap(int[] nums, int min, int i) {
int t=nums[min];
nums[min]=nums[i];
nums[i]=t;
}
时间复杂度O(n^2),空间复杂度:O(1),数据不稳定。
4.堆排序
排序思想:基本原理也是选择排序,只是不在使用遍历的方式查找无序区间的最大的数,而是通过堆来选择无序区间的最大的数。
注意: 排升序要建大堆;排降序要建小堆。
public static void heapSort(int[] nums){
createheap(nums);
for(int i=0;i<nums.length-1;i++){
swap(nums,0,nums.length-i-1);
shiftDown(nums,nums.length-1-i,0);
}
}
private static void shiftDown(int[] nums, int size, int i) {
int left=i*2+1;
while (left < size) {
int right=left+1;
int max=left;
if(right<size&&nums[left]<nums[right]){
max=right;
}
if(nums[max]<nums[i]){
break;
}
swap(nums,max,i);
i=max;
left=i*2+1;
}
}
private static void createheap(int[] nums) {
for(int i=(nums.length-1)/2;i>=0;i--){
shiftDown(nums,nums.length,i);
}
}
时间复杂度:O(n*logn) ,空间复杂度:O(1),数据不稳定。
5.冒泡排序
排序思想:在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序
public static void bubbleSort(int[] nums){
for(int i=0;i<nums.length-1;i++){
for(int j=0;j<nums.length-i-1;j++){
if(nums[j+1]<nums[j]){
swap(nums,j,j+1);
}
}
}
}
时间复杂度:O(n^2),空间复杂度:O(1),数据稳定
6.快速排序
排序思想:
- 从待排序区间选择一个数,作为基准值(pivot);
- Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的
(可以包含相等的)放到基准值的右边; - 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 ==1,代表已经有序,或者小区
间的长度 == 0= 0,代表没有数据。
public static void QuickSort(int[] array){
quickSortInter(array,0,array.length-1);
}
private static void quickSortInter(int[] array, int left, int right) {
if(left>=right){
return;
}
int pivotIndex=partition(array,left,right);
quickSortInter(array,left,pivotIndex-1);
quickSortInter(array,pivotIndex+1,right);
}
private static int partition(int[] array, int left, int right) {
int i=left;
int j=right;
int pivot=array[left];
while(i<j){
while(i<j&&array[j]>pivot){
j--;
}
while(i<j&&array[i]<=pivot){
i++;
}
swap(array,i,j);
}
swap(array,left,i);
return i;
}
时间复杂度:O(n*logn) 空间复杂度:O(logn),数据不稳定
7.归并排序
排序思想:归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and
Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使
子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
public static void mergeSort(int[] array){
mergeSortIntel(array,0,array.length);
}
private static void mergeSortIntel(int[] array, int low, int high) {
if(low>=high-1){
return;
}
int mid=(low+high)/2;
mergeSortIntel(array,low,mid);
mergeSortIntel(array,mid,high);
merge(array,low,mid,high);
}
private static void merge(int[] array, int low, int mid, int high) {
int length=high-low;
int[] a=new int[length];
int left=low;
int mid2=mid;
int k=0;
while(left<mid&&mid2<high){
if(array[left]<=array[mid2]){
a[k++]=array[left++];
}
else{
a[k++]=array[mid2++];
}
}
while(left<mid){
a[k++]=array[left++];
}
while(mid2<high){
a[k++]=array[mid2++];
}
for(int i=0;i<length;i++){
array[low+i]=a[i];
}
}
时间复杂度:O(n*logn),空间复杂度:O(n),数据稳定