如何使用事件驱动的比较编写QuickSort?

时间:2017-02-19 04:38:27

标签: javascript javascript-events quicksort

我正在编写一个网络应用程序,向用户询问一系列问题,这些问题只是两个值的主观比较。他们选择一个更大的那个,它提出了排序所需的下一个比较。目标是对58个项目进行排序,并显示有序列表。

我想使用QuickSort,因为80%的时间它需要比合并排序更少的比较,这需要342次比较。 (我编写了一个程序,运行5,000,000次模拟58项数组排序,发现342是QS所需比较次数的第80个百分点。)由于这是在JavaScript中完成的,我需要算法等待每次需要比较时触发事件,然后,当触发事件时,继续算法。我很难绕过这看起来像什么。

我非常肯定为了以这种方式实现QS - 除非有一些聪明的JavaScript闭包方法,我没想到 - 我不能递归地做。我找到了一个iterative implementation of QS,并试图弄清楚如何将其拆分,以便事件触发器将从中断处继续算法。

我会发布我的代码,但老实说,我认为这是多么混乱和脱节,它会带来更多弊大于利。我喜欢JavaScript中的完整实现,但即使是伪代码也会有所帮助。

1 个答案:

答案 0 :(得分:3)

我使用JavaScript Promises和递归来解决这个问题。我认为这是一个非常干净的解决方案。

class QS {
    constructor(array) {
        this._array = array;
        this._comparisons = 0;
    }

    run() {
        new Promise(r => {
            return this.runQS(0, this._array.length - 1, r);
        }).then(() => {
            console.log(this._array);
            console.log(this._comparisons);
        });
    }

    runQS(low, high, resolve, part) {
        if (low < high) {
            return new Promise(r => {
                this.partition(low, high, r);
            }).then(p => {
                return new Promise(r => {
                    this.runQS(low, p - 1, r, p);
                });
            }).then(p => {
                return new Promise(r => {
                    this.runQS(p + 1, high, r, p);
                });
            }).then(() => {
                resolve(part);
            });
        } else {
            resolve(part);
        }
    }

    partition(low, high, res) {
        let self = this,
            i = low - 1,
            j = low,
            partProm = Promise.resolve();

        function inner(i, j, doSwap) {
            if (doSwap) {
                i++;
                self.swap(i, j);
            }

            j++;
            if (j < high) {
                addThen(i, j);
            } else {
                i++;
                self.swap(i, high);
                res(i);
            }
        }

        function addThen(i, j) {
            partProm = partProm.then(() => {
                self._comparisons++;
                return new Promise(r => {
                    promptUser(self._array, j, high, r);
                });
            }).then(s => {
                inner(i, j, s);
            });
        }

        if (low < high) {
            addThen(i, j);
        }
    }

    swap(i, j) {
        let temp = this._array[i];
        this._array[i] = this._array[j];
        this._array[j] = temp;
    }
}

promptUser()的占位符只是:

function promptUser(a, i, j, resolve) {
    setTimeout(() => {
        console.log('Comparing ' + a[i] + ' against ' + a[j]);
        resolve(a[i] < a[j]);
    }, 10);
}

resolve传递给由按钮onclick触发的函数并不太难。