web-dev-qa-db-ja.com

JavaScriptクイックソートの無限再帰?

これが、私が書いた quicksort コードです。この関数は、ベースケースに到達できないため機能しません。ピボットrlをコンソールに記録すると、ソート関数が何度呼び出されても同じままです。したがって、引数lrが実際にデータとして関数に渡されていないのではないかと思います。なぜそれが起こったのですか?

function sort(data){
    if(data.length < 2){
        return data;
    }
    else{
        var l = [];
        var r = [];
        var pivot = parseInt(data.length/2);
        for(i=0; i<data.length; i++){
            if(data[i] > data[pivot]){
                r.Push(data[i]);
            }
            else{
                l.Push(data[i]);
            }
        }
        return sort(l).concat(sort(r));
    }
}
31
Yujun Wu

ここでの問題は、パーティション分割のステップが必ずしも入力配列を縮小するとは限らないことだと思います。たとえば、[1、2]をソートしようとするとどうなるかをトレースしてみましょう。この場合、ピボット要素は要素2になります。1> 2はfalseであるため、リストlに1が追加されます。 2> 2は偽なので、リストlに2が追加されます。その結果、リストlに対する再帰呼び出しは、元の呼び出しとまったく同じ引数を持ち、無限再帰を引き起こします。

これを修正するには、入力を3つのリストに分割してみてください-小さい値の1つ、等しい値の1つ、大きい値の1つ。このコードは次のとおりです。

function sort(data){
  if (data.length < 2){
    return data;
  } else {
    var l = [];
    var r = [];
    var e = [];
    var i = 0;
    var pivot = (data.length / 2) | 0;

    for(i = 0; i < data.length; i++) {
      if (data[i] > data[pivot]) {
        r.Push(data[i]);
      } else if (data[i] < data[pivot]) {
        l.Push(data[i]);
      } else {
        e.Push(data[i]);
      }
    }  
    return sort(l).concat(e, sort(r)); 
  }
}

この新しいバージョンでは、等しい要素を明示的に独自のリストにグループ化しているため、再帰呼び出しのいずれによっても再帰的に並べ替えられません。また、重複する要素を適切に処理します。

お役に立てれば!

332
templatetypedef

配列の最大値をピボット要素として選択すると、dataのすべての値は配列lになり、rにはありません。したがって、再帰が停止することはありません(およびlrpivotを同じ値に保ちます)。これが脳のエクササイズでない限り、data.sort()を使用するとより良い仕事ができるはずです。 ;)

JavaScriptはオブジェクトを参照渡しします(配列もオブジェクトです)。値で渡したい場合は、 here のようにスプライス関数を使用する必要があります。

これにより、データのコピーが大量に作成されることに注意してください。おそらくネイティブのsort()関数を使用したいでしょう。

0
user1115652