文章目录
第九章 排序
排序的基本概念和分类
排序的稳定性:
当 k i = k j k_i=k_j ki=kj时,如果排序前 r i , r j r_i,r_j ri,rj的前后关系和排序后不变,则称此排序方法是稳定的。
内排序和外排序:内排序是排序过程中,待排序的记录全部放置在内存中;外排序是由于排序的记录个数太多,不能同时放置在内存,排序过程中需要在内外存之间多次交换数据才能进行。
影响排序算法的性能的三个方面:
- 时间性能
- 辅助空间
- 算法的复杂度
根据排序中主要操作方法分类:
- 插入排序
- 交换排序
- 选择排序
- 归并排序
排序用到的结构和函数:
顺序表结构:
#define MAXSIZE 10
typedef struct SqList
{
int r[MAXSIZE+1]; // 存储要排序数组,r[0]用作哨兵或临时变量
int length; // 用来记录顺序表的长度
}
数组两元素交换:
void swap(SqList *L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
冒泡排序
思路:冒泡排序是一种交换排序,基本思想是两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
最简单的冒泡实现:
void BubbleSort0(SqList *L)
{
int i, j;
for (i=1; i<L->length;i++)
{
for (j=i+1; j<=L->length; j++)
{
if (L->r[i] > L->r[j])
{
swap(L, i, j); // 换i和j还是挺笨的
}
}
}
}
正常冒泡算法:
void BubbleSort(SqList *L)
{
int i, j;
for (i=1; i<L->length;i++)
{
// j从后往前循环,小的往前送
for (j=L->length-1; j>=i; j--)
{
if (L->r[j] > L->r[j+1])
{
swap(L, j, j+1);
}
}
}
}
冒泡排序优化
普通冒泡法存在的问题:比如{2,1,3,4,5,6,7,8,9},只需要交换第一个位置和第二个位置,如果使用上面的冒泡,或有很多多余的步骤。
解决的思路:如果已经序列已经有序,不再发生交换,那么可以做个标记,停止循环。
实现代码:
void BubbleSort2(SqList *L)
{
int i, j;
Status flag = True;
//若flag为false则表示不再发生交换,因此退出循环
for (i=1; i<L->length && flag; i++)
{
flag = FALSE;
for (j=L->length-1; j>=1; j--)
{
if (L->r[j] > L->r[j+1])
{
swap(L, j, j+1);
flag = True; // 如果有数据交换,则flag为true
}
}
}
}
冒泡排序的时间复杂度:
最好的情况:只需要n-1次比较,此时复杂度为 O [ n ] O[n] O[n]
最坏的情况:待排序的数组为逆序,需要比较 ∑ i = 2 n ( i − 1 ) = n ( n − 1 ) 2 \sum^n_{i=2}(i-1)=\frac{n(n-1)}{2} ∑i=2n(i−1)=2n(n−1)次,时间复杂度为 O [ n 2 ] O[n^2] O[n2]
JAVA实现冒泡排序
工具类:
public class utils {
public static void swap(int[] L, int i, int j){
int temp = L[i];
L[i] = L[j];
L[j] = temp;
}
public static void show(int[] a) {
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
方法类:
import Sort.utils.utils;
public class bubbleSort {
public static void main(String[] args) {
int[] a = {
62, 58, 88, 47, 73, 99, 35, 52, 93, 37};
BubbleSort0(a);
// utils.show(a);
int[] b = {
62, 58, 88, 47, 73, 99, 35, 52, 93, 37};
BubbleSort1(b);
utils.show(b);
}
// 当不再发生交换时,停止循环
private static void BubbleSort1(int[] a) {
int len = a.length;
boolean flag = true;
for (int i=len-1; i>=0 && flag; i--){
flag = false;
for (int j=0; j<i; j++){
// 发生交换再改变 比 不改变再标记 更简单
if (a[j] > a[j+1]){
utils.swap(a, j, j+1);
flag = true;
}
}
}
}
// 升序
private static void BubbleSort0(int[] a) {
int len = a.length;
for (int i = len-1; i >=0; i--) {
for (int j=0; j < i; j++){
if (a[j] > a[j+1]){
utils.swap(a, j, j+1);
}
}
}
}
}
简单选择排序
思路:通过 n − i n-i n−i次关键字间的比较,从 n − i + 1 n- i + 1 n−i+1个记录中选出关键字最小的记录,并和第 i i i个记录交换之。
代码实现:
void SelectSort(SqList *L)
{
int i, j, min;
for (i=1; i<L->length; i++)
{
min = i;
for (j=i+1; j<=L->length; j++)
{
// 记录最小的,以待交换
if (L->r[min] > L->r[j])
min = j;
}
if (i!=min) // 如果不等,说明找到了最小值
swap(L, i, min);
时间复杂度:
无论好坏,比较次数都是 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1),交换次数最好为0,最差为 n − 1 n-1 n−