内部排序 (js) - 参考:严蔚敏数据结构

内部排序基本类型

  1. 插入排序(InsertionSort)
  2. 快速排序(QuickSort)
  3. 选择排序(SelectSort)
  4. 归并排序(MergeSort)
  5. 基数排序(RadixSort)

局部功能函数

  1. SwapArr(arr, A, B)
  2. Compare: LT、LQ、EQ、HT、HQ
  3. Visit(arr)
  4. CopyArr(arr1, arr2)
  5. 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

插入排序

  1. 直接插入排序
  2. 折半插入排序
  3. 2-路插入排序
  4. 希尔插入排序
/**
 *  @ 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 }

//////////////////////////////////////////////////////////////////////////

快速排序

  1. 冒泡排序
  2. 快速排序
/**
 *  @ 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 }

//////////////////////////////////////////////////////////////////////////

选择排序

  1. 选择排序
  2. 树形选择排序
  3. 堆排序
    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 }

//////////////////////////////////////////////////////////////////////////

归并排序

  1. 二路归并排序
/**
 *  @ 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 }

//////////////////////////////////////////////////////////////////////////

基数排序

  1. 基数排序(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 }

//////////////////////////////////////////////////////////////////////////

你可能感兴趣的:(内部排序 (js) - 参考:严蔚敏数据结构)