1、冒泡排序
1.1 简介
冒泡排序(Bubble Sort)是一种计算科学领域的较简单的排序算法。该算法重复地“走访”要排序的数列,一次比较两个元素,如果它们的顺序错误就把他们交换过来,走访数列的工作是重复进行指导没有在需要交换,也就是说该数列已经排序完成。
该算法是由于越大的元素会经由交换慢慢“浮”到数列的顶端,故为冒泡排序。
1.2 算法原理
冒泡排序算法的原理实现如下所示:
①比较相邻的元素,如果第一个比第二个大,就交换该两个元素;
②对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对,在这一点,最后的元素应该是最大的数;
③针对所有的元素重复以上的步骤,除了最后一个;
④持续每次对越来越少的元素重复上面的步骤,知道没有任何一对数字需要比较。
1.3 算法分析
(1)复杂度
若文件的初始状态时正序的,一次扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值:Cmin=n-1,Mmin=0。
所以,冒泡排序最好的时间复杂度为O(n)。
若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置,在这种情况下,比较次数和移动次数均达到最大值:
冒泡排序的最坏时间复杂度为O(n2)。
综上,因此冒泡排序总的平均时间复杂度为O(n2)。
(2)稳定性
冒泡排序就是把小的元素往前调或吧大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,则不需要交换;如果两个相等元素没有相邻,那么即使通过两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
1.4 算法实现
#!/bin/bash
#冒泡排序:定义一个乱序数组arr
arr=(23 12 48 56 45 73 82 16 90 67 22 73)
#${arr[@]}或${arr[*]}为访问整个数组,${#arr[@]}为获取数组长度
for ((i=0; i<${#arr[@]}; i++))
do
for ((j=0; j<${#arr[@]}-1; j++))
do
#${arr[j]}获取单个元素,-gt为大于
if [[ ${arr[j]} -gt ${arr[j+1]} ]]
then
#分别定义min为小值,MAX为大值
min=${arr[j+1]}
max=${arr[j]}
#调整数组arr中数值顺序
arr[j]=$min
arr[j+1]=$max
fi
done
done
#输出冒泡排序结果
echo "Bubble Sort Result"
echo ${arr[@]}
2、选择排序
1.1 简介
选择排序(Selection sort)是一种简单直观的排序算法。该算法是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,知道全部待排序的数据元素排完。
1.2 算法原理
选择排序算法的原理实现如下所示:
①初始状态,定义无序数列为R[1…n],有序数列为空。
②第1趟排序。在无序数列中选出最小的记录R[k],将它与无序数列中的第一个记录R[1]交换,形成R[1…1]有序数列和R[2…n]无序数列。
③第i趟排序。将无序数列中重复第1趟排序,形成R[1…i-1]有序数列和R[i…n]无序数列。
④依次重复上述排序,最终全部形成有序数列。
1.3 算法分析
(1)复杂度
选择排序的交换操作介于0和(n-1)次之间。选择排序的比较操纵为n(n-1)/2次之间。选择排序的赋值操作介于0和3(n-1)次之间。
比较次数O(n2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+…+1= n(n-1)/2。
交换次数O(n),最好的情况是有序,交换次数0次;最坏情况交换n-1次,逆序交换n/2次。交换次数比冒泡排序少,所以选择排序比冒泡排序快。
(2)稳定性
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二最小的,一次类推,直到第n-1个元素,第n个元素不用进行选择。那么在一趟选择中,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换的稳定性就被破坏了。
如:序列5 8 5 2 9,在第一遍选择第一个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序方法。
1.4 算法实现
#!/bin/bash
#选择排序:定义一个乱序数组arr
arr=(23 12 48 56 45 73 82 16 90 67 22 73)
#${arr[@]}或${arr[*]}为访问整个数组,${#arr[@]}为获取数组长度
for ((i=0; i<${#arr[@]}-1; i++))
do
#定义第i个为最小元素位置
min=$i
for ((j=$i+1; j<${#arr[@]}; j++))
do
#取定义的最小值与数列中剩余元素对比,如果定义最小不是最小,则获取相应元素位置
if [[ ${arr[$min]} -gt ${arr[j]} ]]
then
let min=$j
fi
done
#进行一趟排序后,判断初始第i元素是否为最小,若不是最小则与相应元素进行换位置
if [[ $min -ne $i ]]
then
tmp=${arr[$min]}
arr[$min]=${arr[$i]}
arr[$i]=$tmp
fi
done
#输出选择排序结果
echo "Selection Sort Result"
echo ${arr[@]}
3、插入排序
3.1 简介
插入排序(Insert sort)是将已经有一个有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法—插入排序法(Insertion Sort)。
插入排序的基本思想是每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,知道全部插入完为止。
3.2 算法原理
插入排序算法的原理实现如下所示:
将n个元素的数列分为已有序和无序两个部分,
{{a1},{a2,a3,a4,…,an}}
{{a1(1),a2(1)},{a3(1),a4(1),…,an(1)}}
…
{{a1(n-1),a2(n-1),…},an(n-1)}
每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。
3.3 算法分析
(1)复杂度
如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好的情况就是,序列已经是升序排列了,这种情况下,需要进行的比较操作需要(n-1)次即可;最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较的次数加上(n-1)次。平均来说插入排序算法的时间复杂度为O(n2)。因此,插入排序不适合对于数据量大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。
(2)稳定性
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素,每次比较一个元素,是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到它该插入的位置。如果碰见一个和插入元素相等,则插入的元素放在相等元素的后面,所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
3.4 算法实现
#!/bin/bash
#插入排序:定义一个乱序数组arr
arr=(23 12 48 56 45 73 82 16 90 67 22 73)
#定义数组序列为去除第一个元素后,形成新的无序数组序列
for ((i=1; i<${#arr[@]}; i++))
do
#将获取数组序列第一个元素的值
value=${arr[$i]}
#获取有序数列值最后一个元素位置
let key=$i-1
#如果有序数列最后一个元素位置大于等于0,并且无序数列中第一个元素值小于有序数列最后一个值
while [[ $key -ge 0 ]] && [[ $value -lt ${arr[$key]} ]];do
#将无序数列中第一个元素依次递归与有序数列中元素进行对比
arr[$key+1]=${arr[$key]}
#将有序数列中位置值依次减1
let key--
done
#如果无序数列最终插入位置+1不等于,无序数列第一个元素位置,则将进行转换,如{12} {23 48 56 45 73 82 16 90 67 22 73}
if [[ $key+1 -ne $i ]]
then
#进行数据转换
arr[$key+1]=$value
fi
done
#输出选择排序结果
echo "Insert Sort Result"
echo ${arr[@]}