概述
排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
我们这里说说八大排序就是内部排序。
直接插入排序
代码实现
package com.sto.arithmetic;
import java.util.Arrays;
/**
* @author yanyugang
* @description 直接插入排序
* @date 2019-10-21 10:08
*/
public class InsertSort {
public static void insertSort(int[] array){
//第0位独自作为有序数列,从第1位开始向后遍历
for (int i=1; i < array.length; i++) {
//0~i-1位为有序,若第i位小于i-1位,继续寻位并插入,否则认为0~i位也是有序的,忽略此次循环,相当于continue
if (array[i] < array[i - 1]){
//保存第i位的值
int temp=array[i];
int j=i - 1;
//从第i-1位向前遍历并移位,直至找到小于第i位值停止
while (j >= 0 && temp < array[j]) {
array[j + 1]=array[j];
j--;
}
//插入第i位的值
array[j + 1]=temp;
}
}
}
public static void main(String[] args){
int[] arr={9, 6, 7, 4, 15, 3, 2, 1};
insertSort(arr);
System.out.println(Arrays.toString(arr));
}
}
希尔排序(Shell`s Sort)
希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进。希尔排序又叫缩小增量排序
基本思想:
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
操作方法:
- 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
代码实现
public static void ShellSort(int[] arr) {
int gap = arr.length / 2;
while (1 <= gap) {
// 把距离为 gap 的元素编为一个组,扫描所有组
for (int i = gap; i < arr.length; i++) {
int j = 0;
int temp = arr[i];
// 对距离为 gap的元素组进行插入排序
for (j = i - gap; j >= 0 && temp < arr[j]; j = j - gap) {
arr[j + gap] = arr[j];
}
arr[j + gap] = temp;
}
gap = gap / 2; // 减小增量
}
}
冒泡排序
算法思想
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端,故名。
假设有一个大小为 N 的无序序列。冒泡排序就是要每趟排序过程中通过两两比较,找到第 i 个大的元素,将其往上排。
代码实现
public static void bubbleSort(int[] arr){
// 总共arr.length - 1轮
for (int i=0; i < arr.length - 1; i++) {
// 每轮比较arr.length - i - 1次
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;
}
}
}
}
快速排序
快速排序的基本思想
1、先从数列中取出一个数作为基准数
2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边
3、再对左右区间重复第二步,直到各区间只有一个数
概括来说为挖坑填数+分治法
对挖坑填数进行总结
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j–由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
代码实现
package com.sto.arithmetic;
/**
* @author yanyugang
* @description 快速排序
* 1、先从数列中取出一个数作为基准数
* 2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边
* 3、再对左右区间重复第二步,直到各区间只有一个数
*
* 挖坑填数+分治法
* @date 2019-10-16 18:32
*/
public class QuickSort {
public static void quickSort(int s[], int left, int right){
if (left < right){
// 左边下标位置
int i=left;
// 右边下标位置
int j=right;
// 基准元素
int x=s[left];
while (i < j) {
// 从右向左找第一个小于x的数
while (i < j && s[j] >= x) {
j--;
}
// 将数填到坑里
if (i < j){
s[i++]=s[j];
}
// 从左向右找第一个大于等于x的数
while (i < j && s[i] < x) {
i++;
}
// 将数填到坑里
if (i < j){
s[j--]=s[i];
}
}
// 将基准数填到坑里
s[i]=x;
//此时,i左侧的都比x小,i右侧的都比x大,以i为界,递归调用
quickSort(s, left, i - 1);
quickSort(s, i + 1, right);
}
}
public static void main(String[] args){
int[] arr= new int[]{3,3,3,7,9,122344,4656,34,34,4656,5,6,7,8,9,343,57765,23,12321};
quickSort(arr, 0, arr.length - 1);
for (int i : arr) {
System.out.print(i + "\t");
}
}
}
总结
各种排序的稳定性,时间复杂度和空间复杂度总结:
参考文档:
- https://blog.csdn.net/happy_wu/article/details/51841244
- https://blog.csdn.net/qy1387/article/details/7752973