为了统一起见,我先给出一个主函数,条例比较清晰
public static void main(String[] args) {
int[] array = {34,2,67,88,54,33,78,22,4,90,86,45,6,12,99};
System.out.println(Arrays.toString(array));
insertSort(array);
System.out.println("直接插入排序:"+Arrays.toString(array));
shellSort(array);
System.out.println("希尔排序:"+Arrays.toString(array));
seclectSort(array);
System.out.println("选择排序:"+Arrays.toString(array));
heapSort(array);
System.out.println("堆排序:"+Arrays.toString(array));
quickSort(array);
System.out.println("快速排序:"+Arrays.toString(array));
quickSort2(array);
System.out.println("快排非递归排序:"+Arrays.toString(array));
bubbleSort(array);
System.out.println("冒泡排序:"+Arrays.toString(array));
mergeSort(array);
System.out.println("归并排序:"+Arrays.toString(array));
mergeSort2(array);
System.out.println("归并非递归排序:"+Arrays.toString(array));
}
1、插入排序
1.1、直接插接排序
原理:整个区间被分为有序区间和无序区间
实现:
public static void insertSort(int[] array){
for (int i = 1; i < array.length; i++) {
//[0,i)有序区间
//[i,array.length)有序区间
int tmp=array[i];
int j = i-1;
for (;j>=0;j--) {
// 不写 array[j] == tmp 是保证排序的稳定性
if (array[j]>tmp){
array[j+1]=array[j];
}else{
break;
}
}
array[j+1]=tmp;
}
}
性能分析:
时间复杂度:最好:O(n)最坏:O(n^2)
空间复杂度:O(1)
稳定性:稳定
2.2、希尔排序
原理:分组
希尔排序是对直接插入排序的优化。
实现:
public static void shellSort(int[] array) {
int[] arr = {5,3,1};
for (int i = 0; i <arr.length ; i++) {
shell(array,arr[i]);
}
}
public static void shell(int[] array, int gap) {
for (int i = gap; i < array.length; i++) {
int tmp = array[i];
int j = i-gap;
for ( ;j>=0 ; j=j-gap) {
if (array[j]>tmp){
array[j+gap] = array[j];
}else{
break;
}
}
array[j+gap] = tmp;
}
}
性能分析:
时间复杂度:最好:O(n)最坏:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
2、选择排序
2.1、直接选择排序
原理:每趟选择一个最小值放在前面
实现:
public static void seclectSort(int[] array){
for (int i = 0; i <array.length-1 ; i++) {
for (int j = i+1; j <array.length ; j++) {
if(array[i]>array[j]){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
}
性能分析:
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:不稳定
2.2、堆排序
原理:在建堆的基础上,交换堆顶和堆尾的元素,然后向下调整
注意: 排升序要建大堆;排降序要建小堆。
实现:
public static void heapSort(int[] array){
int len = array.length;
for (int i = (len-1-1)/2; i >= 0 ; i--) {
heap(array,i,len);
}
for (int i = len-1; i > 0; i--) {
swap(array,0,i);
len--;
heap(array,0,len);
}
}
private static void heap(int[] array, int parent, int length) {
int child = parent*2+1;
while (child<length){
if (child+1<length && array[child+1]>array[child]){
child++;
}
if (array[child] > array[parent]){
int tmp = array[child];
array[child] = array[parent];
array[parent] = tmp;
parent = child;
child = parent*2+1;
}else {
break;
}
}
}
public static void swap(int[] array,int a,int b){
int tmp =array[a];
array[a] = array[b];
array[b] = tmp;
}
性能分析:
时间复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定
3、交换排序
3.1、冒泡排序
原理:大家都很熟悉了
public static void bubbleSort(int[] array){
for (int i = 0; i <array.length-1 ; i++) {
boolean flag = true;
for (int j = 0; j <array.length-1-i ; j++) {
if (array[j]>array[j+1]){
int tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
flag = false;
}
}
if (flag){
break;
}
}
}
性能分析:
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:稳定
3.2、快速排序
原理:
主要是找基准值,然后两边继续找基准。
递归实现:
public static void quickSort(int[] array){
quick(array,0,array.length-1);
}
public static void quick(int[] array,int low,int high){
if(low<high){
medianOfThree(array,low,high);
int piv = pivot(array,low,high);
quick(array,low,piv-1);
quick(array,piv+1,high);
}
}
public static int pivot(int[] array,int start,int end){
int tmp = array[start];
while(start<end){
while(start<end && array[end]>=tmp){
end--;
}
array[start] = array[end];
while(array[start]<tmp){
start++;
}
array[end] = array[start];
}
array[start] = tmp;
return start;
}
public static void medianOfThree(int[] array,int low,int high){
int mid = (low+high)/2;
if (array[low]<array[mid]){
swap(array,low,mid);
}
if (array[low]>array[high]){
swap(array,low,high);
}
if (array[mid]>array[high]){
swap(array,mid,high);
}
}
public static void swap(int[] array,int a,int b){
int tmp =array[a];
array[a] = array[b];
array[b] = tmp;
}
非递归实现:
public static void quickSort2(int[] array){
Stack<Integer> stack = new Stack<>();
int low = 0;
int high = array.length-1;
int piv = pivot(array,low,high);
if (piv>low+1){
stack.push(low);
stack.push(piv-1);
}
if (piv<high-1){
stack.push(piv+1);
stack.push(high);
}
while (!stack.empty()){
high = stack.pop();
low = stack.pop();
piv = pivot(array,low,high);
if (piv>low+1){
stack.push(low);
stack.push(piv-1);
}
if (piv<high-1){
stack.push(piv+1);
stack.push(high);
}
}
}
性能分析:
时间复杂度:最好情况:O(nlogn) 最坏的情况O(n^2)
空间复杂度:O(logn)
稳定性:不稳定
4、归并排序
原理:先分解,然后在合并,合并的同时进行排序
递归实现:
public static void mergeSort(int[] array){
merge(array,0,array.length-1);
}
private static void merge(int[] array, int low, int high) {
if (low>=high)return;
int mid = (low+high)/2;
merge(array,low,mid);
merge(array,mid+1,high);
mergeAdd(array,low,mid,high);
}
private static void mergeAdd(int[] array, int low, int mid, int high) {
int s1 = low;
int e1 = mid;
int s2 = mid+1;
int e2 = high;
int[] tmp = new int[high-low+1];
int k=0;
while(s1<=e1&&s2<=e2){
if (array[s1]<=array[s2]){
tmp[k++]=array[s1++];
}else{
tmp[k++]=array[s2++];
}
}
while(s1<=mid) tmp[k++]=array[s1++];
while(s2<=high) tmp[k++]=array[s2++];
for (int i = 0; i <tmp.length ; i++) {
array[i+low] = tmp[i];
}
}
非递归实现:
public static void mergeSort2(int[] array){
for (int i = 1; i <array.length ; i=i*2) {
merge2(array,i);
}
}
private static void merge2(int[] array, int gap) {
int s1 = 0;
int e1 = s1+gap-1;
int s2 = e1+1;
int e2 = s2+gap-1<array.length?s2+gap-1:array.length-1;
int[] tmp = new int[array.length];
int k =0;
while(s2<array.length){
while(s1<=e1&&s2<=e2){
//当有两个归并段,且这两个段内存了数
if(array[s1]<=array[s2]){
tmp[k++] = array[s1++];
}else {
tmp[k++] = array[s2++];
}
}
while(s1<=e1){
tmp[k++] = array[s1++];
}
while (s2<=e2){
tmp[k++] = array[s2++];
}
//从这里开始每个下标都有可能越界
s1 = e2+1;
e1 = s1+gap-1;
s2 = e1+1;
e2 = s2+gap-1< array.length?s2+gap-1:array.length-1;
}
//推出大循环,把S1段内的数据copy
while (s1<array.length){
tmp[k++] = array[s1++];
}
for (int i = 0; i <tmp.length ; i++) {
array[i] = tmp[i];
}
}
性能分析:
时间复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定