数据结构与算法--排序

08 排序

8.0 各排序算法比较

在这里插入图片描述
在这里插入图片描述

关于稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,A1=A2,且A1在A2之前,而在排序后的序列中,A1仍在A2之前,则称这种排序算法是稳定的;否则称为不稳定的。例如简单选择排序中,序列5 8 5 2 9, 第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以该算法不稳定。

(1)不稳定算法:快(快速排序)些(shell 希尔排序)选(选择排序)队(堆排序);

快(快排)归(归并)空间大

(2)每一次排序之后都能确定至少一个元素位置的排序方法包括:

1.选择排序:每次将最大的数放到最后。所以最大的数排一次序后位置就确定了。

2.冒泡排序:同选择排序。每一次排序最大的值位置确定。

3.快排:每一次排序pivot的位置确定。

4.堆排序:每一次排序时,都是将堆顶的元素和最后一个节点互换,然后调整堆,再将堆大小减1。所以每一次排序堆顶元素确定。

不能至少确定一个元素的位置的方法包括:

1.插入排序:不到最后一步求的都是相对位置。

2.shell排序:对简单插入排序的改进。不到最后一步,是无法确定每个元素位置的。

3.归并排序:局部有序,并不能确定任一元素在全局的位置。

4.基数排序,计数排序:利用桶排序的思路,不是基于比较的排序,也无法在一次排序中确定某个元素的位置。因为每一次排序都是整体处理。

(3)其他

  • 元素的移动次数与关键字的初始排列次序无关的是:基数排序
  • 元素的比较次数与初始序列无关是:选择排序、折半插入排序
  • 算法的时间复杂度与初始序列无关的是:选择排序、堆排序、归并排序、基数排序
  • 算法的排序趟数与初始序列无关的是:插入排序、选择排序、基数排序

8.1 插入排序

8.1.1 直接插入排序

直接插入排序是一种最简单的排序算法,基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增 1 的有序表。

定义数据元素类型

typedef struct
{
    KeyType key;     // 关键字域
    ...              // 其他域
}ElemType;

定义表的顺序存储结构

typedef struct
{
    ElemType r[MAXSIZE+1];       // r[0] 为监视哨
    int length;
}SqList;
void InsertSort(SqList L)
{
    int i, j;
    for(i = 2; i < L.length; i++)
    {
        if(L.r[i].key < L.r[i-1].key)
        {
            L.r[0] = L.r[i];       // 放入监视哨
            for(j=i-1; L.r[j].key>L.r[0].key ;j--)
                L.r[j+1] = L.r[j];
            L.r[j+1] = L.r[0];
        }
    }
}
8.1.2 折半插入排序

折半查找 方法确定插入位置的排序。

void BinSort(SqList &L)
{
    int i, j, high, low, mid;
    for(i=2; i<L.length; i++)
    {
        L.r[0] = L.r[i];        // 设置监视哨
        low = 1;    high = i-1;     // i 之前都是有序的
        while(low<=high)
        {
            mid = (high+low)/2;
            if(L.r[0].key<L.r[mid].key)
                high = mid-1;
            else    low = mid+1;
        }
        
        for(j=i-1; j>=low; j--)
            L.r[j+1] = L.r[j];        // 记录后移
        L.r[low] = L.r[0];            // 插入
    }
}
8.1.3 希尔排序

先将整个待排序记录分割成若干个子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

8.2 交换排序

两两比较待排序记录的关键值,交换不满足顺序要求的记录,直到全部满足顺序要求为止。

8.2.1 冒泡排序
void BubbleSort(SqList &L)
{
    int m, j, flag=1;
    m = L.length-1;          // 最多进行 length -1 次排序
    while(m>0 && flag==1)
    {
        flag = 0;   // 没有发生交换,直接退出
        for(j=1, j<m; j++)
        {
            if(L.r[j].key > L.r[j+1].key)
            {
                flag = 1;
                L.r[0]=L.r[j];  
                L.r[j]=L.r[j+1];  
                L.r[j+1]=L.r[0];
            }
        }
        
        m--;
    }
}
8.2.2 快速排序

通常选择第一个元素作为枢轴。

int Partition(SqList &L, int low, int high)
{
    KeyType pivotkey;
    L.r[0] = L.r[low]; 
    pivotkey = L.r[low].key;       // 保存枢轴
    while(low<high)
    {
        while(L.r[high].key>pivotkey && low<high)
            high--;         // 不发生交换
        if(low<high)
        {
            L.r[low]=L.r[high];
            low++;
        }
        
        while(L.r[low].key<pivotkey && low<high)
            low++;
        if(low<high)
        {
            L.r[high]=L.r[low];
            h--
        }
    }
    
    L.r[low]=L.r[0];
    return low;
}

排序程序为

void QuickSort(SqList &L, int low, int high)
{
    int pivotloc;
    if(low<high)
    {
        pivotloc = Partition(L, low, high);
        QuickSort(L, low, pivotloc-1);
        QuickSort(L, pivot+1, high)
    }
}
8.2.3 归并排序

将子序列依次排序合并,最终完全排序。

8.3 选择排序

每次从待排序记录中选出关键字最小的记录,顺序放在已排序的记录序列的后面,直到全部排完为止。

8.3.1 简单选择排序
void SelectSort(SqList &L)
{
    int i, j, k;
    for(i=1; i<L.length; i++)
    {
        k=i;       // 先假设 i 即最小值的下标
        for(j=i+1, j<L.length; j++)
        {
            if(L.r[j].key<L.r[k].key)
                k = j;
        }
        
        if(i!=k)    // 交换
        {
            L.r[0]=L.r[i];  
            L.r[i]=L.r[k];  
            L.r[k]=L.r[0];            
        }
    }
}
8.3.2 堆排序
8.3.3 基数排序

多关键字排序。

“分配-收集”:分别按个位、十位、百位分配收集。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值