使用BubbleSort进行完全排序所需的通行证数量?

时间:2019-06-10 14:56:59

标签: algorithm sorting bubble-sort

我正在调查将[1,n]中的整数array[n]的每种可能组合排序所需的遍数背后的数学。

例如,对于n = 3,有3! = 6个可能的数字排列:

1,2,3 - 1,3,2 - 2,1,3 - 2,3,1 - 3,1,2 - 3,2,1.
  • 这些初始排列之一需要k = 0传递(1,2,3)才能将数组按升序排序;
  • 其中三个要求k = 1通过(1,3,2 - 2,1,3 - 3,1,2)
  • 有两个要求k = 2通过(2,3,1 - 3,2,1)

基本上,我希望能够从数学上得出给定{k}的通过次数n的集合。

对于n = 4,需要k次通过的初始置换P的数量为P(n,k) = 1,7,10,6 for k = 0,1,2,3

当然,对于k = 0(已经升序),只有1个初始置换,即P(n,0) = 1,并且k的最大值(n-1)的初始置换的数量为k !,即P(n,n-1) = (n-1)!。或者,至少我是这样认为的...

我觉得这比我做的要简单,并且涉及阶乘公式。

2 个答案:

答案 0 :(得分:1)

用于生成置换的算法为Heap's algorithm。此代码是用于计算n对象的排列的蛮力方法。对于每种配置,通过次数是元素从其排序位置O(n)开始的最大长度。给定n,这将通过执行直方图给出所有P(n, k)n中的运行时间是指数级的(以C为单位)

#include <stdlib.h> /* EXIT */
#include <stdio.h>  /* printf */
#include <assert.h> /* assert */
#include <errno.h>  /* errno, ERANGE */

typedef void (*PermuteFunc)(const size_t a_size);

unsigned a[12];
const size_t a_max = sizeof a / sizeof *a;

/* https://en.wikipedia.org/wiki/Heap%27s_algorithm#cite_note-3 */
static void heaps_r(const size_t a_size, const unsigned k,
    const PermuteFunc func) {
    size_t i, j;
    assert(k && a_size);
    if(k == 1) { func(a_size); return; }
    for(i = 0; i < k; i++) {
        heaps_r(a_size, k - 1, func);
        if(i >= k - 1) continue;
        j = (k & 1) ? 0 : i; /* Odd/even. */
        a[j] ^= a[k-1], a[k-1] ^= a[j], a[j] ^= a[k-1]; /* Swap. */
    }
}

/* Generates all permutations of size `a_size` and passes them to `func`.
 @return Success. */
static int heaps(const size_t a_size, const PermuteFunc func) {
    size_t i;
    assert(func);
    if(!a_size || a_size > a_max) return errno = ERANGE, 0;
    for(i = 0; i < a_size; i++) a[i] = i + 1; /* Distinct numbers. */
    heaps_r(a_size, a_size, func);
    return 1;
}

static unsigned histogram[256]; /* This is good enough, right? */
static size_t histogram_size = sizeof histogram / sizeof *histogram;

/* @implements PermuteFunc */
static void print(const size_t a_size) {
    size_t i, bin = 0;
    assert(a && a_size);
    for(i = 0; i < a_size; i++) printf("%d ", a[i]);
#if 0 /* I misread the question. */
    /* O(n^2) way to calculate the Kendall tau distance. */
    for(i = 0; i < a_size; i++) {
        size_t j;
        for(j = i + 1; j < a_size; j++) if(a[i] > a[j]) bin++;
    }
#else
    /* Calculate the number of passes bubble-sort needs to make. */
    for(i = 0; i < a_size; i++) {
        size_t passes = abs(a[i] - i);
        if(passes > bin) bin = passes;
    }
#endif
    if(bin >= histogram_size) {
        fprintf(stderr, "Histogram too small for %d.\n", (unsigned long)bin);
        return;
    }
    histogram[bin]++;
    printf("-> %d\n", bin);
}

int main(int argc, char **argv) {
    int n;
    size_t k;
    const char *err = 0;
    do {
        if(argc != 2 || (n = atoi(argv[1]), n <= 0))
            { errno = EDOM; err = "Argument needed"; break; }
        if(!heaps(n, &print)) { err = "Heap's"; break; }
        printf("\n");
        for(k = 0; k < histogram_size; k++) if(histogram[k])
            printf("P(%d, %lu) = %u\n", n, (unsigned long)k, histogram[k]);
    } while(0);
    return err ? (perror(err), EXIT_FAILURE) : EXIT_SUCCESS;
}

通过4,我明白了

P(4, 1) = 1
P(4, 2) = 7
P(4, 3) = 10
P(4, 4) = 6

我用Google搜索了Kendall tau距离代码,发现它是coefficients in expansion of Product_{i=0..n-1} (1 + x + ... + x^i),但是带有冒泡排序的代码与任何文档都不匹配。

答案 1 :(得分:0)

取决于实现: 如果您只沿一个方向前进,那么当目标位于与迭代方向相反的方向时,任何元素都将最多离目标更近一步。因此,所需的迭代次数由任何单个元素在该方向上移动所需的最大距离确定。

如果来回迭代,则不太明显。我怀疑通过转换为有向图(每个边缘指向需要与之交换的其他元素),边缘的属性将给出答案。