Bash : 冒泡排序


冒泡排序是非常基礎的排序算法,本文我們看看在 Bash 腳本中如何寫冒泡排序。本文的演示環境為 ubuntu 16.04。

冒泡排序的簡要描述如下:

  • 通過連續的比較對數組中的元素進行排序
  • 比較兩個相鄰的元素,如果順序不對,就交換這兩個元素的位置
  • 當第一輪比較結束之后,最 "重" 的元素就會被移動到最底部
  • 當第二輪比較結束之后,第二 "重" 的元素就會被移動到次底部的位置
  • 這意味着每輪比較不需要比較之前已經 "沉淀" 好的數據
  • 如果有 n 個元素,則一共執行 n-1 輪比較

用 for 循環實現冒泡

准備一個數組(Bash 數組相關的內容請參考《Bash : 索引數組》一文):

declare -a myArr=(10 1 30 13 2 22)

然后來主備一個交換數組元素的函數:

# 定義函數 exchangeEle() 交換數組中兩個元素的位置
exchangeEle()
{
    # 使用臨時變量保存數組元素
    local temp=${myArr[$1]}
    # 交換元素的位置
    myArr[$1]=${myArr[$2]}
    myArr[$2]=$temp

    return
}

下面通過一個經典的兩層循環來完成排序:

# 獲取數組的長度
arrlen=${#myArr[@]}

# 通過 for 循環對數組排序,注意此時是以字符串來比較的
for (( last = $arrlen ; last > 1 ; last-- ))
do
    for (( i = 0 ; i < last - 1 ; i++ ))
    do
        [[ "${myArr[$i]}" > "${myArr[$((i+1))]}" ]] && exchangeEle $i $((i+1))
    done
done

這就 OK 了,跑跑看:

好吧,數字被作為字符串來比較了。修正這個問題非常簡單,把比較的代碼換成下面的就可以了:

[[ "${myArr[$i]}" -gt "${myArr[$((i+1))]}" ]] && exchangeEle $i $((i+1))

關於 Bash 中的比較操作,請參考《Bash : test 命令》一文。
再運行一次,就能看到正確結果了:

用 while 循序實現冒泡

下面我們來介紹使用 while 循序的版本。這次我們按字母序來排列數組中存放的國家名稱:

myArr=(Netherlands Ukraine Zaire Turkey Russia Yemen Syria \
Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England)

這里我們使用了轉義符 \ 將數組元素的值放在不同的行上,這樣可以避免行中的內容過長。具體的代碼如下:

# 從索引 0 開始列出整個數
echo "The order of the original data in the array:"
echo "${myArr[*]}"

# 獲取數組的長度,並用來控制循環的次數。
n=${#myArr[@]}

echo "Start bubbling sort:"
while [ "$n" -gt 1 ] # 執行 n-1 輪外部循環。
do
    index=0 # 內部循環時的數組元素索引,在每輪循環開始之前需要重置。
    while [ "$index" -lt $(expr $n - 1) ] # 開始內部循環。
    do
        if [[ ${myArr[$index]} > ${myArr[$(expr $index + 1)]} ]]
        then
            exchangeEle $index $(expr $index + 1) # 交換數組元素位置。
        fi
        let "index += 1"
    done # 內部循環結束。
    let "n -= 1" # 外部循環計數減 1。
    # 輸出每輪排序后的結果。
    echo "${myArr[*]}"
done # 外部循環結束。

echo "Sorted data order:"
echo "${myArr[*]}"

同樣是兩層循環,算法完全一樣,只不過是寫法有一點點不同。為了顯示排序的過程,這次輸出了每輪排序后的中間結果:

demo 代碼

下面是本文中 demo 的完整代碼:

#!/bin/bash
# bubble.sh, 本例主要用來演示索引數組的排序
# 冒泡排序的簡要描述如下:
# 通過連續的比較對數組中的元素進行排序
# 比較兩個相鄰的元素,如果順序不對,就交換這兩個元素的位置
# 當第一輪比較結束之后,最 "" 的元素就會被移動到最底部
# 當第二輪比較結束之后,第二 "" 的元素就會被移動到次底部的位置
# 這意味着每輪比較不需要比較之前已經 "沉淀" 好的數據
# 一共執行 n-1 輪比較

# 定義函數 exchangeEle() 交換數組中兩個元素的位置
exchangeEle()
{
    # 使用臨時變量保存數組元素
    local temp=${myArr[$1]}
    # 交換元素的位置
    myArr[$1]=${myArr[$2]}
    myArr[$2]=$temp

    return
}

declare -a myArr=(10 1 30 13 2 22)

# 從索引 0 開始列出整個數組
echo "The order of the original data in the array:"
echo "${myArr[*]}"

# 獲取數組的長度
arrlen=${#myArr[@]}

# 通過 for 循環對數組排序,注意此時是以字符串來比較的
for (( last = $arrlen ; last > 1 ; last-- ))
do
    for (( i = 0 ; i < last - 1 ; i++ ))
    do
        [[ "${myArr[$i]}" > "${myArr[$((i+1))]}" ]] && exchangeEle $i $((i+1))
    done
done

echo "Sorted data order as string:"
echo "${myArr[*]}"

# 通過 for 循環對數組排序,這次是作為整數來比較
for (( last = $arrlen ; last > 1 ; last-- ))
do
    for (( i = 0 ; i < last - 1 ; i++ ))
    do
        [[ "${myArr[$i]}" -gt "${myArr[$((i+1))]}" ]] && exchangeEle $i $((i+1))
    done
done

echo "Sorted data order as number:"
echo "${myArr[*]}"

myArr=(Ukraine Zaire Russia Yemen Syria \
Argentina Japan Mexico Greece)
#這里我們還使用轉義符 \ 將數組元素的值放在不同的行上,這樣可以避免行中的內容過長。

# 從索引 0 開始列出整個數
echo "The order of the original data in the array:"
echo "${myArr[*]}"

# 獲取數組的長度,並用來控制循環的次數。
n=${#myArr[@]}

echo "Start bubbling sort:"
while [ "$n" -gt 1 ] # 執行 n-1 輪外部循環。
do
    index=0 # 內部循環時的數組元素索引,在每輪循環開始之前需要重置。
    while [ "$index" -lt $(expr $n - 1) ] # 開始內部循環。
    do
        if [[ ${myArr[$index]} > ${myArr[$(expr $index + 1)]} ]]
        then
            exchangeEle $index $(expr $index + 1) # 交換數組元素位置。
        fi
        let "index += 1"
    done # 內部循環結束。
    let "n -= 1" # 外部循環計數減 1。
    # 輸出每輪排序后的結果。
    echo "${myArr[*]}"
done # 外部循環結束。

echo "Sorted data order:"
echo "${myArr[*]}"

參考:
《高級 Bash 腳本編程指南》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM