- 这三种排序算法平均时间复杂度都是O(n*log(n))。
- 其中快排和堆排序是不稳定,归并排序是稳定的。
快排递归版本
- 快排是我们必须要掌握的排序算法之一,面试也是常问的考点。快排的思想时采用双指针和选取key不断地去交替值,达到👈为小于key的值;👉为大于key的值。这样说很抽象,直接上代码了。
- 本方法写的还有点小优化,比传统快排的值的替换的次数少。
import java.util.Arrays;
/**
* @author: linjianshan
* @date: 2020/8/15
* @description: top.san.java.algorithm.sort
* @version: 1.0
* 快速排序
*/
public class QuickSort {
static int[] sq = new int[]{10, 56, 32, 564, 86, 325, 45, 69, 32, 5, 6, 3, 4, 45, 41, 414, 141, 415, 145, 5414, 848471, 8, 191, 9, 191, 656156};
public static void main(String[] args) {
new QuickSort().quickSort(sq, 0, sq.length - 1);
System.out.println(Arrays.toString(sq));
}
public void quickSort(int[] arr, int left, int right) {
int l = left;
int r = right;
int mid = arr[(l + r)/2];
while (l < r){
while (arr[l] < mid){
l += 1;
}
while (arr[r] > mid){
r -= 1;
}
//l >=r 表示已排好序了
if (l >= r){
break;
}
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//arr[l]则表明右边排好了,到达了mid这个结点,才会把mid换给左边
if (arr[l] == mid){
r -= 1;
}
//相反
if (arr[r] == mid){
l += 1;
}
}
//不加会递归出不去。
if (l == r){
l += 1;
r -= 1;
}
if (left < r){
quickSort(arr,left,r);
}
if (l < right){
quickSort(arr,l,right);
}
}
}
快排非递归版本
- 基于递归版本推出的非递归版本,因为递归都是使用栈来实现的,我直接使用栈来存取中间变化的量,即可实现非递归版本。
import java.util.Arrays;
import java.util.Stack;
/**
* @author: linjianshan
* @date: 2020/8/19
* @description: top.san.java.algorithm.sort
* @version: 1.0
*/
public class QuickSort0819 {
static int[] sq = new int[]{10, 56, 32, 564, 86, 325, 45, 69, 32, 5, 6, 3, 4, 45, 41, 414, 141, 415, 145, 5414, 848471, 8, 191, 9, 191, 656156};
public static void main(String[] args) {
Stack stack = new Stack();
stack.push(0);
stack.push(sq.length-1);
quickSort0819(sq,stack);
System.out.println(Arrays.toString(sq));
}
public static void quickSort0819(int[] arr, Stack stack){
while (!stack.empty()){
int right = (int) stack.pop();
int r = right;
int left = (int) stack.pop();
int l = left;
int midValue = arr[(l+r)/2];
while (l < r){
while (arr[l] < midValue){
l++;
}
while (arr[r] > midValue){
r--;
}
if (l >= r){
break;
}
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
if (arr[l] == midValue){
r--;
}else if (arr[r] == midValue){
l++;
}
}
if (l == r){
l++;
r--;
}
if (left < r){
stack.push(left);
stack.push(r);
}
if (l < right){
stack.push(l);
stack.push(right);
}
}
}
}
归并排序
归并排序主要是利用分治的思想,先逻辑上将排列数拆成当个,再不断地合并成一个数列,且得到的数列是不断的排序得到的有序序列。
import java.util.Arrays;
/**
* @author: linjianshan
* @date: 2020/8/17
* @description: top.san.java.algorithm.sort
* @version: 1.0
* 分治思想
*/
public class MergetSort0817 {
static int[] sq = new int[]{10, 56, 32, 564, 86, 325, 45, 69, 32, 5, 6, 3, 4, 45, 41, 414, 141, 415, 145, 5414, 848471, 8, 191, 9, 191, 656156};
public static void main(String[] args) {
int[] temp = new int[sq.length];
mergetSort(sq, 0, sq.length - 1, temp);
System.out.println(Arrays.toString(sq));
}
public static void mergetSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
//向左分
mergetSort(arr, left, mid, temp);
//向右分
mergetSort(arr, mid + 1, right, temp);
//从被分到的最小快开始合并
merget(arr, left, mid, right, temp);
}
}
public static void merget(int[] arr, int left, int mid, int right, int[] temp) {
int ls = left; //块的左边开始
int rs = mid+1; //快的右边开始
int t = 0; //记录数组的起始结点
//遍历寻找某块左右两边的最小值首先放入temp
while (ls <= mid && rs <= right) {
if (arr[ls] < arr[rs]) {
temp[t++] = arr[ls++];
} else {
temp[t++] = arr[rs++];
}
}
//某一块的左右两边某一边遍历完,说明另一边剩下的全是有序的,且比较大 左边
while (ls <= mid) {
temp[t++] = arr[ls++];
}
//某一块的左右两边某一边遍历完,说明另一边剩下的全是有序的,且比较大 右边
while (rs <= right) {
temp[t++] = arr[rs++];
}
//将记录再temp的有序序列赋值回传入的块当中
ls = left;
t = 0;
while (ls <= right) {
arr[ls++] = temp[t++];
}
}
}
堆排序
- 堆排序是数组序列借助了树的思想去排列,其中大顶堆满足arr[i] >arr[2i+1]&&arr[i] > arr[2i+2]。
package top.san.java.algorithm.sort;
import java.util.Arrays;
/**
* @author: linjianshan
* @date: 2020/8/18
* @description: top.san.java.algorithm.sort
* @version: 1.0
*/
public class HeapSort0818 {
static int[] sq = new int[]{10, 56, 32, 564, 86, 325, 45, 69, 32, 5, 6, 3, 4, 45, 41, 414, 141, 415, 145, 5414, 848471, 8, 191, 9, 191, 656156};
public static void main(String[] args) {
heapSort0818(sq);
System.out.println(Arrays.toString(sq));
}
public static void heapSort0818(int[] arr) {
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap0818(arr, i, arr.length);
}
for (int j = arr.length - 1; j >= 0; j--) {
int temp = arr[0];
arr[0] = arr[j];
arr[j] = temp;
adjustHeap0818(arr, 0, j);
}
}
//大顶堆的建立
public static void adjustHeap0818(int[] arr, int start, int end) {
int temp = arr[start];
for (int k = start * 2 + 1; k < end; k = k * 2 + 1) {
//<1>这里逻辑arr[k] < arr[k + 1]改arr[k] > arr[k + 1]
if (k + 1 < end && arr[k] < arr[k + 1]) {
k++;
}
//<2>这里逻辑arr[k] < temp改arr[k] < temp ,结合<1>可以构建小顶堆
if (arr[k] > temp) {
//先让大的上去,k的位置不用赋值,因为下面start指针的位移和arr[k] > temp的判断已经决定了arr[k]逻辑上是arr[start]
arr[start] = arr[k];
start = k;
}
}
arr[start] = temp;
}
}