Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Sort #9

Open
barretlee opened this issue May 25, 2016 · 0 comments
Open

Merge Sort #9

barretlee opened this issue May 25, 2016 · 0 comments

Comments

@barretlee
Copy link
Owner

#6#8 是都是从头到尾去遍历数据,不可避免的带来很多交换操作。归并排序是一种用空间换时间的排序算法,一个数组截断成两个子数组,子数据排好序后合并到一起。

/chapters/chapter-2-sorting/2.2-mergesort/merge.js

function merge(input1, input2) {
  var i = 0, j = 0;
  var output = [];
  while(i < input1.length || j < input2.length) {
    if(i == input1.length) {
      output.push(input2[j++]);
      continue;
    }
    if(j == input2.length) {
      output.push(input1[i++]);
      continue;
    }
    if(input1[i] < input2[j]) {
      output.push(input1[i++]);
    } else {
      output.push(input2[j++]);
    }
  }
  return output;
}

上面是一个简单的合并算法,将两个有序数据合并为一个。有人应该会想到,既然一个数组可以打散成两个进行排序,那被打算的子数组是不是也可以继续被打散呢?

答案是肯定的。这是一种典型的分治思想,递归归并。

/chapters/chapter-2-sorting/2.2-mergesort/mergeRecursiveTop2Bottom.js

function mergeRecursiveTop2Bottom(input) {

  return sort(input, 0, input.length - 1);

  function sort(arr, start, end) {
    if(start >= end) {
      return;
    }
    var mid = ((end - start) >> 1) + start;
    sort(arr, start, mid);
    sort(arr, mid + 1, end);
    return merge(arr, start, mid, end);
  }

  function merge(arr, start, mid, end) {
    var i = start, j = mid + 1, tmp = [];
    for(var k = start; k <= end; k++) {
      tmp[k] = arr[k];
    }
    for(k = start; k <= end; k++) {
      if(i > mid) {
        arr[k] = tmp[j++];
        continue;
      }
      if(j > end) {
        arr[k] = tmp[i++];
        continue;
      }
      if(tmp[i] < tmp[j]) {
        arr[k] = tmp[i++];
      } else {
        arr[k] = tmp[j++];
      }
    }
    return arr;
  }
}

上面的算法是自顶向下的递归归并,简单来说就是解决很多小问题,那么大问题也就自然而然的解决了;还有一种自底向上的归并,这种归并简单来说,就是把一个大问题分解为多个小问题,多个小问题的答案就能得出大问题的答案。从解决问题的方式来看,两种处理方式是互逆的。

/chapters/chapter-2-sorting/2.2-mergesort/mergeRecursiveTop2Bottom.js

function sort(arr) {
  for(var sz = 1, len = arr.length; sz < len; sz = sz * 2) {
    for(var start = 0; start < len - sz; start += sz * 2) {
      arr = merge(arr, start, start + sz - 1, Math.min(start + sz * 2 - 1, len - 1));
    }
  }
  return arr;
}
// merge 函数同上

不过自底向上的归并,在代码上稍微难理解一些,脑海重要有清晰的画卷,知道程序跑到哪一步了,尤其还需要处理边界问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant