javascript 数组排序原理的简单理解

js内置的Array函数原型对象有个sort方法,这个方法能按照顺序排序数组。

例如:

1 var arr1 = [6, 4, 2, 5, 2];
2 arr1.sort((x, y) => x - y);
3 console.log(arr1); // [2, 2, 4, 5, 6];

以升序为例,这个方法的实现原理的简单理解:

第一轮比较。

先拿第一个数和第二个数字比较,如果第一个比第二个大,则交换位置。

接着又拿第一个数和第三个数比较,如果第一个比第三个大,则交换位置。

。。。

最后拿第一个数与最后一个数比较,如果第一个数比最后一个数大,则交换位置。

以上是第一轮比较。经过第一轮的比较。第一个数,就是数组中值最小的数了。

用上述例子来描述第一轮比较的过程,如图:

 

接着开始第二轮比较

先拿第二个数与第三个数比较,如果第二个比第三个大,则交换位置。

然后又拿第二个数和第四个数比较,如果第二个比第四个大,则交换位置。

。。。

最后拿第二个数与最后一个数比较,如果第二个数比最后一个数大,则交换位置。

以上是第二轮比较。经过第二轮的比较。第二个数,就是数组中值的第二小的数了。

用上述例子来描述第二轮比较的过程,如图:

 循环往复直至全部都比较完。

 

上述例子的比较过程的代码演示:

 1 function mySort(arr, cb) {
 2   window.count = 0;// 统计循环次数
 3   const res = cb && cb(1, 2);
 4   let i, j, len = arr.length;
 5   if (res < 0) {// 升序
 6     for (i = 0; i < len; i++) {
 7       for (j = i + 1; j < len; j++) {
 8         count++;
 9         if (arr[i] > arr[j]) {
10           [arr[i], arr[j]] = [arr[j], arr[i]];
11         }
12       }
13     }
14   } else {// 降序
15     for (i = 0; i < len; i++) {
16       for (j = i + 1; j < len; j++) {
17         count++;
18         if (arr[i] < arr[j]) {
19           [arr[i], arr[j]] = [arr[j], arr[i]];
20         }
21       }
22     }
23   }
24 }

这种排序方法循环次数为 (len - 1) * len / 2。

验证:

1 const arr = [];
2 for (let i = 0; i < 10; i++) {
3   arr.push(Math.floor(Math.random()*100));
4 }
5 mySort(arr, (x, y) => x - y);

结果:

 

采用排序二叉树结构的算法。代码演示:

 1 function mySort(arr, cb) {
 2   const res = cb && cb(1 ,2);
 3   class Node {
 4     constructor(key) {
 5       this.key = key;
 6       this.left = null;
 7       this.right = null;
 8     }
 9   };
10   class BinaryTree {
11     constructor(key) {
12       this.root = null;
13       this.init(key);
14     }
15     init(key) {
16       this.root = new Node(key);
17     }
18     insert(key) {
19       const newNode = new Node(key);
20       this._insertNode(this.root, newNode);
21     }
22     _insertNode(root, node) {
23       if (node.key < root.key) {
24         if (!root.left) {
25           root.left = node;
26         } else {
27           this._insertNode(root.left, node);
28         }
29       } else {
30         if (!root.right) {
31           root.right = node;
32         } else {
33           this._insertNode(root.right, node);
34         }
35       }
36     }
37     inorderTraversal(callback) {
38       if (res < 0) {
39         this._inorderTraversalNodeSmall(this.root, callback);
40       } else {
41         this._inorderTraversalNodeBig(this.root, callback);
42       }
43     }
44     _inorderTraversalNodeSmall(node, callback) {
45       if (!!node) {
46         this._inorderTraversalNodeSmall(node.left, callback);
47         callback(node);
48         this._inorderTraversalNodeSmall(node.right, callback);
49       }
50     }
51     _inorderTraversalNodeBig(node, callback) {
52       if (!!node) {
53         this._inorderTraversalNodeBig(node.right, callback);
54         callback(node);
55         this._inorderTraversalNodeBig(node.left, callback);
56       }
57     }
58   }
59 
60   const binaryTree = new BinaryTree(arr[0]);
61   let i, len;
62   for(i = 1, len = arr.length; i < len; i++) {
63     binaryTree.insert(arr[i]);
64   }
65   const _arr = [];
66   binaryTree.inorderTraversal(node => {
67     _arr.push(node.key);
68   });
69   return _arr;
70 }

测试:

1 const arr = [];
2 for (let i = 0; i < 10; i++) {
3   arr.push(Math.floor(Math.random()*100));
4 }
5 const newArr1 = mySort(arr, (x, y) => y - x);
6 const newArr2 = mySort(arr, (x, y) => x - y);

结果:

 

当数组比较大的时候,后面这种算法的优势明显。

现以后面这种算法为例,测试代码:

1 const arr = [];
2 for (let i = 0; i < 5000000; i++) {
3   arr.push(Math.floor(Math.random()*50000000));
4 }
5 const time = new Date().getMinutes() + ':' + new Date().getSeconds();
6 mySort(arr, (x, y) => x - y);
7 const nextTime = new Date().getMinutes() + ':' + new Date().getSeconds();

结果:

数组长度为5000000时,函数大概运行了6秒。

如果以第一种算法为例,5000000估计要好几分钟,这里缩减一下,设置成50000。测试代码:

1 const arr = [];
2 for (let i = 0; i < 50000; i++) {
3   arr.push(Math.floor(Math.random()*50000000));
4 }
5 const time = new Date().getMinutes() + ':' + new Date().getSeconds();
6 mySort(arr, (x, y) => x - y);
7 const nextTime = new Date().getMinutes() + ':' + new Date().getSeconds();

结果:

数组长度为50000时,函数大概运行了10秒。

第一种算法的耗时貌似也不是平滑增加的。估计也是一条陡峭的曲线。数学知识都忘光了。以后搞明白了在来完善。

二叉树的实现原理的简单理解

posted @ 2019-07-13 01:47  chulai9527  阅读(608)  评论(0编辑  收藏  举报