七日算法先导(六)——堆排序,桶排序
【摘要】 前言所学前面我们学习了归并,希尔俩个排序,下面由这张图来总结一下八大排序可能有的小伙伴会说,学这些排序有什么用,平时开发也用不到,但是我的理解是这样的:锻炼思维,排序中蕴含的思维很多,双指针,递归,分治等等普及常识性问题面试,区分人才 堆排序堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆 大顶堆,小顶堆当所有...
前言所学
前面我们学习了归并,希尔俩个排序,下面由这张图来总结一下八大排序
可能有的小伙伴会说,学这些排序有什么用,平时开发也用不到,但是我的理解是这样的:
- 锻炼思维,排序中蕴含的思维很多,双指针,递归,分治等等
- 普及常识性问题
- 面试,区分人才
堆排序
堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆
大顶堆,小顶堆
当所有根节点的值,都大于它子节点的值,我们称为大顶(根)堆
当所有根节点的值,都小于它子节点的值,我们称为小顶(根)堆
思路及动画演示
-
对原数组构建成大顶堆。
-
交换头尾值,尾指针索引减一,固定最大值。
-
重新构建大顶堆。
-
重复步骤2,3直到最后一个元素排序完成。
代码实现
public class HeapSort extends BaseSort {
public static void main(String[] args) {
HeapSort sort = new HeapSort();
sort.printNums();
}
@Override
protected void sort(int[] nums) {
if (nums == null || nums.length < 2) {
return;
}
heapSort(nums);
}
private void heapSort(int[] nums) {
if (nums == null || nums.length < 2) {
return;
}
//构建大根堆
createTopHeap(nums);
int size = nums.length;
while (size > 1) {
//大根堆的交换头尾值,固定最大值在末尾
swap(nums, 0, size - 1);
//末尾的索引值往左减1
size--;
//重新构建大根堆
updateHeap(nums, size);
}
}
private void createTopHeap(int[] nums) {
for (int i = 0; i < nums.length; i++) {
//当前插入的索引
int currIndex = i;
//父节点的索引
int parentIndex = (currIndex - 1) / 2;
//如果当前遍历的值比父节点大的话,就交换值。然后继续往上层比较
while (nums[currIndex] > nums[parentIndex]) {
//交换当前遍历的值与父节点的值
swap(nums, currIndex, parentIndex);
//把父节点的索引指向当前遍历的索引
currIndex = parentIndex;
//往上计算父节点索引
parentIndex = (currIndex - 1) / 2;
}
}
}
private void updateHeap(int[] nums, int size) {
int index = 0;
//左节点索引
int left = 2 * index + 1;
//右节点索引
int right = 2 * index + 2;
while (left < size) {
//最大值的索引
int largestIndex;
//如果右节点大于左节点,则最大值索引指向右子节点索引
if (right < size && nums[left] < nums[right]) {
largestIndex = right;
} else {
largestIndex = left;
}
//如果父节点大于最大值,则把父节点索引指向最大值索引
if (nums[index] > nums[largestIndex]) {
largestIndex = index;
}
//如果父节点索引指向最大值索引,证明已经是大根堆,退出循环
if (largestIndex == index) {
break;
}
//如果不是大根堆,则交换父节点的值
swap(nums, largestIndex, index);
//把最大值的索引变成父节点索引
index = largestIndex;
//重新计算左节点索引
left = 2 * index + 1;
//重新计算右节点索引
right = 2 * index + 2;
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
桶排序
过程
排序过程:
(1)设置一个定量的数组当作空桶子;
(2)寻访序列,并且把记录一个一个放到对应的桶子去;
(3)对每个不是空的桶子进行排序。
(4)从不是空的桶子里把项目再放回原来的序列中。
代码实现
public class BucketSort extends BaseSort {
public static void main(String[] args) {
BucketSort sort = new BucketSort();
sort.printNums();
}
@Override
protected void sort(int[] nums) {
if (nums == null || nums.length < 2) {
return;
}
bucketSort(nums);
}
public void bucketSort(int[] nums) {
if (nums == null || nums.length < 2) {
return;
}
//找出最大值,最小值
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int num : nums) {
min = Math.min(min, num);
max = Math.max(max, num);
}
int length = nums.length;
//桶的数量
int bucketCount = (max - min) / length + 1;
int[][] bucketArrays = new int[bucketCount][];
//遍历数组,放入桶内
for (int i = 0; i < length; i++) {
//找到桶的下标
int index = (nums[i] - min) / length;
//添加到指定下标的桶里,并且使用插入排序排序
bucketArrays[index] = insertSortArrays(bucketArrays[index], nums[i]);
}
int k = 0;
//合并全部桶的
for (int[] bucketArray : bucketArrays) {
if (bucketArray == null || bucketArray.length == 0) {
continue;
}
for (int i : bucketArray) {
//把值放回到nums数组中
nums[k++] = i;
}
}
}
//每个桶使用插入排序进行排序
private int[] insertSortArrays(int[] arr, int num) {
if (arr == null || arr.length == 0) {
return new int[]{num};
}
//创建一个temp数组,长度是arr数组的长度+1
int[] temp = new int[arr.length + 1];
//把传进来的arr数组,复制到temp数组
for (int i = 0; i < arr.length; i++) {
temp[i] = arr[i];
}
//找到一个位置,插入,形成新的有序的数组
int i;
for (i = temp.length - 2; i >= 0 && temp[i] > num; i--) {
temp[i + 1] = temp[i];
}
//插入需要添加的值
temp[i + 1] = num;
//返回
return temp;
}
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)