最近在研究数据结构和算法,突然想用shell来实现一把,今天先来写一个冒泡排序。
要想记住各种排序算法,只要知道其原理,用什么语言实现都易如反掌
冒泡排序
- 核心操作 交换相邻两个元素的值
# 定义一个数组
nums=(1 3 5 7 2 3 6 8 22 11 33 22 11 1 34 56)
# 核心操作
function swap(){
# i 和 j 分别代表要交换的两个元素的在数组中的下标
local i=$1;local j=$2
local tmp=${nums[i]} # 注意这里用 ${nums[x]} 的形式才能取出数组对应下标的元素的值
nums[i]=${nums[j]} # 注意这里 ${nums[x]} 中的x 支持数学表达式,没必要 使用 $(()) 来计算
nums[j]=${tmp} # 注意这里 ${ } 包裹 tmp,因为shell中没有显示的指针,也没有引用类型,取值一定要用 ${} 包裹
}
# 数组的元素个数
local size=${#nums[@]} # 注意这里使用${@xxx[@]}的形式取出shell中数组元素的个数
# 用一个下标标识数组最右侧一个元素,相当于一个指针指向了最右侧一个元素,每执行完一轮后指针左移一位
for((i=size-1;i>0;i--)){ # 注意这个地方是size-1因为有size个元素,那最有一个元素的下标一定是size-1因为数组的下标是从零开始的
# 用一个下标标识数组最左侧一个元素, 每次与相邻的下一个元素进行比较,如果当前元素比下一个元素大,则交换两个位置的元素,比较完成后下标右移一位,直到遇到下标i,因为经过几轮排序后i后面的元素都是排好序的
for((j=0;j<i;j++));do # 这个地方是<i
if [[ ${nums[j]} -gt ${nums[j+1]} ]];then # 注意这个地方的比较[1]
swap "${j}" "$((j+1))"
fi
done
echo "第$((size-i))轮冒泡后:${nums[*]}"
}
我们执行一把
第1轮冒泡后:1 3 5 2 3 6 7 8 11 22 22 11 1 33 34 a b c 56
第2轮冒泡后:1 3 2 3 5 6 7 8 11 22 11 1 22 33 a b c 34 56
第3轮冒泡后:1 2 3 3 5 6 7 8 11 11 1 22 22 a b c 33 34 56
第4轮冒泡后:1 2 3 3 5 6 7 8 11 1 11 22 a b c 22 33 34 56
第5轮冒泡后:1 2 3 3 5 6 7 8 1 11 11 a b c 22 22 33 34 56
第6轮冒泡后:1 2 3 3 5 6 7 1 8 11 a b c 11 22 22 33 34 56
第7轮冒泡后:1 2 3 3 5 6 1 7 8 a b c 11 11 22 22 33 34 56
第8轮冒泡后:1 2 3 3 5 1 6 7 a b c 8 11 11 22 22 33 34 56
第9轮冒泡后:1 2 3 3 1 5 6 a b c 7 8 11 11 22 22 33 34 56
第10轮冒泡后:1 2 3 1 3 5 a b c 6 7 8 11 11 22 22 33 34 56
第11轮冒泡后:1 2 1 3 3 a b c 5 6 7 8 11 11 22 22 33 34 56
第12轮冒泡后:1 1 2 3 a b c 3 5 6 7 8 11 11 22 22 33 34 56
第13轮冒泡后:1 1 2 a b c 3 3 5 6 7 8 11 11 22 22 33 34 56
第14轮冒泡后:1 1 a b c 2 3 3 5 6 7 8 11 11 22 22 33 34 56
第15轮冒泡后:1 a b c 1 2 3 3 5 6 7 8 11 11 22 22 33 34 56
第16轮冒泡后:a b c 1 1 2 3 3 5 6 7 8 11 11 22 22 33 34 56
第17轮冒泡后:a b c 1 1 2 3 3 5 6 7 8 11 11 22 22 33 34 56
第18轮冒泡后:a b c 1 1 2 3 3 5 6 7 8 11 11 22 22 33 34 56
注意上面的[1],因为这里我们只能比较数字,也就是只能比较整型数组,小数和字符串的冒泡排序我们的代码是不支持的。搞鬼的地方就在 我代码注释里面标[1]的地方.
我们用的判断相邻两个元素大小的表达是 if [[ a -gt b ]]
这种形式,这种用 [[]] 包裹的if判定表达式只能针对 整数。这个是shell语法决定的
如果nums数组中出现小数,运行程序立马报错,因为shell中没有浮点类型,带点号的shell默认为字符串
line 34: [[: 3.3: syntax error: invalid arithmetic operator (error token is “.3”)
如果要按照字符串比较,应该吧if表达式换成这样 if [ ${nums[j]} \> ${nums[j+1]} ]
但同样,这种形式的比较会使数字的比较出现紊乱,例如
21 和 12 用上面这种比较,shell会认为 12 > 21 因为12的第一个字符1出现在21的第一个字符2之前。