[英]stuck on implementation of merge sort
I am implementing mergesort referencing the geeks for geeks implementation as a guide but my implementation is not working.我正在实施合并排序,参考极客实施作为指南,但我的实施不起作用。
I have my mergesort function that divides my given array in 2 and calls mergesort on half of the list.我有我的 mergesort 函数,它将我的给定数组分成 2 并在列表的一半上调用 mergesort。
Within mergesort, I use a helper function that merges the sub arrays together.在归并排序中,我使用了一个将子数组合并在一起的辅助函数。
I have included my 2 functions.我已经包含了我的 2 个函数。 Could someone be my second set of eyes, I am have staring at this too long to tell the difference between 1's and l's
有人会是我的第二双眼睛吗,我盯着这看太久了,无法分辨 1 和 l 之间的区别
It is running but not sorting correctly.它正在运行但没有正确排序。
void merge(int arr[], int temp[], int l, int m, int r) {
//TODO: implement merge.
// check arr
if (arr == NULL) {
return;
}
int left = m - l + 1;
int right = r - m;
// copy array into temp array
// first half
int i = 0;
for (i = 0; i < left; i++) {
temp[i] = arr[l + i];
}
// second half
int j = 0;
for (j = m + 1; i < right; j++) {
temp[j] = arr[m + l + i];
}
// compare from each end inserting the lower into the next location of the real array
// beginning index of front sub list
int front = 0;
// beginning of back sub list
int back = left;
// index within array to insert back in
int index = l;
while ((front < left) && (back < right)) {
if (temp[front] <= temp[back]) {
// temp front goes in the next array spot
arr[index] = temp[front];
// increase temp
front++;
} else {
// back is smaller and is put back in the list first
arr[index] = temp[back];
// increase back
back++;
}
// increase array index
index++;
}
while (front < left) {
arr[index] = temp[front];
front++;
index++;
}
while (back < right) {
arr[index] = temp[back];
back++;
index++;
}
}
void mergeSort(int array[], int temp[], int l, int r) {
if (r > l) {
// find middle point
int middle = l + (r - l) / 2;
// call merge on first half
mergeSort(array, temp, l, middle);
// call merge on second half
mergeSort(array, temp, middle + 1, r);
// merge the halves
merge(array, temp, l, middle, r);
}
}
I had some trouble understanding your merge
logic.我在理解您的
merge
逻辑时遇到了一些麻烦。
Too many indexes/limits of the form (eg): m - l + 1
表格的索引/限制过多(例如):
m - l + 1
So, I simplified things by having two temp
pointers: tmp_l
and tmp_r
and added some length/count variables.因此,我通过使用两个
temp
指针来简化事情: tmp_l
和tmp_r
并添加了一些长度/计数变量。
This allowed some of the indexes to start with 0.这允许一些索引从 0 开始。
Also, your middle
calculation was unusual.此外,您的
middle
计算不寻常。
And, I changed the arg in the call to merge
from middle
to middle + 1
而且,我将调用中的 arg 更改为从
middle
merge
到middle + 1
I've refactored the code and added a test suite.我重构了代码并添加了一个测试套件。 I've used
cpp
conditionals to denote old vs new code:我使用
cpp
条件来表示旧代码与新代码:
#if 0
// old code
#else
// new code
#endif
Anyway, here's my [working] version:无论如何,这是我的 [working] 版本:
#include <stdio.h>
#include <stdlib.h>
#ifdef DEBUG
#define dbgprt(_fmt...) \
do { \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
void
merge(int arr[], int temp[], int l, int m, int r)
{
if (arr == NULL) {
return;
}
// get number of left elements
int lcnt = (m - l);
// get number of right elements
int rcnt = (r - m) + 1;
dbgprt("merge: BEGIN l=%d m=%d r=%d lcnt=%d rcnt=%d\n",
l,m,r,lcnt,rcnt);
int i = 0;
int *tmp_l = &temp[0];
for (i = 0; i < lcnt; i++)
tmp_l[i] = arr[l + i];
int *tmp_r = &temp[lcnt];
for (i = 0; i < rcnt; i++)
tmp_r[i] = arr[m + i];
int front = 0;
int back = 0;
int index = l;
while ((front < lcnt) && (back < rcnt)) {
// temp front goes in the next array spot
if (tmp_l[front] <= tmp_r[back]) {
arr[index] = tmp_l[front];
// increase temp
front++;
}
// back is smaller and is put back in the list first
else {
arr[index] = tmp_r[back];
// increase back
back++;
}
// increase array index
index++;
}
while (front < lcnt) {
arr[index] = tmp_l[front];
index++;
front++;
}
while (back < rcnt) {
arr[index] = tmp_r[back];
index++;
back++;
}
}
void
mergeSort(int array[], int temp[], int l, int r)
{
int middle;
if (r > l) {
// find middle point
#if 0
middle = l + (r - 1) / 2;
#else
middle = (l + r) / 2;
#endif
dbgprt("msort: ENTER l=%d m=%d r=%d\n",l,middle,r);
// call merge on first half
mergeSort(array, temp, l, middle);
// call merge on second half
mergeSort(array, temp, middle + 1, r);
// merge the halves
#if 0
merge(array, temp, l, middle, r);
#else
merge(array, temp, l, middle + 1, r);
#endif
dbgprt("msort: EXIT l=%d m=%d r=%d\n",l,middle,r);
}
}
void
dotest(int tstno)
{
int count = (rand() % 30) + 1;
printf("dotest: %d %d\n",tstno,count);
int *arr = malloc(sizeof(*arr) * count);
int *tmp = malloc(sizeof(*tmp) * count);
for (int idx = 0; idx < count; ++idx) {
arr[idx] = count - idx;
dbgprt(" %d",arr[idx]);
}
dbgprt("\n");
mergeSort(arr,tmp,0,count - 1);
int err = 0;
for (int idx = 0; idx < count; ++idx) {
printf(" %d",arr[idx]);
if (arr[idx] != (idx + 1)) {
printf("?");
err = 1;
}
}
printf("\n");
if (err)
exit(1);
free(arr);
free(tmp);
}
int
main(void)
{
for (int tstno = 1; tstno <= 4; ++tstno)
dotest(tstno);
return 0;
}
void
merge_ORIG(int arr[], int temp[], int l, int m, int r)
{
if (arr == NULL) {
return;
}
int i = 0;
for (i = 0; i < m - l + 1; i++) {
temp[i] = arr[l + i];
}
for (i = 0; i < r + 1; i++) {
temp[i] = arr[m + l + i];
}
int front = l;
int back = m + 1;
int index = l;
while ((front < m - l + 1) && (back < r - m)) {
if (temp[front] <= temp[back]) {
// temp front goes in the next array spot
arr[index] = temp[front];
// increase temp
front++;
}
else {
// back is smaller and is put back in the list first
arr[index] = temp[back];
// increase back
back++;
}
// increase array index
index++;
}
while (front < m - l + 1) {
arr[index] = temp[front];
index++;
front++;
}
while (back < r - m) {
arr[index] = temp[back];
index++;
back++;
}
}
There is a problem here:这里有一个问题:
// second half
int j = 0;
for (j = m + 1; i < right; j++) {
temp[j] = arr[m + l + i];
}
You should write:你应该写:
// second half
for (i = 0; i < right; i++) {
temp[left + i] = arr[m + 1 + i];
}
Could someone be my second set of eyes, I am have staring at this too long to tell the difference between
1
's andl
's?有人会是我的第二双眼睛吗,我盯着这个看得太久了,无法分辨
1
和l
之间的区别?
This is an excellent point!这是一个很好的观点! The solution is to never use
l
as a variable name, and to simplify the mergesort
implementation to remove the confusing and error prone +1
/ -1
adjustments.解决方案是永远不要使用
l
作为变量名,并简化mergesort
实现以消除混淆和容易出错的+1
/ -1
调整。 For this you just need to use the convention where r
is the index of the element after the end of the slice.为此,您只需要使用约定,其中
r
是切片结束后元素的索引。
Here is a modified version:这是一个修改后的版本:
void merge(int arr[], int temp[], int lo, int mid, int hi) {
// check arr
if (arr == NULL) {
return;
}
int left = mid - lo;
int right = hi - mid;
// copy array into temp array
// first half
for (int i = 0; i < left; i++) {
temp[i] = arr[lo + i];
}
// second half
for (int i = 0; i < right; i++) {
temp[left + i] = arr[mid + i];
}
// compare from each end inserting the lower into the next location of the real array
// beginning index of front sub list
int front = 0;
// beginning of back sub list
int back = left;
// index within array to insert back in
int index = lo;
while ((front < left) && (back < right)) {
if (temp[front] <= temp[back]) {
// temp front goes in the next array spot
arr[index++] = temp[front++];
} else {
// back is smaller and is put back in the list first
arr[index++] = temp[back++];
}
}
while (front < left) {
arr[index++] = temp[front++];
}
while (back < right) {
arr[index++] = temp[back++];
}
}
void mergeSort(int array[], int temp[], int lo, int hi) {
if (hi - lo >= 2) {
// find middle point
int mid = lo + (hi - lo) / 2;
// call merge on first half
mergeSort(array, temp, lo, mid);
// call merge on second half
mergeSort(array, temp, mid, hi);
// merge the halves
merge(array, temp, lo, mid, hi);
}
}
The initial call should give 0
and the length of the array as index arguments.初始调用应该给出
0
和数组的长度作为索引参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.