八大排序算法:
1.冒泡排序
冒泡排序,该排序的命名非常形象,即一个个将气泡冒出。冒泡排序一趟冒出一个最大(或最小)值。
基本思想:
冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。
算法思路:
冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减少。
实验:
#!/bin/bash
arr=(63 4 24 1 3 15)
echo "旧数组的值为: ${arr[@]}"
##获取数组的长度:
length=${
#arr[@]}
##外层循环用来定义比较轮数,比较轮数为数组长度减1,且从1开始
for ((a=1; a<length; a++))
do
##内层循环用来确定比较元素的位置,比较相邻两个元素,较大的元素往后移,并且比较次数会随着比较轮数的增加而减少
for ((b=0; b<length-a; b++))
do
##获取相邻两个元素的前面的元素的值
first=${
arr[$b]}
##获取相邻两个元素的后面元素的值
c=$[b + 1]
second=${
arr[$c]}
##比较两个相邻元素的值的大小,如果前面元素的值较大,则与>
后面元素交换位置
if [ $first -gt $second ];then
##使用临时变量保存前面元素的值,实现两个相邻元素交换>位置
tmp=$first
arr[$b]=$second
arr[$c]=$tmp
fi
done
done
echo "冒泡排序后的数组的值为: ${arr[@]}"
实验结果:
2.直接插入排序
插入排序,又叫直接插入排序。实际中,我们玩扑克牌的时候,就用了插入排序的思想。
基本思想:
- 在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。
- 但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。
实验:
#!/bin/bash
arr=(63 4 24 1 3 15)
echo "排序前数组的值为:${arr[@]}"
length=${
#arr[@]}
#外层循环定义待排序的元素下标位置
for ((b=0; 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[@]}"
实验结果:
3.直接选择排序
与冒号排序相比,直接选择排序的交换次数更少,所以速度会更快
选择排序,即每次从待排序列中选出一个最小值,然后放在序列的起始位置,直到全部待排数据排完即可。
基本思想:
将指定排序位置与其她数组元素分别对比,如果满足条件就交换元素值,注意这里分区别冒泡排序,不是交换相邻元素,而是把满足条件的排序位置交换(如从最后一共元素开始排序),这样排序好的位置逐渐扩大,最后整个数组都成为已排序好的格式。
算法思路:
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零,选择排序是一种不稳定的排序方法。
实验:
#!/bin/bash
arr=(63 4 24 1 3 15)
echo "排序前数组的值为:${arr[@]}"
length=${
#arr[@]}
##外层循环定义待排序的元素下标位置
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[@]}"
实验结果:
4.希尔排序
希尔排序是按其设计者希尔的名字命名的,该算法由希尔1959年公布。希尔可以说是一个脑洞非常大的人,他对普通插入排序的时间复杂度进行分析,得出了以下结论:
- 1.普通插入排序的时间复杂度最坏情况下为O(N2),此时待排序列为逆序,或者说接近逆序。
- 2.普通插入排序的时间复杂度最好情况下为O(N),此时待排序列为升序,或者说接近升序。
于是希尔就想:若是能先将待排序列进行一次预排序,使待排序列接近有序(接近我们想要的顺序),然后再对该序列进行一次直接插入排序。因为此时直接插入排序的时间复杂度为O(N),那么只要控制预排序阶段的时间复杂度不超过O(N2),那么整体的时间复杂度就比直接插入排序的时间复杂度低了。
基本思想:
1.先选定一个小于N的整数gap作为第一增量,然后将所有距离为gap的元素分在同一组,并对每一组的元素进行直接插入排序。然后再取一个比第一增量小的整数作为第二增量,重复上述操作…
2.当增量的大小减到1时,就相当于整个序列被分到一组,进行一次直接插入排序,排序完成。
注:一般情况下,取序列的一半作为增量,然后依次减半,直到增量为1(也可自己设置)。
实验:
#!/bin/bash
array=(7 6 8 3 1 5 2 4)
echo ${
array[*]}
length=${
#array[*]}
#把距离为gap的元素编为一个组,扫描所有组,每次循环减少增量
for ((gap=$length/2; gap>0; gap/=2))
do
for ((i=gap; i<$length; i++))
do
temp=${
array[$i]}
#对距离为gap的元素组进行排序,每一轮比较拿当前轮次最后
一个元素与组内其他元素比较,将数组大的往后放
for ((j=i-gap; j>=0&&temp<${
array[$j]}; j-=gap))
do
array[$j+$gap]=${
array[$j]}
done
#和最左边较大的元素调换位置
array[$j+$gap]=$temp
done
done
echo ${
array[*]}
实验结果:
实验:反转排序
实验:
#!/bin/bash
arr=(1 2 3 4 5 6 7 8 9)
echo "排序前数组的值为: ${arr[@]}"
length=${
#arr[@]}
for ((a=0; a<length/2; a++))
do
tmp=${
arr[$a]}
##获取当前轮数的最后一共元素下标,会随着轮数的增加而减少
last=$[length-1-a]
arr[$a]=${
arr[$last]}
arr[$last]=$tmp
done
echo "排序后数组的值为: ${arr[@]}"
实验结果: