排序算法的理解和实现

以下内容部分参考《王道数据结构2020》

概述

排序算法一般分为两大类,一类是外部排序,这种排序的规模往往比较大,要排序的数据无法同时存放在内存中,必须在排序的过程中不断的在内外存之间移动;另一类是内部排序,规模较小。可以在完全在内存中进行。今天主要实现的是内部排序,常见的内部排序又可以分为五大类:插入排序、交换排序、选择排序、归并排序、基数排序。

一、插入排序

1.1 直接插入排序

主要思想

每次将一个待排序的记录,插入到前面已经有序的子序列中的恰当位置,直到全部记录插入完成
具体步骤:

  • 查找L(i)在L(1…i-1)适当的插入位置k
  • 从L(k)开始,所有元素向后移动一个位置
  • 将L(i)复制到L(k)

算法实现(C语言)

#include <stdio.h>
#define MAX 30

//定义数组
typedef struct {
    int r[MAX];
    int length;
}List;

int insertsort(List &l)
{
    int i,j;
    for(i=1;i<=l.length;i++)
    {
        l.r[0]=l.r[i];//r[0]位置做哨兵
        for(j=i-1;j>=0&&l.r[0]<l.r[j];j--)
        //在1...i-1之间找到合适的插入位置,同时判断是否需要向后移动元素的位置
        {
            l.r[j+1]=l.r[j];//向后移动元素的位置
        }
        l.r[j+1]=l.r[0];//找到合适的位置插入
    }
    return 1;
}

//初始化数组
void initial(List &l)
{
    int i;
    printf("please input size:");
    scanf("%d",&l.length);
    printf("input data:");
    for(i=1;i<=l.length;i++)
        scanf("%d",&l.r[i]);
}

main()
{
    List l;
    int i;
    initial(l);
    insertsort(l);
    printf("data output:");
    for(i=1;i<=l.length;i++)
        printf("%d ",l.r[i]);

}

二、交换排序

2.1 冒泡排序

主要思想

1.简述:从前往后(或从后往前)两两比较相邻元素的值,若为逆序,则交换它们,直到序列比较完毕,这是一趟冒泡排序,结果将最大的元素交换到序列的最后一个位置,确定了一个元素的最终位置。
2.详述:从前往后(或从后往前)从第一个元素开始,与第二个元素比较它们的值大小,若第一个元素的值大于第二个元素,则交换它们的位置,然后从第二个开始和第三个比较…直到第n-1个元素和第n个元素比较完毕,一趟下来,可以确定最大的元素已经在序列的最后一个位置,那么下一次排序就不用再和最后一个元素比较了,因为它的位置已经是正确的了,所以第二次只需要比较n-1次,依次类推,每完成一趟排序,待排序元素便少了一个。
图为冒泡排序的过程,第一趟冒泡时27 < 49 , 不交换; 13 < 27 ,不交换: 76 > 13,交换 : 97 > 13,交换: 65 > 13,交换;38 > 13,交换: 49 > 13,交换。通过第一趟冒泡后,最小元素己交换到第一个位置 ,也是它的最终位置。第二趟冒泡时对剩余子序列采用同样方法进行排序,以此类推,到第六趟结束后没有发生交换,说明表己有序,冒泡排序结束。
冒泡排序

算法实现(C语言)

#include <stdio.h>
#define MAX 30

//定义数组
typedef struct 
{
    int r[MAX];
    int length;
}List;

int bubblesort(List &l)
{
    int i,j,t;
    for(i=0;i<l.length;i++)
        for(j=0;j<l.length-i-1;j++)
            if(l.r[j]>l.r[j+1])
            {
                t=l.r[j];
                l.r[j]=l.r[j+1];
                l.r[j+1]=t;
            }
    return 1;
}

int initial(List &l)
{
    int i; 
    printf("input size:"); 
    scanf("%d",&l.length);
    printf("input data please:");
    for(i=0;i<l.length;i++)
    {
        scanf("%d",&l.r[i]);
    } 
    return 1;
}


main()
{
    List l;
    int i;
    initial(l);
    bubblesort(l);
    printf("output data:");
    for(i=0;i<l.length;i++)
        printf("%d ",l.r[i]);
}

2.2快速排序

主要思想

快速排序是基于分治法的:在待排序表 L[l…n ]中任取一个元素 pivot 作为枢轴(或基准,通常取首元素),通过一趟排序,将待排序表划分为独立的两部分 L[l…k-1 ] 和 [k+l…n],使得 L[l…k - 1 ] 中的所有元素小于 pivot,L [k+ l… n ] 中的所有元素大于等于 pivot,则 pivot 放在了其最终位置 L ( k ) 上,这个过程称为 一趟快速排序(或一次划分)。然后分别递归地对两个子表重复上述过程,直至每部分内只有一个元素或空为止,即所有元素放在了其最终位置上 。

一趟快速排序的过程是一个交替搜索和交换的过程,下面通过实例来介绍。
如图所示,假设两个指针 i 和 j,初值分别为 low 和 high ,取第一个元素 49 为枢轴赋值到变量 pivot 。指针 j 从 high 往前搜索找到第一个小于枢轴的元素 27 , 将 27 交换到 i 所指位置 。
快速排序1
快速排序2

算法实现(C语言)

#include <stdio.h>
#define MAX 30

//定义数组
typedef struct {
    int r[MAX];
    int length;
}List;

void QuickSort(List *l, int low, int high){
    if(low<high){ //递归跳出的条件
        int pivotpos = Partition(l, low, high); //划分
        QuickSort(l, low, pivotpos-1); //依次对两个子表进行递归操作
        QuickSort(l, pivotpos+1, high);
    }
}

int Partition(List *l, int low, int high){
    int pivot = l->r[low];
    while(low<high){
        while(low<high && l->r[high] >= pivot)
            --high;
        l->r[low] = l->r[high];
        while(low <high && l->r[low] <= pivot)
            ++low;
        l->r[high] = l->r[low];
    }
    l->r[low] = pivot;
    return low;
}

void Print(List l){
    for(int i=0;i<l.length;i++){
        printf("%d ", l.r[i]);
    }
    printf("\n");
}
void main(){
    List l = {{49,38,65,97,76,13,27,49},8};
    Print(l);
    QuickSort(&l, 0, 7);
    Print(l);
}

稳定性

在划分算法中,若右端区间有两个关键字相同,且均小于基准值的记录,则在交换到左端区间后,它们的相对位置会发生变化,即快速排序是一种不稳定的排序方法。例如 , 表 l = { 3, 2 , 2 },经过一趟排序后 l = { 2, 2, 3 },最终排序序列也是 l = { 2 , 2, 3 },显然 ,2 与 2 的相对次序己发生了变化 。

三、选择排序

3.1 简单选择排序

主要思想

假设要排序的序列是L(1…n),第i趟排序从L(i…n)里面选出最小的元素与L(i)交换,每一趟排序可以确定一个元素的最终位置,待排序元素也就少了一个,经过n-1趟排序后序列有序。

算法实现(C语言)

#include <stdio.h>
#define MAX 30

//定义数组
typedef struct {
    int r[MAX];
    int length;
}List;

void selectsort(List &l)//mian idear is remmber the number of smallest element after every compare with others
{
    int k,i,j,t;
    for(i=1;i<l.length;i++)//为了下标与元素序号的统一性,这里设置l.r[0]没有存放数据,从l.r[1]开始存放数据
    {
        k=i;
        for(j=i+1;j<=l.length;j++)
            if(l.r[j]<l.r[k])
                k=j;
        if(k!=i)
        {
            t=l.r[k];
            l.r[k]=l.r[i];
            l.r[i]=t;
        }
    }
}

int initial(List &l)
{
    int i; 
    printf("input size:"); 
    scanf("%d",&l.length);
    printf("input data please:");
    for(i=1;i<=l.length;i++)
    {
        scanf("%d",&l.r[i]);
    } 
    return 1;
}

main()
{
    List l;
    int i;
    initial(l);
    selectsort(l);
    printf("output data:");
    for(i=1;i<=l.length;i++)
        printf("%d ",l.r[i]);
}

3.2 堆排序

未完待续…

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值