【问题标题】:Identifying this form of sorting algorithm and calculating its time complexity识别这种形式的排序算法并计算其时间复杂度
【发布时间】:2022-01-20 19:27:46
【问题描述】:

在尝试排序时,我想出了一种类似于某种插入排序的排序。

不同之处在于,在交换时,我不必比较从元素索引到索引 0 的元素(最坏情况)。

它也类似于分治排序算法,因为它在同一数组中模拟已排序的扇区和未排序的扇区。

我的看法是,最初我会将当前元素指定为第一个元素。 然后我会将当前元素与下一个元素进行比较。如果电流更大,我交换元素。然后我递减以保持当前索引不变。

否则,我会递增以推进当前索引。

这意味着我的电流将始终是最新的参考值。比较的其他值总是较小且已排序。

请参考代码:

#include<stdio.h>

void printArray(int *a, int l)
{
    int i = 1;
    printf("[%d", a[0]);
    while(i < l)
    {
        printf(", %d", a[i]);
        ++i;
    }
    printf("]\n");
}

void whatSort(int *a, int l)
{
    int i = 0;
    int temp;

    while(i < (l - 1))
    {
        if(*(a + i) > *(a + i + 1))
        {
            temp = *(a + i);
            *(a + i) = *(a + i + 1);
            *(a + i + 1) = temp;
            --i;
        }
        else
        {
            ++i;
        }
    }
}

int main(void)
{
    //int array[] = {42, 18, 74, 2, 35, 92, 37, 25};
    int array[] = {6, 5, 3, 1, 8, 7, 2, 4};
    printArray(array, 8);
    whatSort(array, 8);
    printArray(array, 8);
    return 0;
}

我很确定这种类型(双关语)已经存在,但我无法找到名称。很高兴知道它叫什么。不过,我希望帮助计算仅用于此类的代码段的运行时复杂度。这就是我想出的。任何帮助将不胜感激。

对于这种特殊情况,假设每个操作需要 1 个时间单位。

Declaration
Assignment
Declaration

Loop condition will run l - 1 times:
    Comparison
    Subtraction

Loop inside code will run l - 2 times:
    IF statement:
        Dereference
            Addition
        Comparison
        Dereference
            Addition
            Addition
    Assignment
    Dereference
        Addition
    Dereference
        Addition
    Assignment
    Dereference
        Addition
        Addition
    Dereference
        Addition
        Addition
    Assignment
    Decrement

    OR

    ELSE statement:
        Increment

最终,我想出 O(n) 其中:

Worst case = 3 + [2 * (l - 1)] + [6 * (l - 2)] + [14 * (l - 2)]
    O(22n - 39)
    O(n)
Best case = 3 + [2 * (l - 1)] + [6 * (l - 2)] + (l - 2)
    O(9n - 13)
    O(n)

【问题讨论】:

  • 这只是一个非常慢的插入排序,所以 O(n^2)。最坏的情况是一个以相反顺序开始的数组,例如int array[] = {9,8,7,6,5,4,3,2,1}; 每次i 到达数组排序部分的末尾,算法需要将下一个数字一直带回数组的开头。这就是插入排序的工作方式,但插入排序做得更快。然后该算法会浪费大量时间来查找已排序部分的结尾。插入排序会跟踪已排序部分的末尾在哪里,然后就跳到那里。
  • 使用我建议的数组。将printf("%d\n", i); 放在循环的顶部。在此处发布结果。
  • 我已经做到了。 i 递增,直到到达已排序部分的末尾。然后它递减直到到达数组的开头。
  • 想象算法已经进行到数组是[6,7,8,9,5,4,3,2,1]i=3array[i] 是9。现在代码比较9 和5,交换它们,并递减i。所以现在array[i] 是 8。比较 8 和 5,交换它们,然后递减 i。该算法必须一直这样做,直到 i 为 0,因为 5 必须在排序部分的开头。
  • 丹尼斯·里奇有一个绝妙的主意,他决定将*(a+i) 写成a[i]

标签: c algorithm sorting time-complexity big-o


【解决方案1】:

抱歉,没有比 O(n log n) 更好的排序算法,除非你对输入设置一些限制。

目前此代码不起作用。

例如,如果第一个元素大于第二个元素(在您的示例中就是这种情况),则 i 会递减。最初是i=0,现在是i=-1。循环重新启动,您尝试访问a[-1],并发生分段错误。错误是

然后我递减以保持当前索引不变。

这不是发生的事情,正如你所说,索引会减少,所以不会保留值。

This is the ouput

编辑:

即使这种情况得到纠正,以下情况也不正确

循环内部代码将运行 l - 2 次:

该算法总是试图将第 (i+1) 个元素放到正确的位置,最坏的情况是将它带到第一个位置。

index == 0 时,您最多进行一次交换。 当index == 1 时,您最多进行两次交换。 当index == 2 时,您最多进行三个交换。

这种情况会一直发生,直到您到达数组的末尾。 所以,1x2x3x...x(n-1),也就是 O(n²)

【讨论】:

  • 代码按预期工作。无论哪种方式,我们都可以通过仅在 i != 0 时添加减量来规避此问题。
  • 我展示了另一个案例。关键是:您需要从索引 0 开始断言子数组,直到对 i 进行排序。
  • 您好,感谢您查看代码。正如我所提到的,如果我只减少i != 0,这个问题是否仍然存在?
  • 是的,现在使用了 20、30、10,我看到了分段错误。我还不太清楚。
  • 啊,没关系必须更改数组长度参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多