- 排序算法
就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作 - 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序
选择排序 冒泡排序 插入排序 希尔排序 归并排序 堆排序 快速排序
- 非比较类排序:不通过比较来决定元素之间的相对次序,它可以突破于比较排序的时间下线,以线性时间运行,因此也称为线性时间非比较类排序
计数排序 桶排序 基数排序
排序的相关概念:
- 稳定:如果a原本在b前面,而 a==b ,排序之后仍然a在b前面
- 不稳定:如果a原本在b前面,而 a==b ,排序之后a可能会出现在b后面
- 时间复杂度:对排序数据总的操作次数,反映当n变化时,操作数呈现什么规律
- 空间复杂度:是指算法在计算机内执行时所需要存储空间的度量,它也是数据规模n的函数
选择排序
选择排序(selection -sort)是一种简单直观的排序算法。他的工作原理:首先在未排序序列中找到最大(最小)元素,存放在排序序列的起始位置,然后,再从剩余未排序的元素中继续寻找最大(最小)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕
- 时间复杂度O(n^ 2)
- 空间复杂度O(1)
- 稳定性:不稳定
public void sort() {
for (int i = 0; i < arr.length-1; i++) {
for (int j = i+1; j < arr.length; j++) {
if(arr[i] > arr[j]){
swap(i,j);
}
}
}
System.out.println(Arrays.toString(arr));
}
冒泡排序
冒泡排序是一种简单的排序算法。它重复地走访过要排序的树列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字是因为最小的元素会经由交换慢慢“浮到”数列顶端
- 时间复杂度O(n^ 2)
- 空间复杂度O(1)
- 稳定性:稳定
public void sort() {
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length- i-1; j++) {
if(arr[j] > arr[j+1]){
swap(j,j+1);
}
}
}
System.out.println(Arrays.toString(arr));
}
插入排序
插入排序(Insertion -sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入
- 时间复杂度O(n^ 2)
- 空间复杂度O(1)
- 稳定性:稳定
public void sort() {
for (int i = 0; i <arr.length ; i++) {
int e = arr[i];
int j = 0;
for ( j = i;j > 0 && arr[j-1] >e; j--) {
arr[j] = arr[j-1];
}
arr[j] = e;
}
System.out.println(Arrays.toString(arr));
}
算法的执行时间,除了跟算法的策略有关系之外,还跟数据分布情况有关系
数据发布情况:完全随机 大致有序 大致平稳
选 择 400ms 230ms 200ms
冒泡 360ms 50ms 250ms
插入 50ms 5ms 50ms
希尔排序
1959年shell发明,第一个突破O(n ^2)的排序算法,是简单插入排序的改进版。它与插入排序不同之处,他会优先比较距离较远的元素。希尔排序又叫缩小增量排序
- 时间复杂度O(n^1.3)
- 空间复杂度O(1)
- 稳定性:不稳定
public void sort() {
int len = arr.length;
for(int gap = len/2;gap >0;gap = gap/2){
for (int i = gap; i < len; i++) {
int j = i;
int e = arr[i];
while ( j-gap >=0 &&arr[j-gap] >e){
arr[j] = arr[j-gap];
j = j-gap;
}
arr[j] = e;
}
}
System.out.println(Arrays.toString(arr));
}
(二路)归并排序
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一种非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个自序列,在使子序列段间有序,若将两个有序表合并成一个有效表,称为二路归并
- 时间复杂度 :O(nlogn)
- 空间复杂度:0(n)
- 稳定性:稳定
public void sort() {
mergeSort(0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
private void mergeSort(int L, int R) {
if( L >=R){
return;
}
int mid = (L+R)/2;
//递归排序当前层级左边
mergeSort(L,mid);
//递归排序当前层级左边
mergeSort(mid+1,R);
//排序完后将左右进行合并
if(arr[mid] > arr[mid+1]){
merge(L,mid,R);
}
}
private void merge(int L, int mid, int R) {
int[]aux = new int[R-L+1];
for (int k = L; k <=R ; k++) {
aux[k-L] =arr[k];
}
int i =L;
int j = mid + 1;
for (int k = L; k <=R ; k++) {
if(i >mid){//左边完毕
arr[k] = aux[j-L];
j++;
}else if(j > R){//右边完毕
arr[k] = aux[i-L];
i++;
}else if(aux[i-L] < aux[j-L]){
arr[k] = aux[i-L];
i++;
}else{
arr[k] = aux[j - L];
j++;
}
}
}