[英]Understanding merge sort code
我正在尝试使用以下网站作为资源来实现合并排序。
http://interactivepython.org/courselib/static/pythonds/SortSearch/TheMergeSort.html
对我来说,我的代码看起来不错; 但是,鉴于我的输出不正确,这显然是错误的。 我不确定哪里或为什么错了。 我认为在查看图像的合并说明时我了解合并排序,但是尝试实现它非常困难。 我试图给所有变量名称一些含义,以帮助减少混乱(“ i”,“ j”,“ k”,“ m”和“ n”有点难以跟踪它们代表什么)。尝试使用打印语句来帮助调试我的代码,但是递归对我而言从来都不是一件容易的事,因此我不确定输出结果是否正确,我的打印语句告诉我的确切信息。不管调试器为何不列出我的任何数组中的值,所以我都无法真正通过调试器进行处理,因此在澄清合并排序实现方面的任何帮助将不胜感激。
#include <stdio.h>
void merge_sort(int array[], int startIndex, int endIndex);
void merge(int array[], int startIndex, int midIndex, int endIndex);
int main(void)
{
int size = 8;
int numbers[8] = {14, 7, 3, 12, 9, 11, 6, 2};
printf("Unsorted Array!\n");
for(int i = 0; i < size; i++)
{
printf("%i ", numbers[i]);
}
printf("\n");
merge_sort(numbers, 0, 7);
printf("Sorted Array!\n");
for(int i = 0; i < size; i++)
{
printf("%i ", numbers[i]);
}
printf("\n");
}
void merge_sort(int array[], int startIndex, int endIndex)
{
// determine size of the array
int size = (endIndex - startIndex) + 1; // updated
// if the array has more than 1 element then it needs broken down into smaller arrays
if(size > 1)
{
int midIndex = (startIndex + endIndex) / 2;
merge_sort(array, startIndex, midIndex); // Sort the LEFT side
merge_sort(array, midIndex + 1, endIndex); // Sort the RIGHT side
merge(array, startIndex, midIndex, endIndex);
}
}
void merge(int array[], int startIndex, int midIndex, int endIndex)
{
int leftSize = midIndex - startIndex + 1;
int rightSize = endIndex - midIndex;
int originalArrayIndex = 0;
int leftArray[leftSize];
int rightArray[rightSize];
int currentLeftIndex = 0;
int currentRightIndex = 0;
// fill the leftArray
for(int i = 0; i < leftSize; i++)
{
leftArray[i] = array[i];
printf("%i ", leftArray[i]);
}
printf(" === Left array\n");
// fill the rightArray
for(int i = 0; i < rightSize; i++)
{
rightArray[i] = array[leftSize + i];
printf("%i ", rightArray[i]);
}
printf(" === Right array\n");
// do the actual merge
// leftStart < leftSize and rightStart < rightSize
while((currentLeftIndex < leftSize) && (currentRightIndex < rightSize))
{
// if the left array value is smaller than the right array value then that means the left array value goes into the original array[]
if(leftArray[currentLeftIndex] < rightArray[currentRightIndex])
{
array[originalArrayIndex] = leftArray[currentLeftIndex];
originalArrayIndex++;
currentLeftIndex++;
}
else
{
array[originalArrayIndex] = rightArray[currentRightIndex];
originalArrayIndex++;
currentRightIndex++;
}
}
// no clue what this is
while(currentLeftIndex < leftSize)
{
array[originalArrayIndex] = leftArray[currentLeftIndex];
originalArrayIndex++;
currentLeftIndex++;
}
// no clue what this is
while(currentRightIndex < rightSize)
{
array[originalArrayIndex] = rightArray[currentRightIndex];
originalArrayIndex++;
currentRightIndex++;
}
for(int i = 0; i < leftSize; i++)
{
printf("%i ", leftArray[i]);
}
printf(" ==== left array after sort\n");
for(int i = 0; i < rightSize; i++)
{
printf("%i ", rightArray[i]);
}
printf(" ==== right array after sort\n");
for(int i = 0; i < endIndex + 1; i++)
{
printf("%i ", array[i]);
}
printf(" ===== post merge =====\n");
}
输出如下:
未排序的数组!
14 7 3 12 9 11 6 2
14 7 ===左数组
3 12 ===右数组
14 7 ====排序后的左数组
3 12 ====排序后的右数组
3 12 14 7 =====合并后=====
3 12 ===左数组
14 7 ===右数组
3 12 ====排序后的左数组
14 7 ====排序后的右数组
3 12 14 7 9 11 6 2 =====合并后=====
3 12 14 7 ===左数组
9 11 6 2 ===右数组
3 12 14 7 ====排序后的左数组
9 11 6 2 ====排序后的右数组
3 9 11 6 2 12 14 7 =====合并后=====
排序数组!
3 9 11 6 2 12 14 7
更新的输出:
未排序的数组!
14 7 3 12 9 11 6 2
14 ===左数组
7 ===右数组
7 14 =====合并后=====
7 ===左数组
14 ===右数组
7 14 3 12 =====合并后=====
7 14 ===左数组
3 12 ===右数组
3 7 12 14 =====合并后=====
3 ===左数组
7 ===右数组
3 7 12 14 9 11 =====合并后=====
3 ===左数组
7 ===右数组
3 7 12 14 9 11 6 2 =====合并后=====
3 7 ===左数组
12 14 ===右数组
3 7 12 14 9 11 6 2 =====合并后=====
3 7 12 14 ===左数组
9 11 6 2 ===右数组
3 7 9 11 6 2 12 14 =====合并后=====
排序数组!
3 7 9 11 6 2 12 14
您的错误在这里:
// fill the rightArray
for(int i = 0; i < rightSize; i++)
{
rightArray[i] = array[rightSize + i];
printf("%i ", rightArray[i]);
}
printf(" === Right array\n");
您需要按左数组大小缩进:
rightArray[i] = array[leftSize + i];
顺便说一下,您评论过的部分
//不知道这是什么
在程序已经完成插入两个数组之一的所有索引的情况下,可以继续插入索引。
更新:还有另一个(更大)问题。 您还需要跟踪原始数组上的当前位置。 如果仔细观察,您会发现即使使用右半部分,也总是复制从numbers[0]
开始的值。 但是保留另一个计数器是一种麻烦的方法,因此请考虑将函数定义更改为:
merge_sort (int array[], int arraySize);
merge (int leftArray[], int leftSize, int rightArray[], int rightSize, int targetArray[]);
这将有助于保持事物的清洁和简单。 它应该是这样的:
#include <stdio.h>
void merge_sort(int array[], int arraySize);
void merge(int leftArray[], int leftSize, int rightArray[], int rightSize, int targetArray[]);
int main(void)
{
int numbers[8] = { 14, 7, 3, 12, 9, 11, 6, 2 };
int size = sizeof(numbers) / sizeof(int);
printf("Unsorted Array!\n");
for (int i = 0; i < size; i++)
{
printf("%i, ", numbers[i]);
}
printf("\n");
merge_sort(numbers, size);
printf("Sorted Array!\n");
for (int i = 0; i < size; i++)
{
printf("%i ", numbers[i]);
}
printf("\n");
}
void merge_sort(int array[], int arraySize)
{
if (arraySize > 1)
{
int leftSize = arraySize / 2;
int rightSize = arraySize - leftSize;
merge_sort(array, leftSize); // Sort the LEFT side
merge_sort(array + leftSize, rightSize); // Sort the RIGHT side
int* targetArray = (int*)malloc(arraySize * sizeof(int));
merge(array, leftSize, array + leftSize, rightSize, targetArray);
memcpy(array, targetArray, arraySize * sizeof(int));
free(targetArray);
}
}
void merge(int leftArray[], int leftSize, int rightArray[], int rightSize, int targetArray[])
{
int currentLeftIndex = 0;
int currentRightIndex = 0;
int targetIndex = 0;
while ((currentLeftIndex < leftSize) && (currentRightIndex < rightSize))
{
if (leftArray[currentLeftIndex] < rightArray[currentRightIndex])
{
targetArray[targetIndex] = leftArray[currentLeftIndex];
currentLeftIndex++;
}
else
{
targetArray[targetIndex] = rightArray[currentRightIndex];
currentRightIndex++;
}
targetIndex++;
}
while (currentLeftIndex < leftSize)
{
targetArray[targetIndex] = leftArray[currentLeftIndex];
targetIndex++;
currentLeftIndex++;
}
while (currentRightIndex < rightSize)
{
targetArray[targetIndex] = rightArray[currentRightIndex];
targetIndex++;
currentRightIndex++;
}
}
在merge
初始化临时左右数组时,您需要修复要访问的索引。 例如,您当前有
// fill the leftArray
for(int i = 0; i < leftSize; i++)
{
leftArray[i] = array[i];
printf("%i ", leftArray[i]);
}
printf(" === Left array\n");
// fill the rightArray
for(int i = 0; i < rightSize; i++)
{
rightArray[i] = array[rightSize + i];
printf("%i ", rightArray[i]);
}
printf(" === Right array\n");
但这假设该array
是原始数组的一部分。 尽管从外观上看mergesort算法从字面上将原始数组拆分为子数组,但是代码实际上并没有这样做。 您仍然会篡改原始数组,但是参数int startIndex, int midIndex, int endIndex
就像原始数组中的边框。 因此,在初始化leftArray
和rightArray
您需要使用类似的参数访问array
的元素,
// fill the leftArray
for(int i = 0; i < leftSize; i++)
{
leftArray[i] = array[i];
printf("%i ", leftArray[startIndex + i]);
}
printf(" === Left array\n");
// fill the rightArray
for(int i = 0; i < rightSize; i++)
{
rightArray[i] = array[midIndex + i];
printf("%i ", rightArray[i]);
}
printf(" === Right array\n");
此版本有效。 这是原始代码,其中的注释中有修正,// //修正了这一行。 其他更改归因于使用Microsoft编译器(旧的C语法)。 还清理了压痕。
#include <stdio.h>
void merge_sort(int array[], int startIndex, int endIndex);
void merge(int array[], int startIndex, int midIndex, int endIndex);
int main(void)
{
int i; // my compiler is old style c
int size = 8;
int numbers[8] = {14, 7, 3, 12, 9, 11, 6, 2};
printf("Unsorted Array!\n");
for(i = 0; i < size; i++)
{
printf("%i ", numbers[i]);
}
printf("\n");
merge_sort(numbers, 0, 7);
printf("Sorted Array!\n");
for(i = 0; i < size; i++)
{
printf("%i ", numbers[i]);
}
printf("\n");
return 0; // added this //
}
void merge_sort(int array[], int startIndex, int endIndex)
{
// determine size of the array
int size = (endIndex - startIndex) + 1; // updated
int midIndex; // my compiler is old style C compiler
// if the array has more than 1 element then it needs broken down into smaller arrays
if(size > 1)
{
midIndex = (startIndex + endIndex) / 2;
merge_sort(array, startIndex, midIndex); // Sort the LEFT side
merge_sort(array, midIndex + 1, endIndex); // Sort the RIGHT side
merge(array, startIndex, midIndex, endIndex);
}
}
void merge(int array[], int startIndex, int midIndex, int endIndex)
{
int leftSize = midIndex - startIndex + 1;
int rightSize = endIndex - midIndex;
int originalArrayIndex = startIndex; // fixed this line //
// my compiler doesn't support variable length arrays
// so allocating from the stack (neither works on large arrays)
int *leftArray = _alloca(leftSize*sizeof(int));
int *rightArray = _alloca(rightSize*sizeof(int));
// int leftArray[leftSize];
// int rightArray[rightSize];
int currentLeftIndex = 0;
int currentRightIndex = 0;
int i; // my compiler is old style c compiler
// fill the leftArray
for(i = 0; i < leftSize; i++)
{
leftArray[i] = array[startIndex+i]; // fixed this line //
printf("%i ", leftArray[i]);
}
printf(" === Left array\n");
// fill the rightArray
for(i = 0; i < rightSize; i++)
{
rightArray[i] = array[midIndex + 1 + i]; // fixed this line //
printf("%i ", rightArray[i]);
}
printf(" === Right array\n");
// do the actual merge
// leftStart < leftSize and rightStart < rightSize
while((currentLeftIndex < leftSize) && (currentRightIndex < rightSize))
{
// if the left array value is smaller than the right array value then that means the left array value goes into the original array[]
if(leftArray[currentLeftIndex] < rightArray[currentRightIndex])
{
array[originalArrayIndex] = leftArray[currentLeftIndex];
originalArrayIndex++;
currentLeftIndex++;
}
else
{
array[originalArrayIndex] = rightArray[currentRightIndex];
originalArrayIndex++;
currentRightIndex++;
}
}
// copy any data remaining in leftArray
while(currentLeftIndex < leftSize)
{
array[originalArrayIndex] = leftArray[currentLeftIndex];
originalArrayIndex++;
currentLeftIndex++;
}
// copy any data remaining in rightArray
while(currentRightIndex < rightSize)
{
array[originalArrayIndex] = rightArray[currentRightIndex];
originalArrayIndex++;
currentRightIndex++;
}
for(i = 0; i < leftSize; i++)
{
printf("%i ", leftArray[i]);
}
printf(" ==== left array after sort\n");
for(i = 0; i < rightSize; i++)
{
printf("%i ", rightArray[i]);
}
printf(" ==== right array after sort\n");
for(i = startIndex; i < endIndex + 1; i++) // fix
{
printf("%i ", array[i]);
}
printf(" ===== post merge =====\n");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.