feat: 修改了LeetCode912_SortArrays和LeetCode215的快速排序算法,并添加了堆排序算法的实现。同时,增加了相关测试用例。

This commit is contained in:
whaifree 2024-08-31 14:38:22 +08:00
parent 4895af547b
commit ae7654ad39
2 changed files with 369 additions and 67 deletions

View File

@ -6,9 +6,132 @@ import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Random;
import static org.junit.Assert.assertArrayEquals;
public class LeetCode215 {
@Test
public void sort_EmptyArray_ShouldHandleGracefull3y() {
int[] nums = {3,2,1,5,6,4};
System.out.println(new Solution5().findKthLargest(nums, 2));
System.out.println(Arrays.toString(nums));
}
class Solution5 {
/**
* 快速排序某次base放对位置后左边刚刚好有k-1个就找到了
* @param nums
* @param k
* @return
*/
public int findKthLargest(int[] nums, int k) {
return sort(nums, 0, nums.length - 1, k);
}
/**
* 快速排序思路对前n-1个进行不断交换最后把基准替换到交接点
* @param nums
* @param start
* @param end
* @param k
* @return
*/
public int sort(int[] nums, int start, int end, int k) {
if (start > end) {
return nums[end];
}
int q = new Random().nextInt(end - start + 1) + start;
swap(nums, q, end);
int base = nums[end];
int left = start;
int right = end;
while (left < right) {
//从左往右遍历当左指针指向的元素小于等于基数时i++左指针持续向右移动
while (nums[left] >= base && left < right) {
left++;
}
//从右往左遍历当右指针指向的元素大于等于基数时j--右指针持续向左移动
while (nums[right] <= base && left < right) {
right--;
}
if (left < right) {
//当左右两个指针停下来时交换两个元素
swap(nums, left, right);
}
}
swap(nums, left, end);
// 从大到小排序如果左边k-1个则left就是第k个左边k-1个比他大
if (left == k - 1) {
return nums[left];
}
// 左边的数量太少了往右边找
if (left < k - 1) {
return sort(nums, left + 1, end, k);
}
return sort(nums, start, left - 1, k);
}
public void swap(int[] heap, int start, int end) {
int temp = heap[start];
heap[start] = heap[end];
heap[end] = temp;
}
}
@Test
public void sort_EmptyArray_ShouldHandleGracefully8() {
// [3,2,3,1,2,4,5,5,6], k = 4
int[] nums = {5,4,3,2,1};
System.out.println(new Solution4().findKthLargest(nums, 2));
}
class Solution4 {
public int findKthLargest(int[] nums, int k) {
for (int i = nums.length - 1; i > 0; i--) {
shiftUp(nums, i);
}
System.out.println(Arrays.toString(nums));
return nums[nums.length - k];
}
public void shiftUp(int[] heap, int end) {
int parent = (end - 1) / 2;
while (parent >= 0) {
int left = parent * 2 + 1;
int right = parent * 2 + 2;
int k = parent;
if (left <= end &&heap[left] > heap[k]) {
k = left;
}
if (right <= end && heap[right] > heap[k]) {
k = right;
}
swap(heap, parent, k);
parent--;
}
swap(heap, 0, end);
}
public void swap(int[] heap, int start, int end) {
int temp = heap[start];
heap[start] = heap[end];
heap[end] = temp;
}
}
@Test
public void main()
{
@ -25,7 +148,7 @@ public class LeetCode215 {
}
@Test
public void test1()
public void test188()
{
new sol().findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 3);
@ -123,52 +246,231 @@ public class LeetCode215 {
}
@Test
public void test()
public void test1()
{
int[] nums = {3,2,1,5,6,4};
sort(nums);
int k = 2;
Solution1 solution = new Solution1();
int i = solution.findKthLargest(nums, k);
System.out.println(i);
}
class Solution1 {
public int findKthLargest(int[] nums, int k) {
sort(nums, nums.length - 1);
return nums[k - 1];
}
/**
* 所有非叶子节点x n/2 开始表示下面都是叶子节点找到子节点中的最大值如果比x 还大swap再排序下一个非叶子节点
* 堆排序思路
* 1. 依次遍历非叶节点 nonLeaf = (end - 1) / 2; --
* 选取左右两边比他大的替换上来不断替换直到最上面是最大的
* 2. 把最大的堆顶移动到最后确定一个最大值
* @param nums
* @param end
*/
public void sort(int[] nums) {
sort(nums, nums.length - 1);
System.out.println(Arrays.toString(nums));
public void sort(int[] nums, int end) {
if (end <= 0) {
return;
}
int heapSize = nums.length;
for (int i = heapSize / 2; i >= 0; --i) {
int l = i * 2 + 1, r = i * 2 + 2, largest = i;
if (l < heapSize && nums[l] > nums[largest]) {
largest = l;
}
if (r < heapSize && nums[r] > nums[largest]) {
largest = r;
}
if (largest != i) {
swap(nums, i, largest);
sort(nums, heapSize - 1);
}
}
swap(nums, 0, end);
}
public void swap(int[] nums, int start, int end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
}
}
@Test
public void sort_EmptyArray_ShouldHandleGracefully() {
int[] nums = {};
sort(nums);
assertArrayEquals(new int[0], nums);
}
@Test
public void sort_NaturalNumberArray_ShouldSortInAscendingOrder() {
int[] nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
sort(nums);
assertArrayEquals(new int[]{1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9}, nums);
}
@Test
public void sort_IntegerArray_ShouldSortInAscendingOrder() {
int[] nums = {10, -1, 2, 5, 0, 6, -3, 4};
sort(nums);
assertArrayEquals(new int[]{-3, -1, 0, 2, 4, 5, 6, 10}, nums);
}
@Test
public void sort_SingleElementArray_ShouldRemainUnchanged() {
int[] nums = {5};
sort(nums);
assertArrayEquals(new int[]{5}, nums);
}
@Test
public void sort_DuplicateElementsArray_ShouldSortInAscendingOrder() {
int[] nums = {4, 2, 2, 8, 3, 3, 1};
sort(nums);
assertArrayEquals(new int[]{1, 2, 2, 3, 3, 4, 8}, nums);
}
@Test
public void sort_NegativeNumberArray_ShouldSortInAscendingOrder() {
int[] nums = {-1, -2, -3, -4, -5};
System.out.println(Arrays.toString(new Solution3().sortArray(nums)));
}
class Solution3 {
public int[] sortArray(int[] nums) {
sort(nums, nums.length - 1);
return nums;
}
/**
* 堆排序思路
* 1. 依次遍历非叶节点 nonLeaf = (end - 1) / 2; --
* 选取左右两边比他大的替换上来不断替换直到最上面是最大的
* 2. 把最大的堆顶移动到最后确定一个最大值
* @param nums
* @param end
*/
public void sort(int[] nums, int end) {
if (end < 0) {
if (end <= 0) {
return;
}
int nonLeaf = (end) / 2;
int nonLeaf = (end - 1) / 2;
while (nonLeaf >= 0) {
TreeNode.constructTreeByArrayWithInteger(nums).printTree();
int left = 2 * nonLeaf + 1;
int right = 2 * nonLeaf + 2;
if (left <= end &&right <= end) {
if (nums[left] < nums[right]) {
if (nums[right] > nums[nonLeaf]) {
swap(nums, nonLeaf, right);
}
}else {
if (nums[left] > nums[nonLeaf]) {
swap(nums, nonLeaf, left);
}
}
} else if (left <= end) {
if (nums[left] < nums[right]) {
if (nums[right] > nums[nonLeaf]) {
swap(nums, nonLeaf, right);
}
}
}else if (right <= end){
int maxIn = nonLeaf; // 父子三个节点的最大值
if (left <= end && nums[maxIn] < nums[left]) {
maxIn = left;
}
if (right <= end && nums[maxIn] < nums[right]) {
maxIn = right;
}
swap(nums, nonLeaf, maxIn);
// // noleaf至少有一个子节点
// if (left <= end &&right <= end) {
// if (nums[left] < nums[right]) {
// if (nums[right] > nums[nonLeaf]) {
// swap(nums, nonLeaf, right);
// }
// }else {
// if (nums[left] > nums[nonLeaf]) {
// swap(nums, nonLeaf, left);
// }
// }
// } else {
// // 只有左边一个节点
// if (nums[left] > nums[nonLeaf]) {
// swap(nums, nonLeaf, left);
// }
// }
nonLeaf--;
}
swap(nums, 0, end );
sort(nums, end - 1);
}
public void swap(int[] nums, int start, int end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
}
}
/**
* 所有非叶子节点x n/2 开始表示下面都是叶子节点找到子节点中的最大值如果比x 还大swap再排序下一个非叶子节点
*/
public void sort(int[] nums) {
sort(nums, nums.length - 1);
System.out.println(Arrays.toString(nums));
}
/**
* 堆排序思路
* 1. 依次遍历非叶节点 nonLeaf = (end - 1) / 2; --
* 选取左右两边比他大的替换上来不断替换直到最上面是最大的
* 2. 把最大的堆顶移动到最后确定一个最大值
* @param nums
* @param end
*/
public void sort(int[] nums, int end) {
if (end <= 0) {
return;
}
int nonLeaf = (end - 1) / 2;
while (nonLeaf >= 0) {
int left = 2 * nonLeaf + 1;
int right = 2 * nonLeaf + 2;
int maxIn = nonLeaf; // 父子三个节点的最大值
if (left <= end && nums[maxIn] < nums[left]) {
maxIn = left;
}
if (right <= end && nums[maxIn] < nums[right]) {
maxIn = right;
}
swap(nums, nonLeaf, maxIn);
// // noleaf至少有一个子节点
// if (left <= end &&right <= end) {
// if (nums[left] < nums[right]) {
// if (nums[right] > nums[nonLeaf]) {
// swap(nums, nonLeaf, right);
// }
// }else {
// if (nums[left] > nums[nonLeaf]) {
// swap(nums, nonLeaf, left);
// }
// }
// } else {
// // 只有左边一个节点
// if (nums[left] > nums[nonLeaf]) {
// swap(nums, nonLeaf, left);
// }
// }
nonLeaf--;
}
swap(nums, 0, end );

View File

@ -242,47 +242,47 @@ class QuickSort{
}
}
class Solution11 {
public int[] sortArray(int[] nums) {
quick_sort(nums, 0, nums.length - 1);
return nums;
}
private void quick_sort(int[] nums, int left, int right) {
if (left >= right) {
return;
}
int i = left;
int j = right;
//! 随机挑选一个幸运儿
int q = new Random().nextInt(right - left + 1) + left;
swap(nums, right, q);
while (i < j) {
while (nums[i] <= nums[right] && i < j) {
i++;
}
while (nums[right] >= nums[left] && i < j) {
j--;
}
swap(nums, i, j);
}
swap(nums, i, right);
quick_sort(nums, left, i - 1);
quick_sort(nums, i + 1, right);
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
// class Solution11 {
// public int[] sortArray(int[] nums) {
// quick_sort(nums, 0, nums.length - 1);
// return nums;
// }
//
// private void quick_sort(int[] nums, int left, int right) {
// if (left >= right) {
// return;
// }
//
//
// int i = left;
// int j = right;
// //! 随机挑选一个幸运儿
// int q = new Random().nextInt(right - left + 1) + left;
// swap(nums, right, q);
//
// while (i < j) {
// while (nums[i] <= nums[right] && i < j) {
// i++;
// }
// while (nums[right] >= nums[left] && i < j) {
// j--;
// }
// swap(nums, i, j);
// }
//
// swap(nums, i, right);
//
//
// quick_sort(nums, left, i - 1);
// quick_sort(nums, i + 1, right);
// }
//
//
//
// private void swap(int[] nums, int i, int j) {
// int temp = nums[i];
// nums[i] = nums[j];
// nums[j] = temp;
// }
// }
}