插入通过交换排序

时间:2016-10-14 19:58:16

标签: c++ c algorithm sorting

我刚刚开始使用DSA,并对插入排序提出了疑问。

这是教科书/教程的版本。

void insertion_sort(int A[], int n) {
    for (int i = 0; i < n; i++) {
        int temp = A[i];    
        int j = i;

        while (temp < A[j - 1] && j > 0) {
            A[j] = A[j - 1];   
            j = j - 1;
        }
        A[j] = temp;       
    }  
}

如果我们使用swapping数字而不是移动数字并将temp值插入正确的孔位置,我认为它会有所作为。

void insertionSort(int A[], int n) {
    for (int i = 0; i < n; i++) {
        int temp = A[i];
        int j = i;

        while (temp < A[j - 1] && j > 0) {
            swap(A[j], A[j - 1]);
            j--;
        }
    }
}

交换代码:

void swap(int &a,int &b){
    int temp = a;
    a = b;
    b = temp;
}

哦,如果有人能解释两者的时间复杂性,那真是太棒了。

2 个答案:

答案 0 :(得分:1)

在最坏的情况下,两种方法的时间复杂度为O(N ^ 2)。但是第二种方法中的操作次数与第一种方法相比更多,因为第二种方法执行与第一种方法中的移位次数相同的交换次数,但交换需要3次分配,而移位中只有一次。基于的方法。因此,与仅移动元素相比,您提出的方法将更慢。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>

void insertion_shift(int* arr, int n){
    int i,j,k;
    for(i=1;i<n;++i){
        int temp=arr[i];
        for(j=i;j>0 && arr[j-1]>temp;--j)
            arr[j]=arr[j-1];
        arr[j]=temp;
    }
}
void swap(int* a, int* b){
  int temp= *a;
  *a= *b;
  *b= temp;
}

void insertion_swap(int* arr, int n){
   int i,j,k;
   for(i=1;i<n;++i){
      int temp=arr[i];
      for(j=i;j>0 && arr[j-1]>temp;--j)
         swap(&arr[j-1],&arr[j]);
   }
 }      

void print_arr(int* arr, int n){
   int i;
   for(i=0;i<n;++i)
      printf("%d ",arr[i]);
   printf("\n");
}

int main(){
   int n;
   scanf("%d",&n);
   int* arr1= (int*)malloc(sizeof(int)*n);
   int* arr2= (int*)malloc(sizeof(int)*n);
   int i;
   for(i=0;i<n;++i){
      scanf("%d",&arr1[i]);
      arr2[i]=arr1[i];
   }

   struct timespec start, end;
   clock_gettime(CLOCK_MONOTONIC_RAW,&start);
   insertion_shift(arr1,n);
   clock_gettime(CLOCK_MONOTONIC_RAW,&end);
   uint64_t time_shift= (end.tv_sec - start.tv_sec)*1000000 +
                        (end.tv_nsec - start.tv_nsec)/1000;
   printf("using shift: %lld microseconds\n",time_shift);

   clock_gettime(CLOCK_MONOTONIC_RAW,&start);
   insertion_swap(arr2,n);
   clock_gettime(CLOCK_MONOTONIC_RAW,&end);

   uint64_t time_swap= (end.tv_sec - start.tv_sec)*1000000 +
                       (end.tv_nsec - start.tv_nsec)/1000;
   printf("using swap: %lld microseconds\n",time_swap);

}

这是我在同一个大小为10000的数组上调用这两个函数时得到的结果。Compilation and execution for 10000 elements array。如果仍然不相信,请尝试生成大小为1000-10000的随机数组并运行上面的代码来观察差异。

答案 1 :(得分:0)

您建议的替代方案不完整,您没有发布swap()的代码。在C中,swap必须是一个宏,并且这样的宏很容易破坏,而在C ++中,它可以是一个通过引用接受两个参数的函数。

此外,您应该在取消引用j > 0之前测试A[j - 1] 。发布后,代码会调用未定义的行为。

关于你的问题,两个函数同样慢,时间复杂度为 O(N 2 ,但第二个函数可能更慢,因为交换涉及更多的读写操作而不是简单地将值移动一个位置,但在排序的数组上可能更快,因为第一个版本有冗余存储。

请注意,您可以通过这种方式以效率为代价进一步简化代码:

void insertionSort(int A[], int n) {
    for (int i = 1; i < n; i++) {
        for (int j = i; j > 0 && A[j] < A[j - 1]; j--) {
            swap(A[j], A[j - 1]);
        }
    }
}