Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 插入排序的过程_C_Algorithm_Insertion Sort - Fatal编程技术网

C 插入排序的过程

C 插入排序的过程,c,algorithm,insertion-sort,C,Algorithm,Insertion Sort,我已经学习排序算法好几天了。目前我正在做插入排序。因此,一般算法是: void insertionSort(int N, int arr[]) { int i,j; int value; for(i=1;i<N;i++) { value=arr[i]; j=i-1; while(j>=0 && value<arr[j]) { arr[j+1]=

我已经学习排序算法好几天了。目前我正在做插入排序。因此,一般算法是:

void insertionSort(int N, int arr[]) {
    int i,j;
    int value;
    for(i=1;i<N;i++)
    {
        value=arr[i];
        j=i-1;
        while(j>=0 && value<arr[j])
        {
            arr[j+1]=arr[j];
            j=j-1;
        }
        arr[j+1]=value;
    }
    for(j=0;j<N;j++)
    {
        printf("%d ",arr[j]);
    }

    printf("\n");
}
void insertionSort(int N,int arr[]){
int i,j;
int值;

对于(i=1;i=0&&value,在每次迭代中,您提供的原始代码通过在循环中移动元素来移动每个元素。对于n元素循环,涉及n+1赋值

可以通过两两交换移动元素来实现插入排序,而不是在更大的循环中。事实上,有时会这样教。这是可能的,因为任何排列(不仅仅是循环)可以表示为一系列交换。通过交换实现一个n元素循环需要n-1交换,每个交换,作为一个2元素循环,需要2+1=3分配。对于大于两个元素的循环,则使用成对交换的方法会做更多工作,按3*(n-1)的比例缩放与n+1相反,这不会改变渐近复杂性,但是,正如你可以看到的,n的指数不会改变

但请注意原始代码和您的代码之间的另一个关键区别:原始代码向后扫描列表以找到插入位置,而您向前扫描。无论您使用成对交换还是更大的循环,向后扫描的优点是,您可以在执行时执行所需的重新排序,以便在找到插入位置后插入位置,完成了。这是使插入排序在比较排序中如此出色的原因之一,也是为什么对于最初几乎已排序的输入,插入排序特别快的原因

向前扫描意味着,一旦找到插入位置,就只能开始。然后必须循环元素。因此,您的方法会在每次迭代中检查已排序数组头的每个元素。此外,当它实际执行重新排序时,它会进行一系列不必要的比较。它可以使用k确认列表的开头已开始排序,只执行一个循环(任意一种方式),而不进行任何比较。额外的比较掩盖了这样一个事实,即代码此时正在执行适当的元素循环(您意识到了吗?)这可能就是为什么有人把你的实现误认为是冒泡排序


从技术上讲,您的仍然是插入排序,但它的实现没有利用抽象插入排序算法的特性,而抽象插入排序算法使编写良好的实现比具有相同渐进复杂性的其他排序具有优势。

插入排序算法和自定义算法之间的主要区别rithm是处理的方向。插入排序算法将范围内较小的元素逐个移动到左侧,而您的算法将范围内较大的元素逐个移动到右侧

另一个关键区别是插入排序和算法的最佳时间复杂度。
如果值您的“自定义”这种方法是冒泡排序。虽然它的复杂程度与插入排序相同,但速度较慢,因为它执行的操作较多(“交换”是三个操作,“移动”只是两个操作).@Ian在整个数组排序之前不会对相邻元素进行冒泡排序…但我不会交换相邻元素。我会从较大数组中取出一部分进行排序,然后再次取出另一部分数组,其中包含上一个数组。然后再次对其进行排序。因此,插入排序可以结束吗?插入后t的工作原理是将整个数组的一个片段用排序后的片段排序到包含前一个片段的下一个更大的片段。我可以知道为什么我的问题会被投反对票吗?它仍然是@JohnBollinger的答案中提到的插入排序,但你执行的操作数(平均)相同作为冒泡排序。如果我反转第二个for循环的迭代顺序,效率会更高吗?@uzumakisaptashi否。反转内部循环的迭代顺序不会影响效率。@uzumakisaptashi,如果反转内部循环的迭代顺序,并使该循环在到达插入位置时停止(即首次发现不需要交换时),那么是的,它将更有效,尽管仍然具有相同的渐进复杂性。但在大多数情况下,它仍将比您首先介绍的实现做更多的工作。OP的自定义排序仍然是插入排序。它只是一个糟糕的实现,确实具有您描述的特征。因此,它具有指导意义:它表明我们通常认为插入排序算法的一些优点不是直接来自算法本身,而是来自它提供的一些实现。
void print_array(int arr_count, int* arr){
        int i;
        for (i=0;i<arr_count;i++){
                printf("%d ",arr[i]);
        }
        printf("\n");

    }

    void swap(int* m, int* n){
        int t = 0;
        t = *m;
        *m = *n;
        *n = t;
    }

    void insertionSort(int arr_count, int* arr) {
        int i, j;

        for(i = 0;i<arr_count;i++){
            for (j=0;j<i;j++){
                if (arr[i] < arr[j]){
                    swap(arr+i, arr+j); 
                  }
            }
            //if (i!=0)
            //print_array(arr_count, arr);
        }

    print_array(arr_count, arr);
    }