基础数据
/**
* @author zhangpei
* @version 1.0
* @description 排序接口
* @date 2019/2/9
*/
public interface Sort {
void sort(int[] nums);
}
/**
* @author zhangpei
* @version 1.0
* @description 排序公共方法
* @date 2019/2/9
*/
public abstract class AbstractSort implements Sort{
/**
* @param nums 交换数组
* @param i 交换坐标i
* @param j 交换坐标j
* @description 数组交换数组
* @author zhangpe0312@qq.com
* @date 2019/2/9
*/
public void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public void run(int[] nums){
if (nums == null){
return;
}
sort(nums);
}
}
- 堆排序
随便编一个数组 int[] nums = {10, 7, 6, 3, 11, 12, 13, 5}
/**
* @author zhangpei
* @version 1.0
* @description 堆排序
* 堆排序:(大根堆)
* <p>
* ①将存放在array[0,...,n-1]中的n个元素建成初始堆;
* <p>
* ②将堆顶元素与堆底元素进行交换,则序列的最大值即已放到正确的位置;
* <p>
* ③但此时堆被破坏,将堆顶元素向下调整使其继续保持大根堆的性质,再重复第②③步,直到堆中仅剩下一个元素为止。
* <p>
* 堆排序算法的性能分析:
* <p>
* 空间复杂度:o(1);
* <p>
* 时间复杂度:建堆:o(n),每次调整o(log n),故最好、最坏、平均情况下:o(n*logn);
* <p>
* 稳定性:不稳定
* <p>
* 父节点:i==0 ? null : (i-1)/2
* 左孩子:2*i + 1
* 右孩子:2*i + 2
* @date 2019/2/10
*/
public class HeapSort extends AbstractSort {
@Override
public void sort(int[] nums) {
initHeap(nums);
int length = nums.length;
for (int i = length - 1; i > 1; i--) {
swap(nums, 0, i);
adjustDownToUp(nums, 0, i);
}
}
/**
* @param nums 北条政数组
* @description 初始化最大堆
* @author zhangpe0312@qq.com
* @date 2019/2/10
*/
public void initHeap(int[] nums) {
int length = nums.length;
// 首先定位到最后一个父节点,然后依次调整(如果不明白请用手画出来自己看,必须从最后一个父节点开始往上查,最终的结果就是初始化好一个最大堆)
for (int i = (length - 2) / 2; i >= 0; i--) {
adjustDownToUp(nums, i, length);
}
}
/**
* @param nums 数组
* @param k 需要调整的节点,这是一个父节点
* @description 自下而上的调整堆
* @author zhangpe0312@qq.com
* @date 2019/2/10
*/
private void adjustDownToUp(int[] nums, int k, int length) {
// 父节点值
int temp = nums[k];
// 从左孩子开始比较,比较步长为下一个左孩子,也就是左孩子的左孩子
for (int i = 2 * k + 1; i < length - 1; i = 2 * i + 1) {
// 1. 左孩子存在 2. 左孩子小于右孩子,则坐标记录为右孩子的值
if (i < length && nums[i] < nums[i + 1]) {
i++;
}
// 如果当前父节点小于其中的最大值
if (temp < nums[i]) {
// 将左右子结点中较大值array[i]调整到双亲节点上
nums[k] = nums[i];
// 更新父节点,为后续调准赋值
k = i;
}
}
//被调整的结点的值放人最终位置
nums[k] = temp;
}
}
- 快速排序
采用分而治之的方法
随便编一个数组 int[] nums = {10, 7, 6, 3, 11, 12, 13, 5}
/**
* @author zhangpei
* @version 1.0
* @description 快速排序
* @date 2019/2/9
*/
public class QuickSort extends AbstractSort {
@Override
public void sort(int[] nums) {
runSort(0, nums.length - 1, nums);
}
public void runSort(int start, int end, int[] num) {
if (start >= end) {
return;
}
// 获取到新一轮的哨兵
int index = sort(start, end, num);
// 左边
runSort(start, index - 1, num);
// 右边
runSort(index + 1, end, num);
}
/**
* 一轮划分
*
* @param start 开始坐标
* @param end 结束坐标
* @param num 排序数组
*/
public int sort(int start, int end, int[] num) {
// 哨兵数据
int flag = num[start];
// 方法体中计算的局部变量
// 用于计算扫描的左指针和又指针的位置,当左指针位置大于又指针的时候,则退出循环
int tempStart = start;
int tempEnd = end + 1;
while (true) {
// 当哨兵大于左指针的数据时不做处理
// 只有当左指针大于哨兵的时候退出并记录当前指针用于后续交换数据
// 适用于升序排序
while (num[++tempStart] < flag) {
if (tempStart >= end) {
break;
}
}
// 和左指针差不多的道理
while (num[--tempEnd] > flag) {
if (tempEnd <= start) {
break;
}
}
// 如果左指针大于右指针说明此轮交换结束
if (tempStart >= tempEnd) {
break;
}
// 交换位置
swap(num, tempStart, tempEnd);
}
// 将哨兵放在合适的位置
swap(num, start, tempEnd);
return tempEnd;
}
}