最好到最坏的常用算法复杂度排序如下:
常数级O(1)、
对数级O(logn)、
线性级O(n)、
线性对数级(nlogn)、
平方级O(n^2)、
立方级O(n^3)、
指数级O(2^n)等。
排序算法
以下是对
https://www.cnblogs.com/manshufeier/p/9364178.html
的总结
分类 | 排序法 | 最差时间分析 | 平均时间复杂度 | 空间复杂度 | 稳定性 |
插入排序 | 直接插入排序 | O(n^2) | O(n^2) | ![]() | 稳定 |
希尔排序 | O(n^2) | O(n^1.3)-O(n^2) | ![]() | 不稳定 | |
交换排序 | 冒泡排序 | O(n^2) | O(n^2) | ![]() | 稳定 |
快速排序 | O(n^2) | O(nlogn) | O(logn)~O(n) | 不稳定 | |
选择排序 | 简单选择排序 | O(n^2) | O(n^2) | ![]() | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | ![]() | 不稳定 | |
归并排序 | 2路归并排序 | O(nlogn) | O(nlogn) | O(n) | 稳定 |
常用排序算法的性能与待排数组的循序的关系作一个总结:
1)冒泡:无关;
2)选择:无关;
3)插入:有关,有序程度越大,比较越少;
4)shell:有关,它的基本思想基于插入排序;
5)合并:有关,有序程度愈大,合并过程的比较次数越少;
6)堆排序:有关,有序程度越大,建立堆下沉操作越少;
7)快排序:有关,如果选择最后值作为阀值,那么有序程度越好,就越可能退化成O(n^2);
摘要:内排序是在排序整个过程中,待排序的所有记录全部被放置在内存中。在数据结构里表示复杂度就是
。
外排序:
外排序是由于排序的记录个数太多,不能同时放置在内存,整个排序过程需要在内外存之间多次交换数据才能进行。
1、多路平衡归并排序
2、置换-选择排序
3、最佳归并树形排序
按照算法的复杂度分为两大类:
1.简单算法:冒泡排序、简单选择排序、直接插入排序
2.改进算法:希尔排序、堆排序 、归并排序、快速排序
使用了分治思想的排序算法
堆排序
思想:将待排序序列构造成一个大顶堆,然后再进行排序,每次交换较大值都需要重新构造大顶堆
import java.util.Arrays;
public class HeapSort {
public static void main(String[] args) {
int[] arr = new int[] {9,6,8,7,0,1,10,4,2};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void heapSort(int[] arr) {
//开始位置是最后一个非叶子节点,即最后一个节点的父节点
int start = (arr.length-1)/2;
//调整为大顶堆
for(int i=start;i>=0;i--) {
maxHeap(arr, arr.length, i);
}
//先把数组中的第0个和堆中的最后一个数交换位置,再把前面的处理为大顶堆
for(int i=arr.length-1;i>0;i--) {
int temp = arr[0];
arr[0]=arr[i];
arr[i]=temp;
maxHeap(arr, i, 0);
}
}
public static void maxHeap(int[] arr,int size,int index) {
//左子节点
int leftNode = 2*index+1;
//右子节点
int rightNode = 2*index+2;
int max = index;
//和两个子节点分别对比,找出最大的节点
if(leftNode<size&&arr[leftNode]>arr[max]) {
max=leftNode;
}
if(rightNode<size&&arr[rightNode]>arr[max]) {
max=rightNode;
}
//交换位置
if(max!=index) {
int temp=arr[index];
arr[index]=arr[max];
arr[max]=temp;
//交换位置以后,可能会破坏之前排好的堆,所以,之前的排好的堆需要重新调整
maxHeap(arr, size, max);
}
}
}
归并排序
思想:两两合并排序后再合并排序
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[] arr = new int[] {1,3,5,2,4,6,8,10};
System.out.println(Arrays.toString(arr));
mergeSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
//归并排序
public static void mergeSort(int[] arr,int low,int high) {
int middle=(high+low)/2;
if(low<high) {
//处理左边
mergeSort(arr, low, middle);
//处理右边
mergeSort(arr, middle+1, high);
//归并
merge(arr,low,middle,high);
}
}
public static void merge(int[] arr,int low,int middle, int high) {
//用于存储归并后的临时数组
int[] temp = new int[high-low+1];
//记录第一个数组中需要遍历的下标
int i=low;
//记录第二个数组中需要遍历的下标
int j=middle+1;
//用于记录在临时数组中存放的下标
int index=0;
//遍历两个数组取出小的数字,放入临时数组中
while(i<=middle&&j<=high) {
//第一个数组的数据更小
if(arr[i]<=arr[j]) {
//把小的数据放入临时数组中
temp[index]=arr[i];
//让下标向后移一位;
i++;
}else {
temp[index]=arr[j];
j++;
}
index++;
}
//处理多余的数据
while(j<=high) {
temp[index]=arr[j];
j++;
index++;
}
while(i<=middle) {
temp[index]=arr[i];
i++;
index++;
}
//把临时数组中的数据重新存入原数组
for(int k=0;k<temp.length;k++) {
arr[k+low]=temp[k];
}
}
}
快速排序
思想:选取一个关键字使他左边的值都比他小,右边的值都比他大,然后左边和右边进行相同的操作。
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] arr = new int[] {3,4,6,7,2,7,2,8,0,9,1};
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr,int start,int end) {
if(start<end) {
//把数组中的第0个数字做为标准数
int stard=arr[start];
//记录需要排序的下标
int low=start;
int high=end;
//循环找比标准数大的数和比标准数小的数
while(low<high) {
//右边的数字比标准数大
while(low<high&&stard<=arr[high]) {
high--;
}
//使用右边的数字替换左边的数
arr[low]=arr[high];
//如果左边的数字比标准数小
while(low<high&&arr[low]<=stard) {
low++;
}
arr[high]=arr[low];
}
//把标准数赋给低所在的位置的元素
arr[low]=stard;
//处理所有的小的数字
quickSort(arr, start, low);
//处理所有的大的数字
quickSort(arr, low+1, end);
}
}
}