排序算法總結



--冒泡算法  (交換排序)
--每當兩相鄰的數比較後發現它們的排序與排序要求相反時,就將它們互換。

local table = {2,4,5,1,9,6,7,8,3}
for i=1,#table or {} do                  
    print(table[i])
end

function  BubbleSort( table)    
    for i=1,#table or {} do                  --對每一位數的操作
        for j=1,#table - i do                --對當前下標的數進行遍歷比較
            if table[j] > table[j+1] then    --比較大小,交換位置
                local temp = table[j+1]
                table[j+1] = table[j]
                table[j] = temp
            end
        end
    end
end

--冒泡排序改進方法1
對冒泡排序常見的改進方法是加入一標誌性變量exchange,用於標誌某一趟排序過程中是否有數據交換,
如果進行某一趟排序時並沒有進行數據交換,則說明數據已經按要求排列好,可立即結束排序,避免不必要的比較過程。

function BubbleSort1( table )
    local i = #table or 0
    local function mySort( ... )
        local  pos = 0                       --每趟開始時,無記錄交換
        for j=1,i-1 do
            if table[j] > table[j+1] then    --比較大小,交換位置
                pos = j
                local temp = table[j+1]
                table[j+1] = table[j]
                table[j] = temp
            end
        end
        i = pos                              --爲下一趟排序作準備
        if i > 0 then  
          mySort()
        end
    end
    mySort( )   
end

--冒泡排序改進方法2
2.傳統冒泡排序中每一趟排序操作只能找到一個最大值或最小值,
我們考慮利用在每趟排序中進行正向和反向兩遍冒泡的方法一次可以得到兩個最終值(最大者和最小者) , 從而使排序趟數幾乎減少了一半。

function BubbleSort2( table )
    local low  = 1
    local high = #table or 0
    local function mySort( ... )

        for j= low,high-1 do                --正向冒泡,找到最大者(去最大)
            if table[j] > table[j+1] then   
                local temp = table[j+1]
                table[j+1] = table[j]
                table[j] = temp
            end
        end
        high = high -1

        for j = high,low + 1,-1 do              --反向冒泡,找到最大者 (去最小)
            if table[j] < table[j-1] then   
                local temp = table[j]
                table[j] = table[j-1]
                table[j-1] = temp
            end
        end
        low = low + 1
        if high > low then  
          mySort()
        end
    end
    mySort( )   
end


---------------------------------------------------------------------------------------------------------------------

快速排序(交換排序)

1)選擇一個基準元素,通常選擇第一個元素或者最後一個元素,
2)通過一趟排序講待排序的記錄分割成獨立的兩部分,其中一部分記錄的元素值均比基準元素值小。另一部分記錄的 元素值比基準值大。
3)此時基準元素在其排好序後的正確位置
4)然後分別對這兩部分記錄用同樣的方法繼續進行排序,直到整個序列有序。

function quickSort( table,low,high)
   if high > low  then
       local keyIndex = partition(table,low,high )
       quickSort(table,low,keyIndex-1)
       quickSort(table,keyIndex+1,high)
   end
end

function partition( table,low,high )
    local  key = table[low]
    local  flow = low
    local  low = low
    local  high = high
    local keyIndex = Exchange(table,key,low,high,flow) --分割下標
    return keyIndex
end

function findSmallIndex( table,key,low,high)  --找出右邊key值小的數 返回下標
    local high = high
    local low = low
    for i = high,low,-1 do
        if key > table[i] then
            return i
        end
    end
    return low
end

function findBigIndex( table,key,low,high)  --找出左邊key值大的數 返回下標
    local high = high
    local low = low
    for i = low,high do
        if key < table[i] then
            return i
        end
    end
    return high
end

function Exchange(table,key,low,high,flow)  --以key分割數組  
    local flow = flow
    local high = high
    local low = low
    if high > low then
        local h = findSmallIndex(table,key,low,high)
        local l = findBigIndex(table,key,low,high)
        if h > l then
            local temp = table[h]
            table[h] = table[l]
            table[l] = temp
            Exchange(table,key,l+1,h-1,flow)
        end
    end
    if high <= low then
        if key > high then           --分割的最後一步 對key的處理
            local temp = table[high]
            table[high] = table[flow]
            table[flow] = temp
        end
        return high
    end
end
===========================================================================================
插入排序 --直接插入排序
將數據分爲兩部分,有序部分與無序部分,一開始有序部分包含第1個元素,依次將無序的元素插入到有序部分

function InsertSort(table)
    for i=2,#table or {} do
        if table[i] < table[i-1] then  --table[i] 以下的都是排好序的了,且table[i]是最大的
            local temp = table[i]
            InsertTemp(table,i-1,temp)
        end
    end
end

function InsertTemp(table , k ,temp) --找到插入的位置
    for j=k,1,-1 do
        if table[j] > temp then    --查找比temp小的位置 ,如果比temp大 則往後移一位
            table[j+1] = table[j]
            table[j] = temp
        else
            table[j+1] = temp
            return
        end
    end
 end

 ---------------------------------------------------------------------------------------------------------------------
 2. 插入排序—希爾排序(Shell`s Sort)
 先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,
 待整個序列中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序。

 function ShellInsertSort( table,k )
    for i = k,#table do
        if table[i] < table[i+1-k]then
            local temp = table[i]
            table[i] = table[i+1-k]
            InsertTemp(table,i-1,temp)
        end
    end
    k = math.floor( k/2)
    if k >= 1 then
        ShellInsertSort(table,k)
    end
 end
 function InsertTemp(table , k ,temp) --找到插入的位置
    for j=k,1,-1 do
        if table[j] > temp then    --查找比temp小的位置 ,如果比temp大 則往後移一位
            table[j+1] = table[j]
            table[j] = temp
        else
            table[j+1] = temp
            return
        end
    end
 end

 ==================================================================================================================
 選擇排序—簡單選擇排序
 在要排序的一組數中,選出最小(或者最大)的一個數與第1個位置的數交換;
 然後在剩下的數當中再找最小(或者最大)的與第2個位置的數交換,依次類推,
 直到第n-1個元素(倒數第二個數)和第n個元素(最後一個數)比較爲止

 function selectSort(table)
    for i=1,#table do
        local index = SelectMinKey(table,i)
        if index~= i then
            local temp = table[i]
            table[i] = table[index]
            table[index] = temp
        end
    end
 end

 function SelectMinKey(table,i)
    for k = i+1,#table do
        if table[i] > table[k] then
            i = k
        end
    end
    return i
 end
 ------------------------------------------------------------------------------------------------------
 選擇排序—堆排序

二叉堆是完全二叉樹或者近似完全二叉樹,滿足兩個特性
1.父結點的鍵值總是大於或等於(小於或等於)任何一個子節點的鍵值
2.每個結點的左子樹和右子樹都是一個二叉堆

當父結點的鍵值總是大於或等於任何一個子節點的鍵值時爲最大堆。
當父結點的鍵值總是小於或等於任何一個子節點的鍵值時爲最小堆。一般二叉樹簡稱爲堆。

初始時把要排序的n個數的序列看作是一棵順序存儲的二叉樹(一維數組存儲二叉樹),
調整它們的存儲序,使之成爲一個堆,將堆頂元素輸出,得到n 個元素中最小(或最大)的元素,
這時堆的根節點的數最小(或者最大)。然後對前面(n-1)個元素重新調整使之成爲堆,輸出堆頂元素,得到n 個元素中次小(或次大)的元素。
依此類推,直到只有兩個節點的堆,並對它們作交換,最後得到有n個節點的有序序列。稱這個過程爲堆排序。

--輸出堆頂 重新成堆
因此,實現堆排序需解決兩個問題:
1. 如何將n 個待排序的數建成堆;
2. 輸出堆頂元素後,怎樣調整剩餘n-1 個元素,使其成爲一個新堆。

首先討論第二個問題:輸出堆頂元素後,對剩餘n-1元素重新建成堆的調整過程。
調整小頂堆的方法:
1)設有m 個元素的堆,輸出堆頂元素後,剩下m-1 個元素。將堆底元素送入堆頂((最後一個元素與堆頂進行交換),
   堆被破壞,其原因僅是根結點不滿足堆的性質。
2)將根結點與左、右子樹中較小元素的進行交換。
3)若與左子樹交換:如果左子樹堆被破壞,即左子樹的根結點不滿足堆的性質,則重複方法 (2).
4)若與右子樹交換,如果右子樹堆被破壞,即右子樹的根結點不滿足堆的性質。則重複方法 (2).
5)繼續對不滿足堆性質的子樹進行上述交換操作,直到葉子結點,堆被建成。


 function HeapSort( table )
    -- 初始堆
    BuildingHeap(table)           --先建堆(BuildingHeap)
    for i = #table,1,-1 do
        local temp = table[i]
        table[i] = table[1]
        table[1] = temp
        HeapAdjust(table,1,i-1) --輸出堆頂元素後,怎樣調整剩餘n-1 個元素,使其成爲一個新堆。
    end
end

function BuildingHeap( table )
    --最後一個有孩子的節點的位置 index = math.math.floor((#table -1) / 2)  
    local index = math.floor((#table -1) / 2)  
    for i = index,1,-1 do
        HeapAdjust(table,i,#table)   --每一層的節點的排序
    end
end

--k 是待調整的數組元素的位置
--length 待調整的數組長度
function HeapAdjust( table , k ,length)
    for i= k,length do
        local temp = table[i]
        local child = i*2 --左子結點的位置    --child = 2 * i + 1  -- 右子結點的位置 = 2 * 父結點的位置 + 1
        if child > (length-1) then
            break
        end
        if child <=(length-1) and table[child] > table[child+1]then
            child = child + 1                        --找到最小的孩子與父節點對比    
        end
        if child <=(length-1) and table[child] < temp then
                table[i] = table[child]
                table[child] = temp
        end
    end 
end

--輸出堆頂 重新成堆
因此,實現堆排序需解決兩個問題:
1. 如何將n 個待排序的數建成堆;
2. 輸出堆頂元素後,怎樣調整剩餘n-1 個元素,使其成爲一個新堆。

==============================================================================================
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章