1、直接插入排序
public void sort(int[] arr){
for(int i=1;i<arr.length;i++){
int k=arr[i];//有序区间[0,i)无序[i,arr.length),
//为无序的第一个数
int j=i-1;//有序的最后一个数
while(j>=0&&arr[j]>v){//进行移位
arr[j+1]=arr[j];
j--;
}//j=-1时推出
arr[j+1]=k;//插入到合适位置
}
}
折半插入排序
public static void bsInsertSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int v = array[i];
int left = 0;
int right = i; // [left, right) // 需要考虑稳定性
while (left < right) {
int m = (left + right) / 2;
if (v >= array[m]) {
left = m + 1;
} else {
right = m;
}
}// 搬移
for (int j = i; j > left; j--) {
array[j] = array[j - 1];
}
arr[left]=v;
}
}
性能分析:时间复杂度O(n^2),空间复杂度O(1),稳定
2、希尔排序
希尔排序法又称缩小增量法。希尔排序法的基本思想是:
先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。
然后,取,重复上述分组和排序的工作。当到达=1
时,所有记录在统一组内排好序。
当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很
快。这样整体而言,可以达到优化的效果。
public void shellSort(int[] arr){
int gap=arr.length;
while(gap>1){
gap=gap/3+1;
for(int i=0;i<arr.length-gap;++i){
int k=arr[i+gap];
while(i>=0&&arr[i]>k){
arr[i+gap]=arr[i];
i--;
}
arr[i+gap]=k;
}
}
}
性能分析:时间复杂度O(n^1.3),空间复杂度O(1),不稳定
3、选择排序
每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完 。
public void selectSort(int[] arr){
for(int i=0;i<arr.length-1;i++){
int max=0;
for(int j=1;j<arr.length-i;j++){
if(arr[j]>arr[max])max=j;
}
int t=arr[max];
arr[max]=arr[arr.length-i-1];
arr[arr.length-i-1]=t;
}
}
性能分析:时间复杂度O(n^2),空间复杂度O(1),不稳定。
4.冒泡排序
在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序。
public static void bubbleSort(int[] arr){
int len=arr.length;
while(len>0){
boolean k=true;
for(int i=0;i<len-1;i++){
if(arr[i]>arr[i+1]){
swap(arr,i,i+1);
k=false;
}
}
if(k){
break;
}
len--;
}
}
性能分析:时间复杂度O(n^2),空间复杂度O(1),稳定
5.快速排序
- 从待排序区间选择一个数,作为基准值(pivot);
- Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
- 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 为1,代表已有序,长度为0代表没有数据。
public static void quickSort1(int[] arr,int left,int right){
if(left<right){
int mid=pation(arr,left,right);
quickSort1(arr,left,mid-1);
quickSort1(arr,mid+1,right);
}
}
public static int partion(int[] arr,int start,int end){
int key=arr[start];
int begin=start;
while(start<end){
while(start<end&&arr[end]>=key){
end--;
}
while(start<end&&arr[start]<=key){
start++;
}
swap(arr,start,end);
}
swap(arr,begin,start);
return start;
}
public static void swap(int[] arr,int a,int b){
int k=arr[a];
arr[a]=arr[b];
arr[b]=k;
}
partion的另一种方法,大致思路还是相同的
public static int patrion2(int[] arr,int left,int right){
int k=arr[left];
int i=left;
int j=right;
while(i<j){
while(i<j&&arr[j]>k){
j--;
}
arr[i]=arr[j];
while(i<j&&arr[i]<k){
i++;
}
arr[j]=arr[i];
}
arr[i]=k;
return i;
}
partion另一种
public static int partion(int[] arr,int left,int right){
int p=arr[left];
int d=left+1;
for(int i=left+1;i<=right;i++){
if(arr[i]<p){//将小于p的值放在其前面
swap(arr,i,d);
d++;
}
}
swap(arr,d-1,left);
return d-1;
}
性能分析:时间复杂度:O(n*log(n)) ;空间复杂度O(log(n));不稳定
6.归并排序
采用分治法,讲已有序列分解,再进行排序,将排好的序列进行有序合并,最后得到排序好的序列
public static void merge(int[] arr,int left,int mid,int right){
int i=left;
int j=mid;
int len=right-left;
int k=0;
int[] narr=new int[len];
while(i<mid&&j<right){
if(arr[i]<=arr[j]){
narr[k++]=arr[i++];
}else{
narr[k++]=arr[j++];
}
}
while(i<mid){
narr[k++]=arr[i++];
}
while(j<right){
narr[k++]=arr[j++];
}
for(int t=0;t<len;t++){
arr[left+t]=narr[t];
}
}
public static void mergeS(int[] arr,int left,int right){
if(left>=right-1){
return;
}
int mid=(left+right)/2;
mergeS(arr,left,mid);
mergeS(arr,mid,right);
merge(arr,left,mid,right);
}
public static void mergeSort(int[] arr){
mergeS(arr,0,arr.length);
}
非递归实现
public static void mergeSort(int[] arr){
for(int i=1;i<arr.length;i=i*2){
for(int j=0;j<arr.length;j=j+i*2){
int left=i;
int mid=j+i;
if(mid>=arr.length){
continue;
}
int right=mid+i;
if(right>arr.length){
right=arr.length;
}
merge(arr,left,mid,right);
}
}
}
性能分析:时间复杂度:O(n*log(n));空间复杂度:O(n);稳定