目录
1.概念
1.1 概念
排序,就是是一串记录,按照其中的某个或某些关键字的大小,递增或递减的排序起来的操作,平时的上下文中,如果提到排序,通常指的是拍升序(非降序)
通常意义上的排序,都是指的原地排序。
1.2稳定性(重要)
两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法是具有稳定性的排序算法
1.3 应用
购物时选择价格升序降序
2.七大基于比较的排序
3.插入排序
3.1 直接插入排序-原理
整个区间被分为
1.有序区间
2.无序区间
3.2 实现
3.3 性能分析
3.4 折半插入排序(了解)
4.希尔排序
希尔排序又称缩小增量法。希尔排序的基本思想是:先选定一个整数,把持排序文件中所有记录分成个组,所有距离为的记录分在同一组,并对每一组的记录进行排序,然后取。重复上述分组和排序工作,当达到=1 时所有记录同意组内排好序
1.希尔排序是对直接插入排序的优化
2.当 gap>1时 都是预排序,目的时让数组更接近于有序,当gap == 1 时,数组已经接近有序的了,这样就会很快。
4.1 原理
4.2 实现
public static void shellSort (int[] args) {
int gap = array.length;
while (gap > 1){
insertSortGap(array,gap);
gap = (gap / 3) + 1;
}
intsertSortGap(array,1);
}
private static void insertSortGap(int[] array,int gap){
for (int i = 1; i < array.length; i++){
int v = array[i];
int j = i - gap;
for (; j >= 0 && array[j] > v; j -= gap){
array[j + gap] = array[j];
}
array[j + gap] = v;
}
}
4.3 性能分析
时间复杂度
最好O(n)
平均O(n^1.3)
最坏O (n^2)
空间复杂度
O(1)
5.选择排序
5.1 直接选择排序-原理
5.2 实现
public static void selectSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
// 无序区间: [0, array.length - i)
// 有序区间: [array.length - i, array.length)
int max = 0;
for (int j = 1; j < array.length - i; j++) {
if (array[j] > array[max]) {
max = j;
}
}
int t = array[max];
array[max] = array[array.length - i - 1];
array[array.length - i - 1] = t;
}
}
5.3 性能分析
时间复杂度:O(n^2)
空间复杂度:O(1)
5.4 双向选择排序(了解)
每一次从无序区间选出最小 + 最大元素,存放在无序区间的最前和最后,直到全部待排序的数据元素排完
6.堆排序
6.1 原理
基本原理也是选择排序,只是不在使用遍历的方式查找戊戌区间的最大的数,而是通过堆来选择无序区间的最大的数
注意: 排升序要建大堆;排降序要建小堆。
6.2 实现
public void heapSort(int[] array){
createHeap(array);
for(int i = 0; i < array.length - 1; i++){
//
//
//
swap(array,0 , array.length - 1);
//
//
//
//
shiftDown(array, array.length - i - 1, 0);
}
}
public void swap (int[] array, int i, int j) {
int t = array[i];
array[i] = array[j];
array[j] = t;
}
private void createHeap(int[] array){
for (int i = (array.length - 1) / 2; i >= 0; i--){
}
}
public static void shiftDown(int[] array,int size,int index ){}
private int index;
int left = 2 * index + 1;
while (left < size) {
int max = left;
int right = 2* index +2;
if(right < size){
if (array[index] >= array[max]){
break;
}
}
int t = array[index];
array[index] = array[max];
array[max] = t;
index = max;
left = 2 * index +1;
}
private class size {
}
6.3 性能分析
时间复杂度 O(n*log(n))
空间复杂度 O(1)
7.冒泡排序
7.1 原理
在无序区间,通过湘灵书的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序。
7.2 实现
public class bubbleSort {
public static void bubbleSort(int[] array){
for(int i = 0; j < array.length - 1; j ++){
if(array[j] > array[j + i]){
swap(array. j, j + i);
isSorted = false;
}
}
if (isSorted){
break
}
}
}
7.3 性能分析
时间复杂度:
最好:O(n)
平均: O (n^2)
最坏: O(n^2)
空间复杂度 O(1)
8.快速排序(重要)
8.1 原理-总结
1.从待排序区间选择一个属,作为基准值(pivot);
2. Partition:遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边
3.采用分治思想,对左右两个小区间按照同样的方法处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0, 代表没有数据。
public static void quickSort(int[] array) {
quickSortInternal(array, 0, array.length - 1);
}
// [left, right] 为待排序区间
private static void quickSortInternal(int[] array, int left, int right) {
if (left == right) {
return;
}
if (left > right) {
return;
}
// 最简单的选择基准值的方式,选择 array[left] 作为基准值
// pivotIndex 代表基准值最终停留的下标
int pivotIndex = partition(array, left, right);
// [left, pivotIndex - 1] 都是小于等于基准值的
// [pivotIndex + 1, right] 都是大于等于基准值的
quickSortInternal(array, left, pivotIndex - 1);
quickSortInternal(array, pivotIndex + 1, right);
}
8.2 原理-partition
实现
private static int partition(int[] array, int left, int right) {
int i = left;
int j = right;
int pivot = array[left];
while (i < j) {
while (i < j && array[j] >= pivot) {
j--;
}
while (i < j && array[i] <= pivot) {
i++;
}
swap(array, i, j);
}
swap(array, i, left);
return i;
}
挖坑法
基本思路和Hoare法一致,只是不再进行交换,而是进行赋值。
实现:
private static int partition(int[] array, int left, int right) {
int i = left;
int j = right;
int pivot = array[left];
while (i < j) {
while (i < j && array[j] >= pivot) {
j--;
}
array[i] = array[j];
while (i < j && array[i] <= pivot) {
i++;
}
array[j] = array[i];
}
array[i] = pivot;
return i;
}
前后遍历法
private static int partition(int[] array, int left, int right) {
int d = left + 1;
int pivot = array[left];
for (int i = left + 1; i <= right; i++) {
if (array[i] < pivot) {
swap(array, i, d);
d++;
}
}
swap(array, d, left);
return d;
}
8.3 性能分析
8.4 原理 基准值的选择
8.5 原理-非递归分治
public static void quickSort(int[] array) {
Stack<Integer> stack = new Stack<>();
stack.push(array.length - 1);
stack.push(0);
while (!stack.isEmpty()) {
int left = stack.pop();
int right = stack.pop();
if (left >= right) {
continue;
}
int pivotIndex = partition(array, left, right);
stack.push(right);
stack.push(pivotIndex + 1);
stack.push(pivotIndex - 1);
stack.push(left);
}
}
8.7 优化总结
8.8 总结
9.归并排序
9.1 原理-总览
归并排序是建立在归并排序操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用,将已有序列的子序列合并,得到完全有序的序列,即先使每个子序列有序,再使子序列段间有序。若将两个有序表合成一个有序表,称为二路并归。
9.2 原理-合并两个有序数组
9.3 实现
public static void mergeSort(int[] array) {
mergeSortInternal(array, 0, array.length);
}
// 待排序区间为 [low, high)
private static void mergeSortInternal(int[] array, int low, int high) {
if (low - 1 >= high) {
return;
}
int mid = (low + high) / 2;
mergeSortInternal(array, low, mid);
mergeSortInternal(array, mid, high);
merge(array, low, mid, high);
}
9.4 性能分析
时间复杂度:O(n * log(n))
空间复杂度:O(n)
9.5 优化总结
9.6 非递归版本
public static void mergeSort(int[] array) {
for (int i = 1; i < array.length; i = i * 2) {
for (int j = 0; j < array.length; j = j + 2 * i) {
int low = j;
int mid = j + i;
if (mid >= array.length) {
continue;
}
int high = mid + i;
if (high > array.length) {
high = array.length;
}
merge(array, low, mid, high);
}
}
}