我是c ++的新手,正在尝试开发合并排序代码。我用大小为5的样本数组测试了它,但代码提出的答案是不正确的。我无法弄清楚出了什么问题。这是我的代码:
#include <iostream>
#include <cstring>
#include <sstream>
#include <fstream>
#include <iomanip>
using namespace std;
void merge(int, int, int, int*);
void merge_sort(int low, int high, int* p){
int pivot;
static int i(1);
if (high>low)
{
cout << "calling merge_sort: "<<i<<endl; i++;
pivot = low + ((high - low)/2);
cout << pivot << endl;
merge_sort(low, pivot, p);
merge_sort(pivot+1, high, p);
merge(low, pivot, high, p);
}
}
void merge(int l, int pi, int h,int* arr)
{
int start = l;
int mid = pi+1;
while((start<=pi)&&(mid <=h)){
if (arr[start] > arr[mid])
{
int temp = arr[mid];
arr[mid] = arr[start];
arr[start] = temp;
mid++;
}
else
start++;
}
}
int main()
{
int a[] = {2, 42, 3, 7, 1};
merge_sort(0, 4, a);
for (int i = 0; i<=4 ; i++)
cout << a[i] << endl;
return (0);
}
输出如下:
calling merge_sort: 1
2
calling merge_sort: 2
1
calling merge_sort: 3
0
calling merge_sort: 4
3
1
3
7
2
42
我在stackoverflow上看到了一些合并排序实现的代码,但它们使用了另一个临时数组,我想避免这种情况。
在排序此问题时,非常感谢任何帮助。
答案 0 :(得分:3)
合并中的逻辑是错误的。在合并阶段,您知道您有2个已排序的数字部分。当您比较并交换arr[start]
和arr[mid]
时,如果arr[start] > arr[mid+1]
,您将打破对顶部数字集的排序。该示例显示您的代码存在问题,因为2将保留在错误的位置:
4 6 8 | 1 3 5 -> 1 6 8 | 4 3 5
^ ^ ^ ^
为了保持2个部分的排序,您必须将arr[start]
插入到顶部数字集中的正确位置,这会使复杂性比O(n lg n)
更差。这就是使用第二个数组的原因。
有一种方法使用比原来更小的阵列进行合并,这些方法有其开销,但不会影响复杂性(或正确性)。如果您想要O(n lg n)
进行排序,那么快速排序或合页是最佳选择。
答案 1 :(得分:2)
以下是整数数组的合并排序实现:
void merge_sort (int array[], int size)
{
int temp[size];
int mid, i;
if (size < 2) {
return;
}
else {
mid = size / 2;
merge_sort(array, mid);
merge_sort(array + mid, size - mid);
merge (array, mid, array + mid, size - mid, temp);
for (i = 0; i < size; i++) {
array[i] = temp[i];
}
}
}
int merge (int list1[ ] , int size1 , int list2[ ] , int size2 , int list3[ ])
{
int i1, i2, i3;
if (size1+size2 > size) {
return false;
}
i1 = 0; i2 = 0; i3 = 0;
/* while both lists are non-empty */
while (i1 < size1 && i2 < size2) {
if (list1[i1] < list2[i2]) {
list3[i3++] = list1[i1++];
}
else {
list3[i3++] = list2[i2++];
}
}
while (i1 < size1) {
/* copy remainder of list1 */
list3[i3++] = list1[i1++];
}
while (i2 < size2) {
/* copy remainder of list2 */
list3[i3++] = list2[i2++];
}
return true;
}
如果你想将它用于其他类型,你可以使用这样的c ++模板:
template <class T>
T* merge_sort(T arr[], int n)
{
if(n < 2){return arr;}
int mid = n/2;
T *arr1 = merge_sort<T>(arr,mid);
T *arr2 = merge_sort<T>(arr+mid,n-mid);
return merge(arr1, mid, arr2, n-mid);
}
template <class T>
T* merge(T arr1[], int size1, T arr2[], int size2)
{
int i = 0,j = 0;
T* out_array = new T[size1+size2];
while((i < size1) && (j < size2))
{
if(arr1[i] >= arr2[j])
{
out_array[i+j] = arr2[j];
++j;
}
else
{
out_array[i+j] = arr1[i];
++i;
}
}
while(i < size1)
{
//copy the reminder
out_array[i+j] = arr1[i];
i++;
}
while( j < size2)
{
out_array[i+j] = arr2[j];
j++;
}
return out_array;
}
但是:
#include <iostream>
using namespace std;
int main() {
int a[] = {2, 42, 3, 7, 1};
int *a2 = merge_sort(a,5);
for (int i = 0; i<= 4 ; ++i)
cout << a2[i] << endl;
return (0);
}
输出:
1
2
3
7
42
希望我帮了一下。
答案 2 :(得分:1)
这些线条对我来说似乎不对:
int temp = arr[mid-1]; // It should be [mid] here
arr[mid] = arr[start]; // Or [mid-1] here
arr[start] = temp;
对于交换两个索引,这两个索引必须匹配。
答案 3 :(得分:0)
这个在代码块中完美地工作(编译器使用:mingw)
#include <iostream>
using namespace std;
void merge(int*,int*,int,int,int);
void mergesort(int *a, int*b, int low, int high)
{
int pivot;
if(low<high)
{
pivot=(low+high)/2;
mergesort(a,b,low,pivot);
mergesort(a,b,pivot+1,high);
merge(a,b,low,pivot,high);
}
}
void merge(int *a, int *b, int low, int pivot, int high)
{
int h,i,j,k;
h=low;
i=low;
j=pivot+1;
while((h<=pivot)&&(j<=high))
{
if(a[h]<=a[j])
{
b[i]=a[h];
h++;
}
else
{
b[i]=a[j];
j++;
}
i++;
}
if(h>pivot)
{
for(k=j; k<=high; k++)
{
b[i]=a[k];
i++;
}
}
else
{
for(k=h; k<=pivot; k++)
{
b[i]=a[k];
i++;
}
}
for(k=low; k<=high; k++) a[k]=b[k];
}
int main()
{
int a[] = {12,10,43,23,-78,45,123,56,98,41,90,24};
int num;
num = sizeof(a)/sizeof(int);
int b[num];
mergesort(a,b,0,num-1);
for(int i=0; i<num; i++)
cout<<a[i]<<" ";
cout<<endl;
}
答案 4 :(得分:0)
简单而完整的工作(由我自己完成)
void MergeSort(int list[], int size)
{
int blockSize = 1, p;
int *a, *b;
int *c = new int[size];
do
{
for (int k = 0; k < size; k += (blockSize * 2))
{
a = &list[k];
b = &list[k + blockSize];
p = 0;
for (int i = 0, j = 0; i < blockSize || j < blockSize;)
{
if ((j < blockSize) && ((k + j + blockSize) >= size))
{
++j;
}
else if ((i < blockSize) && ((k + i) >= size))
{
++i;
}
else if (i >= blockSize)
{
c[p++] = b[j++];
}
else if (j >= blockSize)
{
c[p++] = a[i++];
}
else if (a[i] >= b[j])
{
c[p++] = b[j++];
}
else if (a[i] < b[j])
{
c[p++] = a[i++];
}
}
for (int i = 0; i < p; i++)
{
a[i] = c[i];
}
}
blockSize *= 2;
} while (blockSize < size);
}