我刚刚开始使用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;
}
哦,如果有人能解释两者的时间复杂性,那真是太棒了。
答案 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]);
}
}
}