shell脚本-数组排序算法

408 阅读2分钟

前言

所谓排序算法,即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序。这种新序列遵循着一定的规则,体现出一定的规律,因此,经处理后的数据便于筛选和计算,大大提高了计算效率。对于排序,我们首先要求其具有一定的稳定性,即当两个相同的元素同时出现于某个序列之中,则经过一定的排序算法之后,两者在排序前后的相对位置不发生变化。换言之,即便是两个完全相同的元素,它们在排序过程中也是各有区别的,不允许混淆不清。

数组排序

使用tr;sort;for

  • 使用tr命令将数组内每个元素之间的空格替换为换行符;
  • 之后使用sort命令按从小到大重新排序;
  • 最后使用for循环遍历排序后的元素值。
#!/bin/bash
arr=(12 28 6 5 89)
echo "原数组的顺序为:${arr[@]}"
#将每个元素之间的空格替换为换行符,然后重新排序
list=$(echo ${arr[@]} | tr ' ' '\n' | sort -n)
a=0
for i in $list
do
 arr[$a]=$i
 let a++
done
echo "排序后的数组顺序为:${arr[@]}"

Snipaste_2022-09-12_10-31-32.png

冒泡排序

类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动。

基本思想:

冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。

算法思路:

冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一 般为要排序的数组长度减1次,因为最后一 次循环只剩下一-个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减少。

Snipaste_2022-09-12_10-42-36.png

#!/bin/bash
#冒泡排序
arr=(3 8 9 4 1)
echo "原始数组元素列表顺序为:${arr[@]}"
changdu=${#arr[@]}
for ((a=1; a<changdu; a++))
do
  for ((b=1;b<=changdu-a;b++))
  do
   right=${arr[$b]}
   c=$[b - 1]
   left=${arr[$c]}
   if [ $left -gt $right ];then
    tmp=${arr[$b]}
    arr[$b]=${arr[$c]}
    arr[$c]=$tmp
   fi
  done
done
echo "排列后的数组顺序为:${arr[@]}"

Snipaste_2022-09-11_23-56-48.png

直接选择排序

与冒泡排序相比,直接选择排序的交换次数更少,所以速度会快些。

基本思想:

将指定排序位置与其它数组元素分别对比,如果满足条件就交换元素值,注意这里区别冒泡排序,不是交换相邻元素,而是把满足条件的元素与指定的排序位置交换(如从最后一个元素开始排序),这样排序好的位置逐渐扩大,最后整个数组都成为已排序好的格式。

Snipaste_2022-09-12_10-39-35.png

#!/bin/bash
#直接选择排序,实现升序
arr=(23 14 66 74 2)
length=${#arr[@]}
echo "原数组排序为:${arr[*]}"
#定义排序的轮数,轮数为数组的长度减一
for ((a=1;a<length;a++))
do
 #初始定义假设下标值为0的元素的值最大
 n=0
 #定义内循环变量是从第二个元素下标开始,用于比较当前假设的最大元素的值,并记录最大元>素的下标
 for ((b=1;b<=length-a;b++))
 do
  if [ ${arr[$b]} -gt ${arr[$n]} ];then
   n=$b
  fi
 done
 #获取每轮的最后一个比较元素的下标
 last=$[ length - $a ]
 #把  最大的元素  和   当前轮数的最后一个比较元素  交换他们的值
 tmp=${arr[$last]}
 arr[$last]=${arr[$n]}
 arr[$n]=$tmp
done
echo "排序后的数组的顺序为:${arr[@]}"

Snipaste_2022-09-11_23-59-52.png

反转排序

以相反的顺序把原有数组的内容重新排序。

基本思想:

把数组最后一个元素与第一个元素进行交换,倒数第二个元素与第二个元素进行交换,以此类推,直到把所有数组元素反转替换。

#!bin/bash
#反转排序
arr=(10 20 30 40 50 60 70)
length=${#arr[@]}
echo "数组原本顺序为:${arr[@]}"
#设置前后两个替换元素中的前面元素下标的取值范围,下标从0开始
for ((a=0; a<length/2; a++))
do
#设置变量把需要前后替换的两个元素替换过来
 tmp=${arr[$a]}
 arr[$a]=${arr[$length-1-$a]}
 arr[$length-1-$a]=$tmp
done
echo "反转排序后的数组顺序为:${arr[@]}"

Snipaste_2022-09-11_23-57-44.png

插入排序

插入排序,又叫直接插入排序。实际中,我们玩扑克牌的时候,就用了插入排序的思想。

基本思想:

在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。

但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。 Snipaste_2022-09-12_10-17-55.png

#!/bin/bash
#插入排序,实现升序

arr=(17 23 56 1 8)
echo "原数组为:${arr[@]}"
length=${#arr[@]}
#定义比较的轮数,且a的值也用于待排序的元素下标
for ((a=1;a<length;a++))
do
 #定义用于和待排序的元素比较的元素下标范围
 #使待排序的元素和前面已排序的元素进行比较,较大的数放后面的待排序元素的位置,较小的>数放前面的位置
 for ((b=0;b<a;b++))
 do
  if [ ${arr[$a]} -lt ${arr[$b]} ];then
   tmp=${arr[$a]}
   arr[$a]=${arr[$b]}
   arr[$b]=$tmp
  fi
 done
done
echo "排序后的数组的顺序为:${arr[@]}"

Snipaste_2022-09-12_00-20-39.png