选择排序
选择排序是一个非常简单且直观的算法,顾名思义,就是每次遍历数组,将其最小或最大(以下举例都是从小到大排序)的以依次放入已排好序的数组,再重复此操作。
动画演示
动画过程解释
- 第一步遍历无序数组找到最小的数是2 将其与第一个数组交换(此时0-1即为已排序数组)
- 第二步再次遍历无序数组,找到最小数字是3 ,与第二个数字交换(此时0-2位已排序数组)
- 以此类推 最终得到一个0-n-1的排序数组
代码展示
因为最近我在看Go语言,顺便复习一下算法,所以就用贴Go语言代码了,Go和C/C+语言差不多,应该也能看懂
//选择排序
for i := 0; i < 10; i++ {
var min ,index int = n[i],i
for j := i; j < 10; j++ {
if min > n[j] {
min=n[j]
index=j
}
}
min=n[i]
n[i]=n[index]n
n[index]=min
}
插入排序
插入排序就像是玩扑克牌,假设你有5张牌3 4 6 7 5,如何才能让它好看一点呢,是不是把5插入到4 和6中间去,也就是插入位置的前一位比它小,后一位比它大。用算法分析就是,假设从第二个数开始,默认认为0-1为已排序数组(只有一个数当然排序啦)。如果第n个数比它前面的数小,那么就从此位置开始从后往前依次比较,直到从有序数组里面找到一个数比它小,在此数后面插入它。
动画演示
动画解释
- 第一次默认5为已排序数组(灰色)
- 从第二个开始遍历3<5 3之前没有数,所以把3插入5前面
- 现在3 5 是已排序数组,从第三个开始 3<4 <5 插入3后面
- 依次类推 最终得到一个已排序数组
代码展示
//插入排序
for i := 0; i < 10; i++ {
var temp int = n[i]
j := i - 1
for ; j >= 0; j-- {
if temp < n[j] {
n[j+1] = n[j]
} else {
break
}
}
if j < 0 {
continue
}
n[j] = temp
}
冒泡排序
冒泡排序比较有意思,排序方法就跟水中的泡泡一样,泡泡相当于无序数组中最小的那个数,让他往前移动到未排序数组的顶部,那么顶部就可以看做一个已排序的数组了,那么最后遍历下来就是一个排序数组
动画演示
动画解析
- 从后开始遍历,找到不符合排序顺序的两个数字,图中是4和2,然后依次交换顺序,最终把2运到数组的最顶端,这图其实画的不是很好,请思考一下,加入第一次遍历不符合顺序的数字是4和3,那么第一轮排序完成后,排在数组顶端的数字是多少呢?答案还是2,因为2是数组中最小的数字,任何数字只要在它前面都是不符合排序顺序的,所以第一轮排序结束后,排在第一个的数字一定是2,即冒泡排序第一轮是把最小的数字放在数组顶端,这和选择排序有一点异曲同工之处哦,只是实现的手法不一样。
- 重复以上步骤,最终得到一个排序数组
代码展示
//冒泡
for j := 0; j < 10; j++ { //这里做了一点小小的变动
for i := j + 1; i < 10; i++ { //我不是从后往前遍历的,而是从前往后遍历的
if n[j] > n[i] { //并且我吧最大的数字放在了最后面
tmp := n[j] //而不是图示那样把最小的放在最前面
n[j] = n[i] //或许我不叫冒泡排序
n[i] = tmp //应该叫石头排序 哈哈,不过思想是一样的
}
}
}
时间效率分析
这三种算法时间效率都差不多,因为他们都是一个数字一个数字的依次排序的,以选择排序为例,每次排序一个数字需要遍历一次数组,也就是n次访问数组,一共需要排序n个数字,所以时间效率是O(n^2);