排序的相关概念
排序:所谓排序,就是使一串记录,按照其中的某个或某几个关键字的大小,递增或递减排列起来的操作。
稳定性:在待排序的记录序列中,存在多个具有相同关键字的记录,若经过排序,这些记录的相对次序保持不变,则称这种排序算法是稳定的。
内部排序:把数据全部加载到内存中进行排序。
外部排序:数据太多,内存不能存储了,将数据放到磁盘、U盘上进行排序。
排序算法的分类
插入排序:直接插入排序、希尔排序
选择排序:选择排序、堆排序
交换排序:冒泡排序、快速排序
归并排序:归并排序
排序算法实现
1.交换排序
1.1冒泡排序
基本思想:
遍历arr.length-1次数组,每次从头开始遍历,如果遍历到第j项,有arr[j]>arr[j+1],则将arr[j]和arr[j+1]进行交换。(升序版)
代码实现:
public static void sort7(int[] arr){
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length-1; j++) {
if(arr[j]>arr[j+1]){
int tmp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
}
}
}
}
//冒泡排序优化
public static void sort8(int[] arr){
for (int i = 0; i < arr.length; i++) {
boolean flg=false;
for (int j = 0; j < arr.length-1-i; j++) {
if(arr[j]>arr[j+1]){
int tmp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
flg=true;
}
}
if (flg==false){
return;
}
}
}
特性总结:
1.时间复杂度:O(n^2)
空间复杂度:O(1)
3.稳定性:稳定
1.2快速排序
基本思想:任取待排序元素序列中的某个元素作为基准值,按照该排序码将待排序的集合分割成两个子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排列在相应位置上为止。(可能不好理解,可看下面的图解)
Hoare版
挖坑法
前后指针
快速排序非递归
代码实现:
Hoare版:
public static void quickSort(int[] arr){
quick(arr,0,arr.length-1);
}
private static void quick(int[] arr,int l,int r){
if (l>=r){
return;
}
int pivot = partition1(arr,l,r);//划分
//递归
quick(arr,l,pivot-1);
quick(arr,pivot+1,r);
}
//hoare版
private static int partition1(int[] arr,int left,int right){
int key = arr[left];
int i =left;
while (left<right){
while (arr[right]>=key && left<right){
right--;
}
while (arr[left]<=key && left<right){
left++;
}
swap(arr,left,right);
}
swap(arr,left,i);
return left;
}
挖坑法:
//快速排序 挖坑法
public static void quickSort(int[] arr){
quick(arr,0,arr.length-1);
}
private static void quick(int[] arr,int l,int r){
if (l>=r){
return;
}
int pivot = partition(arr,l,r);//划分
//递归
quick(arr,l,pivot-1);
quick(arr,pivot+1,r);
}
private static int partition(int[] arr,int left,int right){
int key = arr[left];
while (left<right){
while (arr[right]>=key && left<right){
right--;
}
arr[left]=arr[right];
while (arr[left]<= key && left<right){
left++;
}
arr[right]=arr[left];
}
arr[left]=key;
return left;
}
前后指针:
public static void quickSort(int[] arr){
quick(arr,0,arr.length-1);
}
private static void quick(int[] arr,int l,int r){
if (l>=r){
return;
}
int pivot = partition2(arr,l,r);//划分
//递归
quick(arr,l,pivot-1);
quick(arr,pivot+1,r);
}
//前后指针
private static int partition2(int[] arr,int left,int right){
int prev = left;
int cur = left+1;
while (cur<=right){
if (arr[cur]<arr[left] && arr[++prev] != arr[cur]){
swap(arr,prev,cur);
}
cur++;
}
swap(arr,prev,left);
return prev;
}
非递归实现快速排序:
//快速排序非递归
public static void quickSort1(int[] arr){
//用栈放数据
Deque<Integer> stack = new LinkedList<>();
int left=0;
int right = arr.length-1;
int pivot=partition(arr,left,right);
if (pivot>left+1){
stack.push(left);
stack.push(pivot-1);
}
if (pivot<right-1){
stack.push(pivot+1);
stack.push(right);
}
while(!stack.isEmpty()){
right=stack.pop();
left = stack.pop();
pivot=partition(arr,left,right);
if (pivot>left+1){
stack.push(left);
stack.push(pivot-1);
}
if (pivot<right-1){
stack.push(pivot+1);
stack.push(right);
}
}
}
性能总结:
1.时间复杂度:O(N*logN) (最好情况)
2.空间复杂度:O(logN) (最好情况)
3.稳定性:不稳定