内部排序 (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 }

//////////////////////////////////////////////////////////////////////////
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354