对于学校,我必须仅使用指针编程合并排序。 我几乎尝试了所有的东西,但我无法让它发挥作用。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define num_elementi(array) (sizeof(array)/sizeof(array[0]))
void selsort(int arr[],int n);
void swap(int * a, int * b);
void print(int arr[],int n);
void insort(int arr[],int n);
void mergesort(int arr[],int *p,int *u);
void merge(int arr[],int * p, int * q,int * u);
int main(int argc, char *argv[]){
int arr[]={99,12,14,65,2,7,54,78,5,1,43,59,88,28,61};
int n=num_elementi(arr);
printf("numero elementi array: %d\n",n);
print(arr,n);
printf("numero elementi array: %d\n",n);
mergesort(arr,&arr[0],&arr[n-1]);
print(arr,n);
system("pause");
}
void selsort(int arr[],int n){
int *i,*j;
for(i=arr;i<&arr[n-1];i++){
for(j=i+1;j<&arr[n];j++){
if(*j<*i)swap(i,j);;
}
}
}
void swap(int * a, int * b){
int temp;
temp=*a;
*a=*b;
*b=temp;
}
void print(int arr[],int n){
int * p=arr;
for(p;p<&arr[n];p++)printf("%d ",*p);
printf("\n");
}
void insort(int arr[],int n){
int *i,*k;
for(i=&arr[1];i<&arr[n];i++){
k=i-1;
while(k>=&arr[0]&& *k>*(k+1)){
swap(k,k+1);
k=k-1;
}
}
}
void mergesort(int arr[],int *p,int *u){
if (p<u){
int *q=((u-p)/2)+p;
mergesort(arr,p,q);
mergesort(arr,q,u-1);
merge(arr,p,q,u);
}
}
void merge(int arr[],int * p, int * q,int * u){
int arr1[u-p]; //inizializzazione array di dimensioni utili
int * i=p; //puntatore al primo elemento di arr
int *j=q+1; //puntatore al elemento di mezzo +1 di arr
int *k= arr1; //puntatore al primo elemento di arr1
if (u-p==1){
if (*u<*p){
swap(u,p);
}
return;
}
while(i<q && j<u){
if(*i<*j){
*k=*i;
i=i+1;
}
else{
*k=*j;
j=j+1;
}
k=k+1;
}
while(i<q){*k=*i;i++;k++;}
while(j<u){*k=*j;j++;k++;}
i=p;
k=arr1;
for(i,k;i<&arr[u-p];i++,k++){
*i=*k;
}
}
有人可以解释一下我做错了吗?非常感谢你!!
PS:请原谅我非常糟糕的英语。编辑 Maciej Hehl建议的新代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define num_elementi(array) (sizeof(array)/sizeof(array[0]))
void swap(int * a, int * b);
void print(int arr[],int n);
void mergesort(int arr[],int * arr_begin,int * arr_end);
void merge(int * destination, int * r1_begin, int * r1_end, int * r2_begin, int * r2_end);
int main(int argc, char *argv[]){
int arr[]={99,12,14,65,2,7,54,78,5,1,43,59,88,28,61};
int n=num_elementi(arr);
print(arr,n);
mergesort(arr,&arr[0],&arr[n-1]);
print(arr,n);
system("pause");
}
void swap(int * a, int * b){
int temp;
temp=*a;
*a=*b;
*b=temp;
}
void print(int arr[],int n){
int * p=arr;
for(p;p<&arr[n];p++)printf("%d ",*p);
printf("\n");
}
void mergesort(int arr[],int * arr_begin,int * arr_end){
int * med,*arr1,*p,*p1;
printf("i'm doing something\n");
if(arr_begin<arr_end){
med=arr[arr_end-arr_begin]/2+arr_begin;
mergesort(arr,arr_begin,med);
mergesort(arr,med+1,arr_end);
arr1=malloc((arr_end-arr_begin)*sizeof(int));
printf("msort calls ended begin merge\n");
merge(arr1,arr_begin,med,med+1,arr_end);
for(p=arr,p1=arr1;p<arr_end&&p1<&arr1[arr_end-arr_begin];p++,p1++){
*p=*p1;
}
}
}
void merge(int * destination, int * r1_begin, int * r1_end, int * r2_begin, int * r2_end){
int *pdest=destination;
if (r1_end-r1_begin==1){
if (*r1_end<*r1_begin){
swap(r1_end,r1_begin);
}
return;
}
if (r2_end-r2_begin==1){
if (*r2_end<*r2_begin){
swap(r2_end,r2_begin);
}
return;
}
while(r1_begin<=r1_end&&r2_begin<=r2_end){
if(*r1_begin<*r2_begin){
*pdest=*r1_begin;
r1_begin++;
}
else{
*pdest=*r2_begin;
r2_begin++;
}
pdest++;
}
while(r1_begin<r1_end){
*pdest=*r1_begin;
r1_begin++;pdest++;
}
while(r2_begin<r2_end){
*pdest=*r2_begin;
r2_begin++;pdest++;
}
}
答案 0 :(得分:3)
修改强>
你的编辑让我原来的答案(下面)对其他读者毫无意义:)哦,好吧......
首先要确定你的begin
和end
指针是否定义范围[开始,结束]或[开始,结束]。我建议第一个选择因为它在C ++库中使用。如果您同意,那么电话
mergesort(arr,&arr[0],&arr[n]);
是对的。只有在您决定时,您才需要将&arr[n]
更改为&arr[n-1]
,您希望指针begin
和end
定义范围[begin,end],我建议不要这样做
事实上,指针begin
和end
足以对范围进行排序,而mergesort
函数不需要第一个参数。
med
的计算不正确
med=arr[arr_end-arr_begin]/2+arr_begin;
在之前的版本中是正确的(变量名为q)
以下调用也不正确
mergesort(arr,arr_begin,med);
mergesort(arr,med+1,arr_end);
第一次调用应该对范围[arr_begin,med]进行排序,而不是[arr_begin,med](*med
不属于该范围),因此第二次调用应该从{{开始对范围进行排序1}}。
arr1的分配是正确的,这要归功于差异med
等于元素的数量。这是选择范围[开始,结束]而不是[开始,结束]的优势。但是,如果您在使用后释放了已分配的内存,那将会很不错。
合并调用不正确,就像上面对end - begin
的调用一样。第二个范围sholuld从mergesort
开始,因为med
指向第一个范围,而不是它的最后一个元素。
med
的实施过于复杂。你不必交换任何东西。您只需从两个范围中获取元素并将它们复制到目标。这三个while循环开始我原来的帖子(下面)就足够了,但要注意条件。
我再次重复merge
点过去第一个范围,med
点过去第二个范围。考虑到这一点,您应该使用arr_end
还是<=
运营商?
我不喜欢以下代码中条件<
,i<=q
,j<=u
,i<q
的不一致性:
j<u
您可以像这样调用您的mergesort:
while(i<=q && j<=u){
if(*i<*j){
*k=*i;
i=i+1;
}
else{
*k=*j;
j=j+1;
}
k=k+1;
}
while(i<q){*k=*i;i++;k++;}
while(j<u){*k=*j;j++;k++;}
这意味着,mergesort(arr,&arr[0],&arr[n]);
是一个指针,指向数组的最后一个元素之后的点。换句话说,你似乎想到了你的指针,比如迭代器u
和begin
,它们定义范围[begin,end] - end
属于范围,但是{{1不是,
在你写的*begin
的定义中
*end
与上述假设不一致。如果mergesort
,则int *q=((u-p)/2)+p;
mergesort(arr,p,q);
mergesort(arr,q+1,u);
可能相等q
。
p
表示对范围[p,q)进行排序(u == p+1
超出范围)
mergesort(arr,p,q);
表示对范围[q + 1,u)进行排序(q
超出范围)
如果您使用指针表示范围是一致的,那么您永远不会以这种方式触及元素mergesort(arr,q+1,u);
。
将范围视为[begin,end]而不是[begin,end](在第二种情况下u
是范围的一部分)与在C ++中使用迭代器的方式一致,但它不是强制性的。您也可以使用指针来定义范围,但在这种情况下,您必须将调用*q
更改为*end
。 在这两种情况下,您必须重新考虑开头引用的代码中的条件。
这是一个家庭作业,所以我不会为你解决它,但这里有一点暗示,这可能有助于思考它。重新定义您的mergesort(arr,&arr[0],&arr[n]);
,因此明确合并需要2个范围:
mergesort(arr,&arr[0],&arr[n-1]);
并思考如何使用它。稍后你可以简化一些事情。您并不真正需要目标参数,并且您不必复制所有合并元素。您可以先复制一个范围,然后直接合并到目标中,从第一个范围的副本和第二个范围中获取元素。
答案 1 :(得分:1)
在主要情况下,如果您在每次调用printf("*** n=%d\n", n)
之前添加print
,您会注意到,在第二次调用之前,输出为n=61
。也就是说,您正在对阵列进行良好排序,但是当您再次打印它时,您将打印61个数字
你也可以注意到61是数组中最大的数字,n
是在arr
之后定义的,所以n
和arr
将在连续的内存地址中在堆栈中。我认为在n
函数调用期间mergesoft
被覆盖了
实际上,当您使用mergesoft
致电&arr[n]
时,会发生覆盖。数组的最后一个元素的索引为n-1。第n个索引实际上对应于n
变量。将通话更改为:mergesort(arr,&arr[0],&arr[n-1]);