前言:本文主要是用JavaScript
实现数据结构中的各种排序算法,例如:插入排序
、希尔排序、合并排序等。
冒泡排序
function bubbleSort(arr) { console.time("冒泡排序")var num = 0; for (var i = arr.length; i > num; num++) { for (var j = i - 1; j > num; j--) { if(arr[j-1]>arr[j]){ var temp = arr[j-1]; arr[j-1] = arr[j]; arr[j] = temp; } } } console.timeEnd("冒泡排序") return arr } var arr = [12, 290, 219, 278, 4432,21, 43, 89, 78]; console.log( bubbleSort(arr));
时间复杂度: 最差 O(n2) ; 最优 O(n)
插入排序
插入排序的基本原理如下图:从前向后构建有序序列,对于未排序序列,在已排序的序列中从后向前扫描插入位置,对于第p个元素,需要扫描p-1次,平均来说插入排序算法复杂度为O(n2)
function insertSort(arr) { console.time("插入排序") var len = arr.length; if (len <= 1) { return arr; } // 1~n-1趟排序 arr.map(function(item,index){ if(index>0){ for (var j = index; j > 0 && arr[j - 1] > item; j--) { arr[j] = arr[j - 1]; } arr[j] = item; } }); console.timeEnd("插入排序") return arr } var arr = [12, 290, 219, 278, 4432, 21, 43, 89, 78]; console.log(insertSort(arr));
希尔排序
shell排序也称为递减增量排序,效果比插入排序更好,对于不同的增量,排序性能也不同
下面我们看看 步长选择为并且对步长取半直到步长达到1的算法实现。
function shellSort(arr) { console.time("希尔排序") var gap, i, j; var temp; for (gap = arr.length >> 1; gap > 0; gap >>= 1) for (i = gap; i < arr.length; i++) { temp = arr[i]; for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) arr[j + gap] = arr[j]; arr[j + gap] = temp; } console.timeEnd("希尔排序") return arr } var arr = [12, 290, 219, 278, 4432, 21, 43, 89, 78]; console.log(shellSort(arr));
算法实现过程如下:这里我们选择 步长为4:(每一列相当于一次插入排序)
12 190 219 278 4432 21 43 89 78 // 第一次排序之后得到: 12 21 43 89 78 190 219 278 4432 // 连接起来得到的是 [12,21,43,89,78,190,219,278,4432],接着以2为步长 排序之后变为: 12 21 43 89 78 190 219 278 4432 // 然后就是简单的插入排序
平均时间复杂度为:
快速排序
快排的思想也很简单,以升序为例,在序列中选一标杆,一般讲第一个元素作为标杆,然后将序列中比标杆小的元素放到标杆左边,将比标杆大的放到标杆右边。然后分别在左右两边重复这样的操作。
快速排序的关键在于选取中心枢纽povit,该值可以随机选择,但是不同的选择会有所影响,在这里我直接选择了最左端的元素
void ksort(int a[], int l, int r) {
// 长度小于2有序
if (r - l < 2) return;
int start = l, end = r;
while (l < r) {
// 向右去找到第一个比标杆大的数
while (++l < end && a[l] <= a[start]);
// 向左去找第一个比标杆小的数9 while(--r > start && a[r] >= a[start]);
if (l < r) swap(a[l], a[r]); // 前面找到的两个数相对于标杆逆序 ,需交换过来 。l==r 不需要交换,
}
swap(a[start], a[r]); // 将标杆挪到正确的位置.
// 对标杆左右两边重复算法,注意,这个l已经跑到r后面去了
ksort(a, start, r);
ksort(a, l, end);
}
快速排序实现2: (以中间的为基准值)
1 function qSort(arr) { 2 if (arr.length <= 1) { 3 return arr; 4 } 5 var num = Math.floor(arr.length / 2); 6 7 var numValue = arr.splice(num, 1)[0]; 8 var left = [], 9 right = []; 10 for (var i = 0; i < arr.length; i++) { 11 if (arr[i] < numValue) { 12 left.push(arr[i]); 13 } else { 14 right.push(arr[i]); 15 } 16 } 17 return qSort(left) 18 .concat([numValue], qSort(right)) 19 } 20 21 console.log(qSort([32, 45, 37, 16, 2, 87]))
快速排序的平均时间复杂度为O(NLogN)
合并排序
合并排序采用分治法的思想对数组进行分治,对半分开,分别对左右两边进行排序,然后将排序后的结果进行合并。按照这样的思想,递归做是最方便的。
1 int a[N], c[N]; 2 void mergeSort(l, r) { 3 int mid, i, j, tmp; 4 if (r - 1 > l) { 5 mid = (l + r) >> 1; 6 // 分别最左右两天排序 7 mergeSort(l, mid); 8 mergeSort(mid, r); 9 // 合并排序后的数组 10 tmp = l; 11 for (i = l, j = mid; i < mid && j < r;) { 12 if (a[i] > a[j]) c[tmp++] = a[j++]; 13 else c[tmp++] = a[i++]; 14 } 15 // 把剩余的接上 16 if (j < r) { 17 for (; j < r; j++) c[tmp++] = a[j]; 18 } else { 19 for (; i < mid; i++) c[tmp++] = a[i]; 20 } 21 // 将c数组覆盖到a里 22 for (i = l; i < r; i++) { 23 a[i] = c[i]; 24 } 25 } 26 }
结束语
更新几种排序算法的实现