希尔排序原理:
1.选定一个增长量h,按照增长量h作为数据分组的依据,对数据进行分组。
2.对分好的每一组进行插入排序。
3.减小增长量,最小减为1,重复2操作。
//希尔排序:O(log(n))
let arr = [4, 3, 2, 1, 6, 5, 7, 9, 8, 5]
//1.首先根据数组的长度,确定增长量h的值
let h = 1
while (h < arr.length / 2) {
h = 2 * h + 1
}
//2.开始排序
while (h >= 1) {
for (let i = h; i < arr.length; i++) {
for (let j = i; j >= h; j -= h) {
if (arr[j] > arr[j - h]) {
let temp = arr[j]
arr[j] = arr[j - h]
arr[j - h] = temp
} else {
break
}
}
}
//取整
h = parseInt(h / 2)
}
归并排序原理:
1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
2.将相邻的两个子组进行合并成一个有序的大组。
3.不断的重复步骤2,直到最终只有一个组为止。
//归并排序:O(nlogn)
//辅助数组
let assist = null
function sort(arr) {
//初始化辅助数组
assist = new Array(arr.length)
//定义一个lo变量和hi变量,分别记录数组中最小索引和最大索引
let lo = 0
let hi = arr.length - 1
sortGroup(arr, lo, hi)
document.getElementById("div1").innerText = arr
}
//分组排序
function sortGroup(arr, lo, hi) {
if (lo >= hi) {
return
}
//拆分
//对lo和hi之间的数组分为两组
let mid = parseInt(lo + (hi - lo) / 2)
sortGroup(arr, lo, mid)
sortGroup(arr, mid + 1, hi)
console.log("lo:"+lo+"||"+"mid:"+mid+"||"+"hi:"+hi);
//再把两个组中的数据进行归并
merge(arr, lo, mid, hi)
}
//归并
function merge(arr, lo, mid, hi) {
//定义三个指针
let i = lo
let p1 = lo
let p2 = mid + 1
//遍历,移动p1,p2指针,比较对应索引处的值,找出小的那个,放到辅助数组对应的索引处
while (p1 <= mid && p2 <= hi) {
if (arr[p1] < arr[p2]) {
assist[i++] = arr[p1++]
} else {
assist[i++] = arr[p2++]
}
}
//遍历走完p1还没走完的索引
while (p1 <= mid) {
assist[i++] = arr[p1++]
}
//遍历走完p2还没走完的索引
while (p2 <= hi) {
assist[i++] = arr[p2++]
}
//将辅助数组中的数据拷贝到原数组
for (let index = lo; index <= hi; index++) {
arr[index] = assist[index]
}
}
//待排序数组
let arr = [8, 4, 5, 7, 1, 3, 6, 2]
//调用排序方法
sort(arr)
快速排序原理:
1.首先设定一个分界值,通过该分界值将数组分成左右两部分。
2.将大于或等于分界值的数据放到到数组右边,小于分界值的数据放到数组的左边。此时左边部分中各元素都小于
或等于分界值,而右边部分中各元素都大于或等于分界值。
3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两
部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当
左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了。
//快速排序
function sort(arr) {
//初始化辅助数组
assist = new Array(arr.length)
//定义一个lo变量和hi变量,分别记录数组中最小索引和最大索引
let lo = 0
let hi = arr.length - 1
sortGroup(arr, lo, hi)
document.getElementById("div1").innerText = arr
}
function sortGroup(arr, lo, hi) {
if (hi <= lo) {
return
}
//需要对数组中lo索引到hi索引处的元素进行分组
let partition = partition(arr, lo, hi)
//让左子树有序
sortGroup(arr, lo, partition - 1)
//让右子树有序
sortGroup(arr, partition + 1, hi)
}
//对数组a中,从索引lo到索引hi之间的元素进行分组,并返回分组界限对应的索引
function partition(arr, lo, hi) {
//确定分界值
let key = a[lo]
//定义两个指针,分别指向带切分元素的最小索引处和最大索引处的下一个位置
let right = hi + 1
let left = lo
//切分
while (true) {
//先从右往左扫描,移动right指针,找到一个比分界值小的元素,停止
while (key < a[--right]) {
if (right == lo) {
break
}
}
//在从左往右扫描,移动left指针,找到一个比分界值大的元素,停止
while (a[++left] < key) {
if (left == hi) {
break
}
}
//判断 left >=right,如果是,扫描完毕,否,交换元素
if (left >= right) {
break
} else {
let temp = arr[left]
arr[left] = arr[right]
arr[right] = temp
}
}
let temp = arr[right]
arr[right] = arr[lo]
arr[lo] = temp
return right
}
注:以上均由JS代码编写。