内部排序基本类型
- 插入排序(InsertionSort)
- 快速排序(QuickSort)
- 选择排序(SelectSort)
- 归并排序(MergeSort)
- 基数排序(RadixSort)
局部功能函数
- SwapArr(arr, A, B)
- Compare: LT、LQ、EQ、HT、HQ
- Visit(arr)
- CopyArr(arr1, arr2)
- InitArr(arr, item, len)
function SwapArr(arr, A, B)
{
let temp = arr[A]
arr[A] = arr[B]
arr[B] = temp
}
function Visit(arr)
{
let str = ''
for (let i = 0; i < arr.length; i++)
str += `${arr[i]} `
console.log(str)
}
function CopyArr(arr1, arr2, es=0, ee=arr1.length-1)
{
arr1.map((item, inx) => {
if (inx >= es && inx <= ee)
arr2[inx] = item
})
}
function InitArr(arr, df, len)
{
for (let i = 0; i < len; i++)
{
arr.push(df())
}
}
let LT = (A, B) => A < B
let LQ = (A, B) => A <= B
let EQ = (A, B) => A === B
let NQ = (A, B) => A !== B
let HT = (A, B) => A > B
let HQ = (A, B) => A >= B
插入排序
- 直接插入排序
- 折半插入排序
- 2-路插入排序
- 希尔插入排序
/**
* @ InsertionSort
* 1、DirectInsertionSort
* 2、BinaryInsertionSort
* 3、TwoWayInsertionSort
* 4、ShellInsertionSort
*/
//////////////////////////////////////////////////////////////////////////
/*
-----------------------
@ DirectInsertionSort
-----------------------
For example:
A = [2,5,1,8,6]
Process:
index 0 1 2 3 4
init (2) 5 1 8 6
1 (2 5) 1 8 6
2 (1 2 5) 8 6
3 (1 2 5 8) 6
4 (1 2 5 6 8)
Information about the array sort:
Loop times: 4
Total Value: 5
External Compare Times: 3
Internal Compare Times: n(untill find value smaller than it)
Explanation:
Parentheses mean that alreay sorted
Thus, we only use one value compare with values in sorted array
'J' means array's last boundary, of which need 'I' substract 1
to obtain its location
*/
function DirectInsertionSort(arr)
{
// Determinate your loop times
// Calculate Method is len - 1 - 1
// the first one is comparative times and the second one is stored number
for (let i = 1; LT(i, arr.length); i++)
{
// the variable capacity used to temporary storing value inserted
let temp = arr[i]
// filter some value larger than the maximum of array order
if (HQ(temp, arr[i - 1])) continue
// i is insert value's index
// i - 1 is the maximum value's index of array
for (var j = i - 1; LT(temp, arr[j]) && HQ(j, 0); j--)
{
// move it to the next value's position if it larger than the tempary value
arr[j + 1] = arr[j]
}
// j is the index about portion values larger than it
// but this j has already been subtracted one
// as such, we need this j that the position of value plus one
arr[j + 1] = temp
}
}
/*
-----------------------
@ BinaryInsertionSort
-----------------------
For example:
A = [2,5,1,8,6]
Process:
index 0 1 2 3 4
mid = 0 range (1, 4)
1 (2 5) 1 8 6
mid = 1 range 0 or (2, 4)
2 (1 2 5) 8 6
mid = 1 range 0 or (2, 4)
3 (1 2 5 8) 6
mid = 2 range (0, 1) or (3, 4)
4 (1 2 5 6 8)
Information about the array sort:
Loop times: 4
Total Value: 5
External Compare Times: 3
Internal Compare Times: n(untill find value smaller than it)
Explanation:
The First One is 'low' and The Last One is 'high'
Calculate 'mid' via ('low' + 'high') / 2
Search the location for this value via reduce search range
Move values which begin at there behind
*/
function BinaryInsertionSort(arr)
{
// variable statement
let low, high, mid, temp
// continuously set larger 'high' value
for (let i = 1; LT(i, arr.length); i++)
{
// set array range low and high
low = 0; high = i - 1
// build a tempary container
temp = arr[i]
// get out of the loop when 'high' lower than 'low'
while (LQ(low, high))
{
// obtain the middle value of the range between low and high
mid = Math.floor((low + high) / 2)
// compare with middle value, so as to reduce its Search range
if (LT(temp, arr[mid])) high = mid - 1
else low = mid + 1
}
// Now, 'low' maybe a position about this 'temp' value
// We need to move them to next position
for (var j = i - 1; HT(j, high); j--) arr[j + 1] = arr[j]
// Here will be a empty seat offer this value to use
arr[low] = temp
}
}
/*
-----------------------
@ TwoWayInsertionSort
-----------------------
For example:
A = [2,5,1,8,6]
Process:
index 0 1 2 3 4
tail = 0 head = 0
init (2) ? ? ? ?
tail = 1 head = 0
1 (2 5) ? ? ?
tail = 1 head = 4
2 (2 5) ? ? (1)
tail = 2 head = 4
3 (2 5 8) ? (1)
tail = 3 head = 4
4 (2 5 6 8) (1)
Organize information from head to tail
result 1 2 5 6 8
Information about the array sort:
Loop times: 4
Total Value: 5
Internal Compare Times: n(untill find value smaller than it)
Explanation:
First of all, build up head and tail pointer before sort
The Second step is to construct a tempary array to store data
At the same time, initialize the first data in array
Then, conduct n - 1 times data sort
Methods:
1、< Head, Let new data transfer to head after add data before head
2、> Tail, Let data as new tail after put data to tail's next location
3、You possibly search its position, if the pointer in this range from head to tail,
and move data after it to the next position, the last step is to fill out data in its position
*/
function TwoWayInsertionSort(arr)
{
// Variable declaration
let head, tail, mid, pmid
let res = []
let len = arr.length
// Variable initialization
head = tail = 0
res[0] = arr[0]
// Compare n - 1 times
for (let i = 1; LT(i, len); i++)
{
// data > tail
if (HT(arr[i], res[tail]))
{
// increase data and let tail move behind
res[++tail] = arr[i]
}
// data < head
else if (LT(arr[i], res[head]))
{
// Search index way likes circle queue's one
// increase data in front of head and move head frontly
head = (head - 1 + len) % len
res[head] = arr[i]
}
// data belong range from head to tail
else
{
// reserve enough store to set data
mid = ++tail
// move behind if it bigger than data
while (HT(res[(mid - 1 + len) % len], arr[i]))
{
// calculate the position of previous index
pmid = (mid - 1 + len) % len
// move data behind
res[mid] = res[pmid]
// reset index
mid = pmid
}
// fill out data at location searched
res[mid] = arr[i]
}
}
// Flexibly copy data from tempary array to oringinal one
for (let i = 0; LT(i, len); i++)
{
// from head to tail
// head -> tail
arr[i] = res[(head + i) % len]
}
}
/*
-----------------------
@ BinaryInsertionSort
-----------------------
For example:
A = [2,5,1,8,6]
Process:
index 0 1 2 3 4
interval = 3
1 (2) (5) (1) 8 6
interval = 2
2 (2) (5) 1 8 6
interval = 2
3 (1) (5) 2 8 6
interval = 1
4 (1) 2 5 6 8
Information about the array sort:
Loop times: 4
Total Value: 5
External Compare Times: 3
Internal Compare Times: n(untill find value smaller than it)
Explanation:
Parentheses mean that alreay sorted
Interval from big to small
{
() -> sorted
Here has interval, so it means to interval array sort
It get next index via index substract or plus 'interval'
Search position via index surplus
Move behind and fill out data
}
*/
function ShellInsertionSort(arr, interval)
{
// change sort interval from large to small,
// that mean its compare number more and more large from small,
// this like the half behind part of merge sort
for (let k = interval; k > 0; k--)
{
// this like compare n - 1 times, but here has interval
for (let i = k; i < arr.length; i++)
{
// tempary container
let temp = arr[i]
// start compare with data before it
// if data pos is i, so the last data pos of sorted array is (i - interval)
// this compare range from small to big, it will form a sort array at suitable interval
// Compare way is from big to small
for (var j = i - k; temp < arr[j] && j >= i % k; j -= k)
{
// move data behind
arr[j + k] = arr[j]
}
// fill out data
arr[j + k] = temp
}
}
}
module.exports = { DirectInsertionSort, BinaryInsertionSort,
TwoWayInsertionSort, ShellInsertionSort }
//////////////////////////////////////////////////////////////////////////
快速排序
- 冒泡排序
- 快速排序
/**
* @ QuickSort
* 1、BubbleSort
* 2、QuickSort
*/
//////////////////////////////////////////////////////////////////////////
function BubbleSort(arr)
{
for (let i = 1; LT(i, arr.length); i++)
{
for (let j = 0; LT(j, arr.length - i); j++)
{
if (LT(arr[j + 1], arr[j]))
SwapArr(arr, j + 1, j)
}
}
}
function QuickSort(arr, low=0, high=arr.length-1)
{
// 大小索引检测
if (HQ(low, high)) return
// 指定最小索引的值作为比较值
let pivot = arr[low]
// 初始赋值大小位置索引
let i = low, j = high
while (LT(i, j))
{
// 由于从头开始作为比较值,那么这里从后面开始寻找
// 大于比较值则交换,并且交换后左边的右移,右边的左移(左填坑)
while (LT(i, j) && HQ(arr[j], pivot)) j--
if (LT(i, j)) SwapArr(arr, i++, j)
// 小于比较值则交换,并且交换后右边的左移,左边的右移(右填坑)
while (LT(i, j) && LQ(arr[i], pivot)) i++
if (LT(i, j)) SwapArr(arr, i, j--)
}
// 分治法
// 这里的 i = j 所以退出了循环,所以任一即可
// 除了 i or j 的左边
QuickSort(arr, low, i - 1)
// 除了 i or j 的右边
QuickSort(arr, i + 1, high)
}
module.exports = { BubbleSort, QuickSort }
//////////////////////////////////////////////////////////////////////////
选择排序
- 选择排序
- 树形选择排序
- 堆排序
PS:堆的代码请参考:https://www.jianshu.com/p/54345f3151c3
/**
* @ SelectSort
* 1、SelectSort
* 2、TreeSelectSort
* 3、HeapSort
*/
//////////////////////////////////////////////////////////////////////////
function SelectSort(arr)
{
let min
for (let i = 0; LT(i, arr.length); i++)
{
min = i
for (let j = i; LT(j, arr.length); j++)
{
if (LT(arr[j], arr[min]))
{
min = j
}
}
if (NQ(min, i)) SwapArr(arr, min, i)
}
}
const HP = require('./Heap.js')
function TreeSelectSort(arr)
{
let MH = new HP.Heap(arr)
let temp = []
MH.createMaxHeap()
for (let i = arr.length - 1; HQ(i, 0); i--)
{
temp.unshift(arr[0])
MH.setHeapVal(0, 0)
MH.adjustMaxHeap(0, arr.length)
}
CopyArr(temp, arr)
}
function HeapSort(arr)
{
let MH = new HP.Heap(arr)
// 创建最大堆
MH.createMaxHeap()
// 由于将最大值添加至排序数组的尾部
// 所以最大堆调整范围的长度会不断地减少
for (let i = arr.length - 1; HQ(i, 0); i--)
{
// 最大值于排序数组尾部的值替换,成为固定的值
SwapArr(arr, 0, i)
// 不断调整最大堆的调整范围,不断调整新的最大值
MH.adjustMaxHeap(0, i)
}
}
module.exports = { SelectSort, TreeSelectSort, HeapSort }
//////////////////////////////////////////////////////////////////////////
归并排序
- 二路归并排序
/**
* @ MergeSort
* 1、TwoWayMergeSort
*/
//////////////////////////////////////////////////////////////////////////
function MergeSort(arr, sta, mid, end)
{
// Slice the Array via index
// Array 1's sta pos is 'i'
// Array 2's sta pos is 'j'
// Temp is tempory Array to fill out data partial
let i = sta, j = mid + 1, counter = sta
let temp = []
// Compare data between arr1 and arr2
// to select the smaller value put in the temp array
// Position movement via pointer 'i', 'j' and 'counter'
while (LQ(i, mid) && LQ(j, end))
{
if (LT(arr[i], arr[j])) temp[counter++] = arr[i++]
else temp[counter++] = arr[j++]
}
// To determinate another unfinished array's items
// and put them to the temp array
while (LQ(i, mid))
{
temp[counter++] = arr[i++]
}
while (LQ(j, end))
{
temp[counter++] = arr[j++]
}
// Copy data from temp array to original array
CopyArr(temp, arr, sta, end)
}
function TwoWayMergeSort(arr, sta=0, end=arr.length-1)
{
// Check a regulation about start and end 's position relation
if (HQ(sta, end)) return
// Calculate the index's number of which to slice the array two parts
let mid = Math.floor((sta + end) / 2)
// Slice the array untill that only one data as a array
TwoWayMergeSort(arr, sta, mid)
TwoWayMergeSort(arr, mid+1, end)
// You already sliced the array if you arrive here
// from now on, we begin to merge per two arrays order
MergeSort(arr, sta, mid, end)
}
module.exports = { TwoWayMergeSort }
//////////////////////////////////////////////////////////////////////////
基数排序
- 基数排序(LSD)
PS: 队列的代码则参考 https://www.jianshu.com/p/ebd932c4b7e1
/**
* @ RadixSort
* 1、RadixSort(MSD、LSD)
*/
//////////////////////////////////////////////////////////////////////////
let CQ = require('./ChainQueue.js')
function RadixSort_Array(arr)
{
// Calculate the max length in number
let max = arr[0]
for (let i = 1; i < arr.length; i++)
{
if (HT(arr[i], max))
{
max = arr[i]
}
}
// Copy arr to arr1 at the same time transfrom data as String Object
let arr1 = arr.map((item, inx) => {
return new String(item).split('')
})
// Initialize array used to store data temparily
let temp = []
InitArr(temp, ()=> new CQ.Queue(), 10)
// Calculate pointer move between start and end
let times = new String(max).split('').length
let sta = 0
while (sta < times)
{
for (let i = 0; i < arr.length; i++)
{
// data
let el = arr1[i]
// data's end pointer
let ll = el.length - 1
// index of number
let inx = ll - sta
// check type and put them in queue
if (inx >= 0)
{
temp[el[inx]].push(el)
} else {
temp[0].push(el)
}
}
// clear tempary container
arr1 = []
// get out data from queue
for (let i = 0; i < 10; i++)
{
while (!temp[i].empty())
{
arr1.push(temp[i].pop())
}
}
// from small to big
sta++
}
// turn back data to original array
arr1.map((item, inx) => {
arr[inx] = parseInt(item.join(''))
})
}
function RadixSort(arr1)
{
let arr = arr1
// Check the max val
let max = arr[0]
for (let i = 1; LT(i, arr.length); i++)
{
if (HT(arr[i], max))
{
max = arr[i]
}
}
// Initialize array used to store data temparily
let temp = []
InitArr(temp, ()=> new CQ.Queue(), 10)
// Initialize pointer relation
let exp = 1
let base = 10
// judge by (max val / now exp)
while (HT(Math.floor(max / exp), 0))
{
for (let i = 0; LT(i, arr.length); i++)
{
// limit range to locate
// example:
// (1)
// 234 -> Hundreds of digits
// 234 / exp = 234 / 10^2 = 2.34 => 2
// 2 % base = 2 % 10 = 2
// (2)
// 234 -> Ten digits
// 234 / exp = 234 / 10 = 23.4 => 23
// 23 % base = 23 % 10 = 3
// Select digit via divide and surplus
// divide used to ensure the head of digit
// The remainder is used to crop the last bit of the number
let inx = Math.floor(arr[i] / exp) % base
// check type and put them in queue
temp[inx].push(arr[i])
}
// clear container
arr = []
// get out data from queue
for (let i = 0; LT(i, 10); i++)
{
while (!temp[i].empty())
{
arr.push(temp[i].pop())
}
}
// Move forward by 10 digits
exp *= base
}
// reback data to original array
arr.map((item, inx) => {
arr1[inx] = item
})
}
module.exports = { RadixSort, RadixSort_Array }
//////////////////////////////////////////////////////////////////////////