冒泡排序
冒泡排序的思想就是就是相邻的两个依次比较,如果是升序:总是先将最大的放在最后,然后是第二大放在倒数第二的位置,依次往下重复.
时间复杂度:O(N^2)
空间复杂度:O(1);
稳定性:稳定
public static void bubbleSort(int[] arr){
for(int i = 0 ; i < arr.length-1; i++){
//设置一个标志位
boolean flag = false;
for(int j = 0 ; j < arr.length- i -1 ; j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = true;
}
}
//如果标志位为false证明没有发生交换(此时数组及时有序的了,直接break;)
if(flag == false){
break;
}
}
}
选择排序
选择排序的思想是将当前元素和他后面的元素相比较,如果是升序排序可以发现总是将小的往前面放(第一小在数组第一个位置,第二小在数组第二的位置…).
时间复杂度:O(N^2)
空间复杂度:O(1);
稳定性:不稳定
public static void selectSort(int[] arr){
for(int i = 0 ; i < arr.length ; i++){
for(int j = i+1 ; j < arr.length ;j++){
if(arr[i] > arr[j]){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
}
直接插入排序
直接插入排序的思想就是就是先将当前元素插入进来,如果是升序排序,判断当前插入元素是否比他前面的小,如果小就让比它大的元素往后面走,直到碰到比插入元素小的元素,将它插入到比它小的前面.
时间复杂度 : 最好情况下:当数据有序的时候,O(n) 当数据越有序越快 , 最坏情况下:当数据逆序的时候,可以达到O(n^2)
空间复杂度 : O(1)
稳定性 : 不稳定
public static void insertSort(int[] arr){
for(int i = 1 ; i < arr.length ;i++){
int temp = arr[i];
int j = i-1;
for(;j>=0;j--){
if(temp < arr[j]){
arr[j+1] = arr[j];
}else{
break;
}
}
arr[j+1] = temp;
}
}
希尔排序
希尔排序又叫做缩小增量排序,其本质还是插入排序,是对直接插入排序的一种优化版本,只是在将待排序序列按照某种规则分成几个子序列,分别对这几个子序列进行直接插入排序,这个规则的体现就是增量的选取,如果选择增量为1那么就是直接插入排序。而希尔排序的每一趟排序都会使整个序列变得有序,等到整个序列有序了,那么再使用增量为1的插入排序的话那么就会使得排序的效率提高
时间复杂度:O(n*logN)
空间复杂度:O(1);
稳定性:不稳定
public static void shellSort(int[] arr){
int gap = arr.length >>>1;
while(gap>1){
shell(gap,arr);
gap = gap>>>1;
}
shell(1,arr);
}
public static void shell(int gap , int[] arr){
for(int i = gap ; i < arr.length ; i++){
int temp = arr[i];
int j = i-gap;
for(;j >= 0 ; j-=gap){
if(temp < arr[j]){
arr[j+gap] = arr[j];
}else{
break;
}
}
arr[j+gap] = temp;
}
}
堆排序
如果是升序排序,就建大根堆,如果是降序排序,就建小根堆,建堆完成之后,通过根节点与最后一个节点的交换实现排序过程.
时间复杂度: O(N*logN);
空间复杂度: O(1);
稳定性:不稳定
我们以升序排序为例:
//建立大根堆
public static void createHeap(int[] arr){
for(int i = (arr.length-1-1)/2; i>= 0 ; i--){
adjustDown(i,arr,arr.length);
}
}
//向下调整
public static void adjustDown(int p , int[] arr,int len){
int child = 2*p+1;
while(child<len){
if(child+1 < len && arr[child+1] >arr[child]){
child++;
}
if(arr[child] > arr[p]){
int tmp = arr[child];
arr[child] = arr[p];
arr[p] = tmp;
p = child;
child = 2*p+1;
}else{
break;
}
}
}
public static void heapSort(int[] arr){
createHeap(arr);
int len = arr.length;
while(len-1 > 0){
int tmp = arr[0];
arr[0] = arr[len-1];
arr[len-1] = tmp;
len--;
adjustDown(0,arr,len);
}
}
快速排序
快速排序的思想是先以数组的低位为基准,(以升序排序为例)比它大的后边放,比它小的往前边放,然后将它基准元素放入中间位置,此时就有基准左边的一组数组(都是比基准小的),和基准右边的一组数据(都是比基准数据大的),然后每组数据重复相同的动作,每组又会被分成两个组,直到每组只有一个数据时,这个数组就是有序的了.
时间复杂度:O(N*logN)
空间复杂度:O(1)
稳定性:不稳定
递归写法:
public static int partion(int[] arr,int low , int end){
int tmp = arr[low];
while(low< end){
while(low < end && tmp <= arr[end]){
end--;
}
arr[low] = arr[end];
while(low < end && tmp >=arr[low]){
low++;
}
arr[end] = arr[low];
}
arr[low] = tmp;
return low;
}
public static void quickSort(int[] arr,int low , int end){
if(low<end){
int partion = partion(arr, low, end);
quickSort(arr,low,partion-1);
quickSort(arr,partion+ 1,end);
}
}
非递归写法:
public static void noRecQuickSort(int[] arr){
Stack<Integer> stack = new Stack<>();
int low = 0 ;
int high = arr.length-1;
int par = partion(arr, low, high);
//1、分别判断 左右两边是否有两个元素以上,包含两个元素
//左边有2个元素以上
if(par > low+1) {
// 左边有2个元素以上
stack.push(low);
stack.push(par-1);
}
//右边有2个元素以上
if(par < high-1) {
stack.push(par+1);
stack.push(high);
}
while(!stack.empty()){
high= stack.pop();
low= stack.pop();
par = partion(arr, low, high);
if(par > low+1) {
//入栈:
stack.push(low);
stack.push(par-1);
}
//右边有2个元素以上
if(par < high-1) {
stack.push(par+1);
stack.push(high);
}
}
}
归并排序
归并排序使用的是分治的思想基本思想:将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行排序,最终将排好序的子集合合并成为所要求的排好序的集合。
时间复杂度:O(N*logN)
空间复杂度:O(N)
稳定性:稳定
递归写法:
public static void mergeSort(int[] arr,int low , int high){
if(low >=high){
return;
}
int mid = (low+high)>>>1;
mergeSort(arr,low,mid);
mergeSort(arr,mid+1,high);
//合并
merge(arr,low,mid,high);
}
public static void merge(int[] arr,int low , int mid ,int high){
int[] tmp = new int[high-low+1];
int i = 0;
int s1 = low;
int s2 = mid+1;
int e1 = mid ;
int e2 = high;
while(s1 <= e1 && s2 <= e2){
if(arr[s1] <= arr[s2]){
tmp[i++] = arr[s1++];
}else{
tmp[i++] = arr[s2++];
}
}
while(s1 <= e1){
tmp[i++] = arr[s1++];
}
while(s2 <= e2){
tmp[i++] = arr[s2++];
}
for(int k = 0 ; k < tmp.length ; k++){
arr[k+low] = tmp[k];
}
}
非递归写法:
public static void mergeSort2(int[] arr){
for(int gap = 1 ; gap < arr.length;gap*=2){
merge2(gap , arr);
}
}
public static void merge2(int gap , int[] arr){
int[] tmp = new int[arr.length];
int i = 0;
int s1 = 0;
int e1 = s1+gap-1;
int s2 = e1+1;
int e2 = s2+gap-1 >= arr.length ? arr.length-1:s2+gap-1;
while(s2 < arr.length){
//保证两个段都有元素
while(s1 <= e1 && s2 <= e2){
if(arr[s1] <= arr[s2]){
tmp[i++] = arr[s1++];
}else{
tmp[i++] = arr[s2++];
}
}
while(s1 <= e1){
tmp[i++] = arr[s1++];
}
while(s2 <= e2){
tmp[i++] = arr[s2++];
}
s1 = e2+1;
e1 = s1+gap-1;
s2 = e1+1;
e2 = s2+gap-1 >= arr.length ? arr.length-1:s2+gap-1;
}
while(s1 < arr.length){
tmp[i++] = arr[s1++];
}
for(int k = 0 ; k < tmp.length ; k++){
arr[k] = tmp[k];
}
}