概述
- 插入排序:直接插入(稳定)[n2]/希尔排序[n1.3]
- 选择排序:简单选择排序[n2]/堆排序[nlogn]
- 交换排序:冒泡排序(稳定)[n2]/快速排序[nlogn]
- 归并排序(稳定)[nlogn]
- 基数排序(稳定)[d*(r+n)]
基本有序时选择直接插入排序或者冒泡排序,时间复杂度可降到O(n),但对于快速排序则相反,时间复杂度可提高为O(n2)
1.快速排序
public void quickSort(int[] array, int begin, int end) {
if (begin < end && begin >= 0 && end < array.length) {
int midIndex = partionSort1(array, begin, end);
quickSort(array, begin, midIndex - 1);
quickSort(array, midIndex + 1, end);
}
}
// Wikipedia 选择最后一位作为参考值。
public int partionSort(int[] array, int begin, int end) {
int pivotValue = array[end];
int sortIndex = begin;
for (int i = begin; i < end; i++) {
if (array[i] < pivotValue) {
swap(array, sortIndex, i);
sortIndex++;
System.out.println(Arrays.toString(array));
}
}
swap(array,sortIndex,end);
return sortIndex;
}
//优化过后的代码
public int partionSort1(int[] arr,int left,int right){
int pivotKey = arr[left];
while(left < right) {
while(left < right && arr[right] >= pivotKey)
right --;
arr[left] = arr[right]; //把小的移动到左边
System.out.println(Arrays.toString(arr));
while(left < right && arr[left] <= pivotKey)
left ++;
arr[right] = arr[left]; //把大的移动到右边
System.out.println(Arrays.toString(arr));
}
arr[left] = pivotKey; //最后把pivot赋值到中间
System.out.println(Arrays.toString(arr));
return left;
}
2.归并排序
public class MergeSort {
public void sort(int[] arr){
msort(arr,0,arr.length-1);
}
//递归,先拆后合并,
public void msort(int[] arr,int left,int right){
if(left<right){
int mid = (left+right)>>1;
msort(arr,left,mid);
msort(arr,mid+1,right);
merge(arr,left,mid,right);
}
}
//合并结果放入一个新的数组中,再赋值给原数组。
public void merge(int[] arr,int left,int mid,int right){
int len = right - left +1;
int[] result = new int[len];
int k = 0;
int i = left;
int j = mid+1;
while(i<=mid && j<=right){
result[k++] = (arr[i]<=arr[j])?arr[i++]:arr[j++];
}
while(i<=mid){
result[k++] = arr[i++];
}
while(j<=right){
result[k++] = arr[j++];
}
i = left;j = 0;
while(i<=right){
arr[i++] = result[j++];
}
}
}
3.基数排序/桶排序
public class BucketSort {
public void sort(int[] arr){
int[] temp = new int[arr.length];
int[] bucket = new int[10];
int digit = findMax(arr);
int radix = 1;
for(int i=0;i<digit;i++){
resetArray(bucket);//清空桶
//装桶
for(int j=0;j<arr.length;j++){
bucket[(arr[j]/radix)%10]++;
}
//求积分
for(int k=1;k<10;k++){
bucket[k] += bucket[k-1];
}
//排序
for(int j=arr.length-1;j>=0;j--){
int x = (arr[j]/radix)%10;
int index = bucket[x]--;
temp[index-1] = arr[j];//这里index-1而不是temp[index]
}
//将temp赋值到arr
for(int j=0;j<arr.length;j++){
arr[j] = temp[j];
}
radix *= 10;
}
}
//数组清零
public void resetArray(int[] arr){
for(int i=0;i<arr.length;i++){
arr[i] = 0;
}
}
//返回最大值的位数
public int findMax(int[] arr){
int max = arr[0];
for(int i=1;i<arr.length;i++){
if(arr[i]>max){
max = arr[i];
}
}
int digit = 0;
for(;max>0;digit++){
max /= 10;
}
return digit;
}
}
4.插入排序
public void sort(int[] array){
int len = array.length;
int step = 1;//为希尔排序做准备
for (int i = step; i < len; i++) {
for (int j = i; j > 0; j -= step) {//相应步进序列进行插入排序
if(array[j]<array[j-step]){
Util.swap(array,j,j-step);
System.out.println(Arrays.toString(array));
}else{
break;
}
}
}
}
5.希尔排序
希尔排序是插入排序的一种高效率的实现,也叫缩小增量排序。简单的插入排序中,如果待排序列是正序时,时间复杂度是O(n),如果序列是基本有序的,使用直接插入排序效率就非常高。基本思想是:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时再对全体记录进行一次直接插入排序。
记录移动次数依赖于增量因子序列d的选取
//步进选择:每次减半。
public void sort(int[] array) {
int len = array.length;
for (int step = len / 2;step > 0;step >>= 1) {//步进递减到1
for (int i = step; i < len; i++) {//
for (int j = i; j >=step; j -= step) {//相应步进序列进行插入排序,注意终止条件!!!错写为 j>0!!!
if(array[j]<array[j-step]){
Util.swap(array,j,j-step);
System.out.println(Arrays.toString(array));
}else{
break;
}
}
}
}
}
6.堆排序
public class HeapSort {
private int len = 0;
public void sort(int[] array){
len = array.length;
for(int i=len/2-1;i>=0;i--){
heap(array,i);
}
Util.swap(array,0,len-1);
len--;
while(len>0){
heap(array,0);
Util.swap(array,0,len-1);
len--;
}
}
public void heap(int[] array,int rootIndex){//Max-Heap
int leftIndex = rootIndex*2+1;
int rightIndex = leftIndex+1;
int maxIndex = rootIndex;
if(leftIndex<len && array[leftIndex]>array[maxIndex])
maxIndex = leftIndex;
if(rightIndex < len && array[rightIndex]>array[maxIndex])
maxIndex = rightIndex;
if(maxIndex != rootIndex){
Util.swap(array,maxIndex,rootIndex);
heap(array,maxIndex);
}
}
}
7.冒泡排序
//对普通的冒泡加以改进
public class BubbleSort {
public void sort1(int[] arr){
int len = arr.length;
for(int i=len-1;i>0;i--){
boolean flag = false;//加一个flag可减少不必要的操作,如果没有交换,则说明数组已经排好序。
for(int j=0;j<i;j++){
if(arr[j]>arr[j+1]){
Util.swap(arr,j,j+1);
flag = true;
}
}
if(!flag)break;
}
}
//进一步优化,记录每次最后交换的位置。如果没有发生交换,则说明后面已经排好序。
public void sort(int[] arr){
int i = arr.length-1;
while (i>0){
int pos = 0;
for(int j=0;j<i;j++){
if(arr[j]>arr[j+1]){
Util.swap(arr,j,j+1);
pos = j;
}
}
i = pos;
}
}
}
8.选择排序
//简单版本
public void sort(int[] arr) {
int mindex;
for (int i = 0; i < arr.length - 1; i++) {
mindex = i;
for (int j = i; j < arr.length; j++) {
if (arr[j] < arr[mindex]) {
mindex = j;
}
}
if (mindex != i){
Util.swap(arr,mindex,i);
}
}
}
//改进版本:二元选择排序
public void sort(int[] arr) {
int len = arr.length;
for (int i = 0; i < len / 2; i++) {
int mindex = i;
int maxdex = i;
for (int j = i + 1; j < len - i; j++) {
if (arr[j] > arr[maxdex]) {
maxdex = j;
continue;//如果符合该条件,就不用判断下面了
}
if (arr[j] < arr[mindex]) {
mindex = j;
}
}
Util.swap(arr, i, mindex);
//这里要注意:有一种情况是maxdex==i,这时候最大值已经和最小值交换,所以最大值的位置应该在mindex。
if (maxdex == i) {
Util.swap(arr, len - i - 1, mindex);
} else {
Util.swap(arr, len - i - 1, maxdex);
}
}
}
}