***************************转载请注明出处!*****************************
(大家可能注意到,这次的标题最后用的是“1”而不是“上”。对的,排序这段是够昊昊喝一壶了T T ,回学校之前都不一定能讲完额……)
一提到算法,可能好多人最先接触的都是排序,那昊昊今天就来带大家看一看排序~
从百度抄一段:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
http://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html
这里有冒泡排序,选择排序,插入排序,希尔排序,归并排序以及快速排序。
插入排序
还记得我们第一篇概述的时候,提到过理牌咩亲?~理牌的过程跟插入排序类似。假设我们有一个数组,里面有一组乱序的数字,插入排序就是要用“插入”的方法将它们排好。如果数组中只有一个数。那我们可以认为它已经是有序的了。如果数组中有多个,我们来分析一下如何插入(说得我很害羞 ~\(≧▽≦)/~)……刚开始,我们还没有排序,所以只有第一个数可以看做有序。然后我们取第二个数,试图将第二个数插入到前面已排序的数组中。此时只要简单得跟第一个数比较一下大小,然后决定是放前面或者放后面。再取第三个,插到左边两个数中去……到了第i个数,来联系一下理牌,前面已排序的牌好比是我们手上已经有序的牌,后面没排序的牌好比是还没抓到手上的牌堆,第i个数就是我们刚抓到的牌。因为前面数组已经是有序的,所以只需要从后向前一个一个比较,就能找到第i张牌的位置。但愿我已经说明白了T T 。伪代码如下:
INSERTION-SORT(A)
For j ← 2 to length[A]
Do key ← A[j]
//以下是把a[j]插入有序数组A[1..j-1]的过程
i ← j – 1
while I > 0 and A[i]>key
do A[i+1] ← A[i]
i ← i – 1
A[i+1] ← key
PS: j好比是咱摸牌的手,指到哪抓到哪。当j指到某个位置时,1..j-1这部分数组是有序的。我们先把A[j]的值取到key中。再用一个指针i,从j-1网前扫。如果A[i]比key大,说明还没有找到key的位置,就把A[i]往后挪一位。当while循环结束的时候A[i]<=key所以A[i+1]就应该是key要呆的地方。当j扫到数组末,就意味着前面的数组已经排序号,再把最后一个数正确插入,此时整个数组都有序。其实,我上面说的有一些用循环不变式证明算法正确性的意思,当然不严谨,严谨证明的时候要考虑初始化、保持、终止几个部分~~有兴趣的可以自己百度一下循环不变式是神马东东。
主页菌给大家分享了插入排序的视频,可以看一看,有助于新童鞋理解~
冒泡排序
惯例,有了前面排序的基础,类似的我就不会仔细地说了。冒泡排序这个名字还是很形象的。数组最后我们可以看作水面,数组开头看作是水底,我们要让大数浮到水面上去。下面我粘一段寒假作业给大家(玛德,肿么老是作业 T T ,这是c++的代码):
void BUBBLESORT(int n,int a[] )//n为数组长度,a[]为传进来的数组
{
int b[100]; //数组要反复用,我就另开了一个
for (int i=0; i<n; i++)
b[i] = a[i];
for (int i=n-1; i>0; i-- )
for (int j=0; j<i; j++ )
if ( b[j] > b[j+1] )
ex(&b[j],&b[j+1]); //交换b[j] b[j+1]
print(n,b);
}
PS:第一个指针i,从后向前扫,i后面的数都是已经“浮上来”的大数,所以我们不用理睬。内循环,j从前向后到i。当b[j] > b[j+1]的时候就交换(浮上去了~)大家手动跑一跑吧,没啥难度O_o,另外主页菌也给大家分享了相关视频,可以看一看。
选择排序
跟冒泡类似,只是我们这里不采用各种交换的方式,而是将无序数组中最大的一个先通过比较找出来,然后放到数组末尾。作业里没有,我也懒得现写了。就当思考题了吧~同样,主页里也有视频~欢迎观赏~
简单的几个排序就这么弄完了O_o,后面几个排序都会挺麻烦,但愿我能给大家讲清楚。