Re-implement merge sort function. (#888)

This commit is contained in:
Yudong Jin 2023-10-26 02:56:33 +08:00 committed by GitHub
parent 7822bf9cd4
commit e441ee4e35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 186 additions and 181 deletions

View file

@ -7,33 +7,34 @@
#include "../utils/common.h" #include "../utils/common.h"
/* 合并左子数组和右子数组 */ /* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
void merge(int *nums, int left, int mid, int right) { void merge(int *nums, int left, int mid, int right) {
int index; // 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
// 初始化辅助数组 // 创建一个临时数组 tmp ,用于存放合并后的结果
int tmp[right + 1 - left]; int tmpSize = right - left + 1;
for (index = left; index < right + 1; index++) { int *tmp = (int *)malloc(tmpSize * sizeof(int));
tmp[index - left] = nums[index]; // 初始化左子数组和右子数组的起始索引
int i = left, j = mid + 1, k = 0;
// 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
tmp[k++] = nums[i++];
} else {
tmp[k++] = nums[j++];
} }
// 左子数组的起始索引和结束索引
int leftStart = left - left, leftEnd = mid - left;
// 右子数组的起始索引和结束索引
int rightStart = mid + 1 - left, rightEnd = right - left;
// i, j 分别指向左子数组、右子数组的首元素
int i = leftStart, j = rightStart;
// 通过覆盖原数组 nums 来合并左子数组和右子数组
for (int k = left; k <= right; k++) {
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
if (i > leftEnd)
nums[k] = tmp[j++];
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
else if (j > rightEnd || tmp[i] <= tmp[j])
nums[k] = tmp[i++];
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
else
nums[k] = tmp[j++];
} }
// 将左子数组和右子数组的剩余元素复制到临时数组中
while (i <= mid) {
tmp[k++] = nums[i++];
}
while (j <= right) {
tmp[k++] = nums[j++];
}
// 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for (k = 0; k < tmpSize; ++k) {
nums[left + k] = tmp[k];
}
// 释放内存
free(tmp);
} }
/* 归并排序 */ /* 归并排序 */

View file

@ -7,28 +7,29 @@
#include "../utils/common.hpp" #include "../utils/common.hpp"
/* 合并左子数组和右子数组 */ /* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
void merge(vector<int> &nums, int left, int mid, int right) { void merge(vector<int> &nums, int left, int mid, int right) {
// 初始化辅助数组 // 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
vector<int> tmp(nums.begin() + left, nums.begin() + right + 1); // 创建一个临时数组 tmp ,用于存放合并后的结果
// 左子数组的起始索引和结束索引 vector<int> tmp(right - left + 1);
int leftStart = left - left, leftEnd = mid - left; // 初始化左子数组和右子数组的起始索引
// 右子数组的起始索引和结束索引 int i = left, j = mid + 1, k = 0;
int rightStart = mid + 1 - left, rightEnd = right - left; // 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
// i, j 分别指向左子数组、右子数组的首元素 while (i <= mid && j <= right) {
int i = leftStart, j = rightStart; if (nums[i] <= nums[j])
// 通过覆盖原数组 nums 来合并左子数组和右子数组 tmp[k++] = nums[i++];
for (int k = left; k <= right; k++) {
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
if (i > leftEnd)
nums[k] = tmp[j++];
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
else if (j > rightEnd || tmp[i] <= tmp[j])
nums[k] = tmp[i++];
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
else else
nums[k] = tmp[j++]; tmp[k++] = nums[j++];
}
// 将左子数组和右子数组的剩余元素复制到临时数组中
while (i <= mid) {
tmp[k++] = nums[i++];
}
while (j <= right) {
tmp[k++] = nums[j++];
}
// 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for (k = 0; k < tmp.size(); k++) {
nums[left + k] = tmp[k];
} }
} }

View file

@ -8,28 +8,29 @@ namespace hello_algo.chapter_sorting;
public class merge_sort { public class merge_sort {
/* 合并左子数组和右子数组 */ /* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
static void Merge(int[] nums, int left, int mid, int right) { static void Merge(int[] nums, int left, int mid, int right) {
// 初始化辅助数组 // 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
int[] tmp = nums[left..(right + 1)]; // 创建一个临时数组 tmp ,用于存放合并后的结果
// 左子数组的起始索引和结束索引 int[] tmp = new int[right - left + 1];
int leftStart = left - left, leftEnd = mid - left; // 初始化左子数组和右子数组的起始索引
// 右子数组的起始索引和结束索引 int i = left, j = mid + 1, k = 0;
int rightStart = mid + 1 - left, rightEnd = right - left; // 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
// i, j 分别指向左子数组、右子数组的首元素 while (i <= mid && j <= right) {
int i = leftStart, j = rightStart; if (nums[i] <= nums[j])
// 通过覆盖原数组 nums 来合并左子数组和右子数组 tmp[k++] = nums[i++];
for (int k = left; k <= right; k++) {
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
if (i > leftEnd)
nums[k] = tmp[j++];
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
else if (j > rightEnd || tmp[i] <= tmp[j])
nums[k] = tmp[i++];
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
else else
nums[k] = tmp[j++]; tmp[k++] = nums[j++];
}
// 将左子数组和右子数组的剩余元素复制到临时数组中
while (i <= mid) {
tmp[k++] = nums[i++];
}
while (j <= right) {
tmp[k++] = nums[j++];
}
// 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for (k = 0; k < tmp.Length; ++k) {
nums[left + k] = tmp[k];
} }
} }

View file

@ -5,35 +5,37 @@
package chapter_sorting package chapter_sorting
/* 合并左子数组和右子数组 */ /* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
func merge(nums []int, left, mid, right int) { func merge(nums []int, left, mid, right int) {
// 初始化辅助数组 借助 copy 模块 // 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
// 创建一个临时数组 tmp ,用于存放合并后的结果
tmp := make([]int, right-left+1) tmp := make([]int, right-left+1)
for i := left; i <= right; i++ { // 初始化左子数组和右子数组的起始索引
tmp[i-left] = nums[i] i, j, k := left, mid+1, 0
} // 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
// 左子数组的起始索引和结束索引 for i <= mid && j <= right {
leftStart, leftEnd := left-left, mid-left if nums[i] <= nums[j] {
// 右子数组的起始索引和结束索引 tmp[k] = nums[i]
rightStart, rightEnd := mid+1-left, right-left
// i, j 分别指向左子数组、右子数组的首元素
i, j := leftStart, rightStart
// 通过覆盖原数组 nums 来合并左子数组和右子数组
for k := left; k <= right; k++ {
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
if i > leftEnd {
nums[k] = tmp[j]
j++
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
} else if j > rightEnd || tmp[i] <= tmp[j] {
nums[k] = tmp[i]
i++ i++
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
} else { } else {
nums[k] = tmp[j] tmp[k] = nums[j]
j++ j++
} }
k++
}
// 将左子数组和右子数组的剩余元素复制到临时数组中
for i <= mid {
tmp[k] = nums[i]
i++
k++
}
for j <= right {
tmp[k] = nums[j]
j++
k++
}
// 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for k := 0; k < len(tmp); k++ {
nums[left+k] = tmp[k]
} }
} }

View file

@ -10,28 +10,29 @@ import java.util.*;
public class merge_sort { public class merge_sort {
/* 合并左子数组和右子数组 */ /* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
static void merge(int[] nums, int left, int mid, int right) { static void merge(int[] nums, int left, int mid, int right) {
// 初始化辅助数组 // 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
int[] tmp = Arrays.copyOfRange(nums, left, right + 1); // 创建一个临时数组 tmp 用于存放合并后的结果
// 左子数组的起始索引和结束索引 int[] tmp = new int[right - left + 1];
int leftStart = left - left, leftEnd = mid - left; // 初始化左子数组和右子数组的起始索引
// 右子数组的起始索引和结束索引 int i = left, j = mid + 1, k = 0;
int rightStart = mid + 1 - left, rightEnd = right - left; // 当左右子数组都还有元素时比较并将较小的元素复制到临时数组中
// i, j 分别指向左子数组右子数组的首元素 while (i <= mid && j <= right) {
int i = leftStart, j = rightStart; if (nums[i] <= nums[j])
// 通过覆盖原数组 nums 来合并左子数组和右子数组 tmp[k++] = nums[i++];
for (int k = left; k <= right; k++) {
// 左子数组已全部合并完则选取右子数组元素并且 j++
if (i > leftEnd)
nums[k] = tmp[j++];
// 否则右子数组已全部合并完左子数组元素 <= 右子数组元素则选取左子数组元素并且 i++
else if (j > rightEnd || tmp[i] <= tmp[j])
nums[k] = tmp[i++];
// 否则左右子数组都未全部合并完左子数组元素 > 右子数组元素则选取右子数组元素并且 j++
else else
nums[k] = tmp[j++]; tmp[k++] = nums[j++];
}
// 将左子数组和右子数组的剩余元素复制到临时数组中
while (i <= mid) {
tmp[k++] = nums[i++];
}
while (j <= right) {
tmp[k++] = nums[j++];
}
// 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for (k = 0; k < tmp.length; k++) {
nums[left + k] = tmp[k];
} }
} }

View file

@ -5,33 +5,33 @@
*/ */
/* 合并左子数组和右子数组 */ /* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
function merge(nums, left, mid, right) { function merge(nums, left, mid, right) {
// 初始化辅助数组 // 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
let tmp = nums.slice(left, right + 1); // 创建一个临时数组 tmp ,用于存放合并后的结果
// 左子数组的起始索引和结束索引 const tmp = new Array(right - left + 1);
let leftStart = left - left, // 初始化左子数组和右子数组的起始索引
leftEnd = mid - left; let i = left,
// 右子数组的起始索引和结束索引 j = mid + 1,
let rightStart = mid + 1 - left, k = 0;
rightEnd = right - left; // 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
// i, j 分别指向左子数组、右子数组的首元素 while (i <= mid && j <= right) {
let i = leftStart, if (nums[i] <= nums[j]) {
j = rightStart; tmp[k++] = nums[i++];
// 通过覆盖原数组 nums 来合并左子数组和右子数组
for (let k = left; k <= right; k++) {
if (i > leftEnd) {
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
nums[k] = tmp[j++];
} else if (j > rightEnd || tmp[i] <= tmp[j]) {
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
nums[k] = tmp[i++];
} else { } else {
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ tmp[k++] = nums[j++];
nums[k] = tmp[j++];
} }
} }
// 将左子数组和右子数组的剩余元素复制到临时数组中
while (i <= mid) {
tmp[k++] = nums[i++];
}
while (j <= right) {
tmp[k++] = nums[j++];
}
// 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for (k = 0; k < tmp.length; k++) {
nums[left + k] = tmp[k];
}
} }
/* 归并排序 */ /* 归并排序 */

View file

@ -1,39 +1,38 @@
""" """
File: merge_sort.py File: merge_sort.py
Created Time: 2022-11-25 Created Time: 2022-11-25
Author: timi (xisunyy@163.com) Author: timi (xisunyy@163.com), Krahets (krahets@163.com)
""" """
def merge(nums: list[int], left: int, mid: int, right: int): def merge(nums: list[int], left: int, mid: int, right: int):
"""合并左子数组和右子数组""" """合并左子数组和右子数组"""
# 左子数组区间 [left, mid] # 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
# 右子数组区间 [mid + 1, right] # 创建一个临时数组 tmp ,用于存放合并后的结果
# 初始化辅助数组 tmp = [0] * (right - left + 1)
tmp = list(nums[left : right + 1]) # 初始化左子数组和右子数组的起始索引
# 左子数组的起始索引和结束索引 i, j, k = left, mid + 1, 0
left_start = 0 # 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
left_end = mid - left while i <= mid and j <= right:
# 右子数组的起始索引和结束索引 if nums[i] <= nums[j]:
right_start = mid + 1 - left tmp[k] = nums[i]
right_end = right - left
# i, j 分别指向左子数组、右子数组的首元素
i = left_start
j = right_start
# 通过覆盖原数组 nums 来合并左子数组和右子数组
for k in range(left, right + 1):
# 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
if i > left_end:
nums[k] = tmp[j]
j += 1
# 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
elif j > right_end or tmp[i] <= tmp[j]:
nums[k] = tmp[i]
i += 1 i += 1
# 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
else: else:
nums[k] = tmp[j] tmp[k] = nums[j]
j += 1 j += 1
k += 1
# 将左子数组和右子数组的剩余元素复制到临时数组中
while i <= mid:
tmp[k] = nums[i]
i += 1
k += 1
while j <= right:
tmp[k] = nums[j]
j += 1
k += 1
# 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for k in range(0, len(tmp)):
nums[left + k] = tmp[k]
def merge_sort(nums: list[int], left: int, right: int): def merge_sort(nums: list[int], left: int, right: int):

View file

@ -5,33 +5,33 @@
*/ */
/* 合并左子数组和右子数组 */ /* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
function merge(nums: number[], left: number, mid: number, right: number): void { function merge(nums: number[], left: number, mid: number, right: number): void {
// 初始化辅助数组 // 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
let tmp = nums.slice(left, right + 1); // 创建一个临时数组 tmp ,用于存放合并后的结果
// 左子数组的起始索引和结束索引 const tmp = new Array(right - left + 1);
let leftStart = left - left, // 初始化左子数组和右子数组的起始索引
leftEnd = mid - left; let i = left,
// 右子数组的起始索引和结束索引 j = mid + 1,
let rightStart = mid + 1 - left, k = 0;
rightEnd = right - left; // 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
// i, j 分别指向左子数组、右子数组的首元素 while (i <= mid && j <= right) {
let i = leftStart, if (nums[i] <= nums[j]) {
j = rightStart; tmp[k++] = nums[i++];
// 通过覆盖原数组 nums 来合并左子数组和右子数组
for (let k = left; k <= right; k++) {
if (i > leftEnd) {
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
nums[k] = tmp[j++];
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
} else if (j > rightEnd || tmp[i] <= tmp[j]) {
nums[k] = tmp[i++];
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
} else { } else {
nums[k] = tmp[j++]; tmp[k++] = nums[j++];
} }
} }
// 将左子数组和右子数组的剩余元素复制到临时数组中
while (i <= mid) {
tmp[k++] = nums[i++];
}
while (j <= right) {
tmp[k++] = nums[j++];
}
// 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
for (k = 0; k < tmp.length; k++) {
nums[left + k] = tmp[k];
}
} }
/* 归并排序 */ /* 归并排序 */