把暑假作业发在这里……
排序算法 by:yao1995
给定一个数列a[1..n],将其从小到大输出,这需要用到排序算法。常见的排序算法有下面几种。
1.选择排序
选择排序,顾名思义就是通过选择进行的排序。每次从数列中拿出最小的一个放在最前面,n个数都选出后,数列自然就是有序的了。
程序(按本人的理解,不过和标准的选择排序不太一样):
var a:array[0..1001] of longint;
n,i,j,min,t:longint;
begin
assign(input,’sort1.in’);
assign(output,’sort1.out’);
reset(input);
rewrite(output);
readln(n);
for i:=1 to n do read(a[i]);//读入
a[0]:=maxlongint;
for i:=1 to n-1 do//共需选择n-1次最小值
begin
min:=0;//初始值为a[0],即maxlongint
for j:=i to n do//前i-1个已经完成了,要从后n-i+1个中选出最小值
if a[j]<a[min] then min:=j;//如果a[j]小于当前的最小值,记录下a[j]
t:=a[i];a[i]:=a[min];a[min]:=t;//将最小值放在a[i]的位置上
end;
for i:=1 to n-1 do write(a[i],' ');
writeln(a[n]);
close(input);
close(output);
halt;
writeln(‘By: Yao Jiupeng’);
end.
时空分析:选择排序要进行n-1次选择,每次选择平均要进行n/2次比较,时间复杂度为O(n2),对于n比较小的情况适用,当n>5000时就可能会爆掉了。
选择排序是一种原地排序(既不需要开辟新的空间),空间复杂度为O(n)。
2.插入排序
有n张卡片,每张卡片上有一个数字,要求你一张一张地抓起卡片(就是说抓一张卡片时你不知道下一张上的数字是多少),并且保证最后你手中卡片上数字是有序的,该怎么办呢?全部抓完后再进行排序,太麻烦了吧?对了!每次抓完卡片后将它插在相应位置,使手中的卡片总是有序的。插入排序的模型大体就是这样。不过电脑没有人脑那么智慧,不能把数直接插在合适的位置,需要通过交换来找到应当插入的位置。
程 序:
var a:array[0..3001] of longint;
n,i,j,t:longint;
begin
assign(input,’sort2.in’);
assign(output,’sort2.out’);
reset(input);
rewrite(output);
readln(n);
for i:=1 to n do read(a[i]);
for i:=2 to n do//将第2~n个元素依次插入到正确的位置,开始时前i个元素已经是递增的
begin
j:=i;//用a[j]表示当前要插入的元素
while a[j]<a[j-1] do
begin
t:=a[j];a[j]:=a[j-1];a[j-1]:=t;//如果a[j]比前一个元素小,就把它和前一个交换
dec(j);
end; //上面的程序可以优化
end;
for i:=1 to n-1 do write(a[i],' ');
writeln(a[n]);
close(input);
close(output);
end.
时空分析:插入排序同样是一种原地排序,空间复杂度为Ο(n)。
按上面的做法,当输入数据已经排好序时,再好不过了,只需将a[i]与a[i-1]进行n-1次比较,不需要进行交换,时间复杂度为O(n);
当输入数据同样是有序,不过是逆序,这个时候就惨了,每个a[i]都要不断进行交换一直交换到a[1],时间复杂度为O(n^2)。
总的来说,插入排序比选择排序优一些,100000左右的数据还是能过一部分的。
3.冒泡排序
冒泡排序的思想也是比较简单的,在a[1]..a[n]中,从前到后依次将相邻两个数进行比较,如果前面的数比后面的大,那就不科学了,需要将两个数进行调换。这样下来,其中最大的数就可以像气泡一样“冒”到a[n]的位置了。这样下一轮只需将a[1]..a[n-1]再“冒泡”一次,确定出第二大的数。以此类推。