写在前面的话:
——————————————————————————————————————————————————————————————————
一、实验目的
掌握各种排序方法的实现思想。
二、实验内容
1、创建排序类。
2、提供操作:选择排序、冒泡排序、插入排序、基数排序、快速排序、归并排序。(快速排序、归并排序讲到之后再做)
3、*能够显示各种排序算法的中间过程。
——————————————————————————————————————————————————————————————————
下面是我的代码: 点此下载排序算法演示
——————————————————————————————————————————————————————————————————
这里要求创建排序类,就用类的方式来表示吧(能看懂的完全可以转换成c的代码):
0,排序类定义 Sort.h 的内容为:
class Sort
{
public:
Sort(int *array,int num);
//the sort method
void BubbleSort();
void RadixSort();
void SelectSort();
void InsertSort();
//print the sorted array
void Output();
private:
int *a;//the array to be sorted
int n;//the length of the array a
};
然后是在Sort.cpp中的实现:
1,构造方法:
Sort::Sort(int *array,int num)
{
n=num;
a=new int[n];
for(int i=0;i<n;i++)
{
a[i]=array[i];
}
}
将传入的数组拷贝到Sort内部的数组a中,也就是排内部数组,不是将传入数组排序。其实怎么样实现都无所谓了,具体看排序算法吧。
2,选择排序算法:
void Sort::SelectSort()
{
for(int i=0;i<n-1;i++)//总共n个,只需要排n-1个即可
{
int small=i;
for(int j=i+1;j<n;j++) //从剩下的第i+1到n-1个里挑最小的
{
if(a[small]>a[j])
small=j;
}
Output();//这个是输出一下数组内容,可以看到单步排序的过程
swap(a[i],a[small]);//将最小的那个排到队列的后面,这时0-i是已经排好的序列
}
Output();
}
a)思想:
首先明确我的排序是排成从小到大的升序。所以选择排序的是一种很自然的排序思想——每次选一个最小的来排。也就是第一次选一个最小的a1放在要输出的序列里,第二次选剩下最小的a2放在序列最后面,现在序列就变成a1,a2了。依次选最小的放序列最后面即可。
类似现在有一堆小孩,要从小个到大个排队。首先找出最矮个的小孩a1站在排头,然后挑剩下一堆小孩最矮的a2再站在a1的后面。依次就排好了。
b)复杂度分析:
i=0时,从0~n-1个里找最小的,需要n-1次比较,参看第4行的for循环,从1到n-1,所以共n-1次
i=1时,从1~n-1个里找最小的,需要n-2次比较
……
i=n-2时,需要n-1到n-1共1次比较
总计:(n-1)+(n-2)+...+1 = (n-1)*n/2
复杂度为O(n²)
c)排序过程:
Select Sort:
5 4 3 2 1
1 4 3 2 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
3,冒泡排序
这个排序在学完之后,同学们在说起排序的时候都会想到冒泡排序,可能原因是这个名字比较好吧,当然前提是它相对简单。
void Sort::BubbleSort()
{
for(int i=0;i<n-1;i++) //总共n个,只需要排n-1个即可
{
//将最小的冒泡到前面去,因为前面已经是排好的,所以只能冒到第i个
for(int j=n-1;j>i;j--)
{
Output();//这个是输出一下数组内容,可以看到单步排序的过程
if(a[j]<a[j-1])
swap(a[j],a[j-1]);
}
}
Output();
}
a)思想:
我实现的冒泡排序是两两比较,然后将最小的冒到前面。如第1个和第2个比较,如果第1个比第2个大,那么第2个就冒到第1个前面。
还是例如一排小孩要按照高矮个排序,矮个子的要排在前面。
选择排序的方法是:
放眼望去,自己找出最矮的拎到最前面去。第二步是在剩下找最矮的放到第二。。。一直到最后排序完成。
冒泡排序的方法是:
从最后一个小孩开始,他看看自己是不是比前面的矮,是比前面的矮的话就跟他换一下位置。这样倒数第1的小孩现在是倒数第2了。
然后是倒数第2的小孩看看自己是不是比前面的矮,是比前面的矮的话就跟他换一下位置,否则就不换。
然后是倒数第3的小孩。。。最后就完成最矮的肯定在最前面。到这里才算完成选择排序的第一趟。
然后继续冒第二矮的小孩。。。直到最后排序完成。
b)复杂度分析:
i=0时,从0~n-1个里找最小的,需要n-1次比较,参看第5行的for循环,从1到n-1,所以共n-1次
i=1时,从1~n-1个里找最小的,需要n-2次比较
……
i=n-2时,需要n-1到n-1共1次比较
(跟选择排序一模一样,不过移动次数会多一点)复杂度为O(n²)
c)排序过程:
Bubble Sort:
5 4 3 2 1
5 4 3 1 2
5 4 1 3 2
5 1 4 3 2
1 5 4 3 2
1 5 4 2 3
1 5 2 4 3
1 2 5 4 3
1 2 5 3 4
1 2 3 5 4
1 2 3 4 5
4,插入排序
void Sort::InsertSort()
{
for(int i=1;i<n;i++) //总共n个,只需要排n-1个即可
{
//前i-1个是排好的,将第i个插入到合适的位置
for(int j=i;j>0;j--)
{
Output();//这个是输出一下数组内容,可以看到单步排序的过程
if(a[j]<a[j-1])
swap(a[j],a[j-1]);
else
break;
}
}
Output();
}
a)思想:
将数据分为两份:排好序的和未排好序的。每次从未排好序的里面选一个插入到排好的序列中。当然要插入到适当位置,使得插入后还是排好序的序列。
由于是插入到已经排好序的序列中,所以就从后到前挨个比较即可,比自己大就与自己交换一下,遇到比自己小的时候,此时一定是找到了自己的合适的位置了。
可以用打扑克时候的插扑克牌来想象即可。
b)复杂度分析:
i=1时,将1号插入到序列中,只需跟0号比较,需要1次比较
i=2时,将2号插入到序列中,最多跟1号和0号比较,需要2次比较
……
i=n-1时,最多需要n-1次比较
复杂度为O(n²)
c)排序过程:
Insert Sort:
5 4 3 2 1
4 5 3 2 1
4 3 5 2 1
3 4 5 2 1
3 4 2 5 1
3 2 4 5 1
2 3 4 5 1
2 3 4 1 5
2 3 1 4 5
2 1 3 4 5
1 2 3 4 5
排序算法总结:
特点 名称 | 时间复杂度 | 原理 | 稳定性 | 举例(3,1,4,5,2) |
名次排序 | O(n2) | 先排出名次,再根据名次,将数据放入相应 的数组排序 | 稳定 | 名次是(3,1,4,5,2) 排序是(1,2,3,4,5) |
冒泡排序 | O(n2) | 一次冒泡是从前面开始两两比较,如果前面大 后面数小就互换,共冒n次泡 | 稳定 | 一次冒泡:1,3,4,2,5 二次冒泡:1,3,2,4,5 三次冒泡:1,2,3,4,5 四次冒泡:1,2,3,4,5 五次冒泡:1,2,3,4,5 |
插入排序 | O(n2) | 第一个数据不动,将第二个与之比较,并插 入,第三个与前两个比较并插入....直到n个 | 稳定 | 插入第二个:1,3,4,5,2 插入第三个:1,3,4,5,2 插入第四个:1,3,4,5,2 插入第五个:1,2,3,4,5 |
选择排序 | O(n2) | n个数中选择最大的放在最后,再在前n-1个 选择最大的放在倒数第二个...直到第一个. | 稳定 | 第一次:3,1,4,2,5 第二次:3,1,2,4,5 第三次:1,2,3,4,5 第四次:1,2,3,4,5 |
基数排序 | Θ(n) | 按照基数r分为r个盒子,将符合条件的数据 放入相应链表盒子里,直到排序完成 | 稳定 | 一次:1,2,3,4,5 |
堆排序 | O(nlogn) | 利用最大堆排序,将数据初始化为最大堆,依次 删除最大元素,直到删完,排序完成 | 不稳定 | 删除5,删除4,删除3, 删除2,删除1,依次放入链表, 12345 |
拓扑排序 | O(n2) | 在由任务建立的有向图中,边(i,j)表示在装配 序列中任务i 在任务j 的前面,具有这种性质 的序列称为拓扑序列根据任务的有向图建立 拓扑序列的过程 | 稳定 | 无 |
快速排序 | 平均O(nlog2n) 最坏O(n2) | 不断寻找一个序列的中点,然后对中点左右 的序列递归的进行排序,直至全部序列排序 完成,使用了分治的思想 | 稳定 | 第一次;1,3,4,5,2 第二次:1,3,4,2,5 第三次:1,2,3,4,5 |
归并排序 | 平均O(nlog2n) 最坏O(nlog2n) | 将原序列划分为有序的两个序列,然后利用 归并算法进行合并,合并之后即为有序序列。 | 稳定 | 3,1 4,5,2 1,3 2,4,5 1, 2, 3 ,4, 5 |