排序
1. 将一个数据元素(或记录)的任意序列,重新排列成一个按关键字有序的序列
2. 排序分类
第一种分法:按待排序记录所在位置
(1) 内部排序:待排序记录全部存放在内存的排序过程
(2) 外部排序:待排序记录的数量很大,以致于内存一次不能容纳全部记录,在排序过程中尚需要对外存进行访问的排序过程
第二种分法:按排序依据原则
(1) 插入排序:直接插入排序、折半插入排序、希尔排序
(2) 交换排序:冒泡排序、快速排序
(3) 选择排序:简单选择排序、堆排序
(4) 归并排序:2—路归并排序
(5) 基数排序
3. 内部排序
(1) 直接插入排序:将一个记录插入到已排好序的有序表中,第i趟将第i+1个元素插入到前i个元素中—此时前i个元素有序,从后往前顺序找插入点,顺便往后移动元素(时间复杂度: )
(2) 折半插入排序:查找插入位置的时候用折半查找法(时间复杂度: )
(3) 希尔排序(缩小增量排序):先将整个待排记录序列分割为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序(因为插入排序:基本有序时,移动元素少;n值较小时,效率高)
希尔排序的一个特点:子序列的构成不是简单地“逐段分割”,而是将相隔某个“增量”的记录组成一个子序列,需要注意的是:应使增量序列中的值没有除了1之外的公因子,而且最后一个增量值必须等于1(时间复杂度: )
(4) 冒泡排序:每次关键字最大的记录被安置到最后一个记录的位置(时间: )
(5) 快速排序:通过一趟排序将待排记录分割为独立的两个部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序——递归(时间复杂度: ;空间消耗较大,需要一个栈空间实现递归)
(6) 简单选择排序:通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录交换(时间复杂度: ,与序列中数据初始排列无关)
(7) 树形选择排序(锦标赛排序):按照锦标赛的思想进行选择排序的方法,首先对N个记录的关键字进行两两比较,然后在其中N/2个较小者之间再进行两两比较,直到选出最小关键字的记录为止(时间复杂度: ;辅助存储空间较多,最大值多余比较等)
(8) 堆排序:堆排序只需要一个记录大小的辅助空间,每个待排序的记录仅占一个存储空间;堆的特点:完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值;
1. 输出堆顶元素之后,以堆中最后一个元素替代堆顶元素位置,然后,从上往下,和其左、右孩子结点中较小(或较大)且小于(或大于)该结点者交换,直到叶子结点或其左右孩子结点都不小于(或大于)该结点
第i个元素的左右孩子分别为第2i个元素和第2i+1个元素
2. 从一个无序序列建堆的过程就是一个反复筛选的过程,如将此序列看成是一个完全二叉树,则最后一个非终端结点是第n/2个元素,由此筛选只需从第n/2个元素开始,依次向前,直到第1个元素,筛选过程为:和其左右孩子中较小(或较大)且比自身小(或大)者交换,直到叶子结点或其左右孩子结点都小于(或大于)自身。
堆排序方法对记录数较少的文件并不值得提倡,但对n值较大的文件还是很有效的
(堆排序的时间复杂度为: ;且在最坏情况下时间复杂度不变)
(9)归并排序:归并的含义是将两个或两个以上的有序表组合成一个新的有序表
假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个长度为2或1的有序子序列,然后再两两归并,直到得到一个长度为n的有序序列为止这种排序方法称为2—路归并排序——核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列(时间复杂度: )
递归形式的2—路归并算法形式上简洁,但实用性很差,归并算法的和快排算法、堆排序算法相比,最大的特点是,它是一种稳定的排序方法
(10)基数排序:基数排序不需要进行记录关键字之间的比较,基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法
链式基数排序:基数排序是借助“分配”和“收集”两种操作对单逻辑关键字进行排序的一种内部排序方法(比如把每一个十进制数字的每一位(个、十、.百)看成关键字,按不同关键字,依次分配,收集)(时间复杂度: )
4. 各种内部排序方法的比较
(1) 平均时间性能而言,快排最佳,但快排最坏情况下,时间性能不如堆排序和归并排序;在n值较大时,归并排序时间比堆排序省,但需要辅助空间较大
(2) 所有简单排序中,在序列中的记录基本有序或n值较小时,直接插入排序最佳
(3) 基数排序适用于n值很大而关键字较小的序列
(4) 基数排序、归并排序和所有简单排序都是稳定的
(5) 排序方法 简单排序 快速排序 堆排序 归并排序 基数排序
平均时间
最坏情况
辅助存储
(6) 借助于比较进行排序的算法在最坏情况下能达到的最好时间复杂度为
快排算法:
void quicksort(int *a,int left,int right)
{
int i = left;
int j = right;
int temp;
if(left > right) return;
temp = a[left];
while(i != j)
{
while(a[j] >= temp && j > i) --j;
if(j > i) a[i++] = a[j];
while(a[i] <= temp && j > i) ++i;
if(j > i) a[j--] = a[i];
}
a[i] = temp;
quicksort(a,left,i-1);//递归左边
quicksort(a,i+1,right);//递归右边
}