一、直接插入排序
原理:整个区间被分为:有序区间和无序区间;每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入。
当待排序区间元素比较少或者接近有序时,直接插入的效率比较高。
private static void insertSort(int[] array){
for(int bound=1;bound<array.length;bound++){
int temp=array[bound];
int cur=bound-1;
for(;cur>=0;cur--){
if(array[cur]>temp){
array[cur+1]=array[cur];
}
else{
break;
}
}
array[cur+1]=temp;
}
}
时间复杂度:最好:数据有序O(n);最坏:数据逆序O(n^2);平均 O(n^2)。
空间复杂度:O(1)
稳定性:稳定排序。
二、希尔排序
原理:将待排序区间分成若干子区间,分别进行直接插入排序。经过上述粗略调整,整个序列中的记录基本有序,最后一次再对全部记录进行直接插入排序。
private static void shellSort(int[] array){
int gap=array.length/2;
while(gap>1){
shellSortHelper(array,gap);
gap/=2;
}
shellSortHelper(array,1);
}
private static void shellSortHelper(int[] array,int gap){
for(int bound=gap;bound<array.length;bound++){
int temp=array[bound];
int cur=bound-gap;
for(;cur>=0;cur-=gap){
if(array[cur]>temp){
array[cur+gap]=array[cur];
}
else{
break;
}
}
array[cur+gap]=temp;
}
}
时间复杂度:O(n^1.3)
空间复杂度:O(1)
稳定性:不稳定排序
三、冒泡排序
原理:反复扫描待排序记录序列,依次比较相邻两个元素的大小,若是逆序就交换位置。
private static void bubbleSort(int[] array){
for(int i=0;i<array.length;i++){
for(int j=0;j<array.length-i-1;j++){
//如果这里写成>=就无法保证稳定性
if(array[j]>array[j+1]){
int temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
}else{
continue;
}
}
}
}
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:稳定排序
四、快速排序
原理:取一个基准值K,将左侧区间整理成小于等于基准值,右侧区间整理成大于等于基准值。
取最后一个元素为基准值,从左往右找,找到一个大于基准值的元素;从右往左找,找到一个小于基准值的元素,交换两个元素;重复刚才的过程,直到左右下标重合。重合后,交换基准值和重合位置元素。
private static void quickSort(int[] array,int beg,int end){
if(beg>=end){
return;
}
int index=partition(array,beg,end);
quickSort(array,beg,index-1);
quickSort(array,index+1,end);
}
private static int partition(int[] array,int beg,int end){
int left=beg;
int right=end;
int temp=array[end];
while(left<right){
while(left<right&&array[left]<=temp){
left++;
}
while(left<right&&array[right]>=temp){
right--;
}
swap(array,left,right);
}
swap(array,left,end);
return left;
}
private static void swap(int[] array,int i, int j) {
int m=array[i];
array[i]=array[j];
array[j]=m;
}
时间复杂度:最坏情况数组逆序O(N^2),平均O(NlogN)
空间复杂度:最坏情况数组逆序O(N),平均O(NlogN)
稳定性:不稳定排序
五、简单选择排序
原理:从待排序区间中选出最小值,放到已排序区间末尾。通过打擂台方式找到最小值。
private static void selectSort(int[] array){
for(int bound=0;bound<array.length;bound++){
for(int cur=bound+1;cur<array.length;cur++){
if(array[cur]<array[bound]){
int temp=array[bound];
array[bound]=array[cur];
array[cur]=temp;
}
}
}
}
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:不稳定排序
六、堆排序
原理:从待排序区间找到一个做大值,放到已排序区间最前面。
private static void heapSort(int[] array){
createHeap(array);
for(int i=0;i<array.length;i++){
swap(array,0,array.length-i-1);
shiftDown(array,array.length-i-1,0);
}
}
private static void createHeap(int[] array) {
for(int i=(array.length-1-1)/2;i>=0;i--){
shiftDown(array,array.length,i);
}
}
private static void shiftDown(int[] array,int size,int index){
//建大堆
int parent=index;
int child=2*parent+1;
while(child<size){
if (child + 1 < size && array[child+1]>array[child]) {
child=child+1;
}
if(array[parent]<array[child]){
swap(array,child,parent);
}
else{
break;
}
parent=child;
child=2*parent+1;
}
}
private static void swap(int[] array,int i, int j) {
int m=array[i];
array[i]=array[j];
array[j]=m;
}
时间复杂度:O(NlogN)
空间复杂度:O(1)
稳定性:不稳定排序
七、归并排序
原理:将待排序序列中相邻的两个有序子序列合并成一个有序序列。
private static void mergeSort(int[] array){
mergeSortHelper(array,0,array.length);
}
//[left,mid)
//[mid,right)
private static void mergeSortHelper(int[] array,int left,int right){
//不能写成if(left>=right){return;}
if(right-left<=1){
return;
}
int mid=(left+right)/2;
mergeSortHelper(array,left,mid);
mergeSortHelper(array,mid,right);
merge(array,left,mid,right);
}
private static void merge(int[] array,int low,int mid,int high){
int[] extra=new int[high-low];
int cur1=low;
int cur2=mid;
int index=0;
while(cur1<mid&&cur2<high){
//写成<不能保证稳定性
if(array[cur1]<=array[cur2]){
extra[index]=array[cur1];
cur1++;
index++;
}
else{
extra[index]=array[cur2];
cur2++;
index++;
}
}
while(cur1<mid){
extra[index]=array[cur1];
cur1++;
index++;
}
while(cur2<high){
extra[index]=array[cur2];
cur2++;
index++;
}
for(int i=0;i<high-low;i++){
array[low+i]=extra[i];
}
}
时间复杂度:O(NlogN)
空间复杂度:O(N)
稳定性:稳定排序