一、排序概念
排序称为分类,就是把一批任意序列的数据记录,按关键字重新排成一个有序的序列。
排序一般又分为以下几种:
(1)稳定排序和不稳定排序
稳定排序:两个相等的数排序前的位置顺序与排序后位置的顺序不变。比如排序前:5,2,5。排序后:2,5,5。
不稳定排序:两个相等的数排序前的位置顺序与排序后位置的顺序颠倒。比如5,8,5,2,9。选择排序中:第一个5先跟2发生了交换。
(2)根据存储设备的不同,分为内部排序和外部排序
内部排序:数据全部存放在计算机的内存储器中进行的排序过程,在此期间没有进行内、外存储器的数据对象。
外部排序:指待排序记录的数量很大,以致内存不能依次容纳全部记录,所以排序的过程中,数据的主要部分存在外存储器上,借助与内存储器逐步调整记录之间的相对位置。在这个过程中,需要不断地在内、外存储器之间进行数据地交换。
稳定排序:直接插入排序、基数排序、归并排序、冒泡排序…
不稳定排序:快速排序、希尔排序、简单选择排序、堆排序…
二、排序的分类
1、直接插入排序:
基本思想:每一个待排序的记录按其排序码关键字的大小插到前面已经排好序的序列。直接插入过程可以理解为:不断建立监察哨,不断更新监察哨的位置
假设一组关键字序列为{48,35,18,45,12,68,33},一共7个记录
其上就是监察哨地位置变化结果。不断与监察范围的元素比较,范围内的数比监察哨大,就交换。
核心代码实现:
void insertsort(int a[],int n){
///从小到大排序
for(int i=2;i<=n;i++){
a[0]=a[i];///监察哨
int j=i-1;///监察范围最大值
while(a[0]<a[j]){
a[j+1]=a[j];
j--;
}
a[j+1]=a[0];
}
}///时间复杂度:O(n的平方/2)
2、折半插入排序(二分插入排序):
基本思想:类似二分查找,先取一个序列的中间关键字与当前关健字比较,如果相等则查找成功,否则就改变查找区间。但是排序通过查找元素的插入。注意:运用此算法的前提就是一个有序的序列,所以在直接插入排序的基础上再插入。
核心代码实现:
void insertsort(int a[],int n){
///从小到大排序
int low,high;
for(int i=2;i<=n;i++){
a[0]=a[i];///暂存a[i]
low=1;
high=i-1;
while(low<=high){
int mid=(low+high)/2;
if(a[0]<a[mid]) high=mid-1;
else low=mid+1;
}
for(int j=i-1;j>=high+1;j--) a[j+1]=a[j];
a[high+1]=a[0];
}
}
3、冒泡排序
基本思想:依次比较两个相邻的元素,如果(从小到大或从大到小)顺序相反就把它们交换。冒泡排序可以理解为,不断交换找最大数(冒泡)、缩小范围继续找次最小,直到所有元素排序完毕。
比如一个无序序列:45 15 68 2.其冒泡排序的简易图如下:
核心代码实现:
void bubblesort(int a[],int n){
for(int i=1;i<=n-1;i++)///不用遍历到n,因为j+1已经访问了
for(int j=1;j<=n-i;j++)///缩小范围
if(a[j+1]<a[j]){
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}///时间复杂度O(n的平方),
4、简单选择排序
基本思想:不断地找出序列中最小的数,然后与当前比较的数进行交换
核心代码实现:
void selectsort(int a[],int n){
for(int i=1;i<=n;i++)
{
int t=i;