C语言分析基础排序算法——交换排序

这篇具有很好参考价值的文章主要介绍了C语言分析基础排序算法——交换排序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

交换排序

冒泡排序

快速排序

Hoare版本快速排序

挖坑法快速排序

前后指针法快速排序

快速排序优化

快速排序非递归版


交换排序

冒泡排序

见C语言基础知识指针部分博客C语言指针-CSDN博客

快速排序

Hoare版本快速排序

Hoare版本快速排序的过程类似于二叉树前序遍历的过程,基本思想是:在需要排序的数据中确定一个值放入key中,接着使用左指针和右指针从数据的起始位置以及数据的末端位置向中间遍历,左指针找数值比key大的数据,右指针找数值比key小的数据,交换这两个指针的数据之后接着向中间移动,直到两个指针最后相遇时交换key所在的数值以及相遇位置的数值,完成第一趟排序,接着进行左边部分的排序,方法如同第一趟排序,左边排序完毕后进行右边部分的排序,方法如同第二趟排序,直到最后全部排序完成后为止。具体思路如下:

📌

注意key是数值的下标

//以下面的数组为例
int data[] = { 23,48,67,45,21,90,33,11 };

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

下面是完整过程递归图

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

参考代码

void swap(int* num1, int* num2)
{
    int tmp = *num1;
    *num1 = *num2;
    *num2 = tmp;
}

//一趟排序,返回key指向的位置
int PartSort(int* data, int left, int right)
{
    int key = left;//使key指向区间的第一个元素位置
    while (left < right)
    {
        //先让右侧指针先走,右指针找小
        while (left < right && data[right] >= data[key])
        {
            right--;
        }
        //再让左侧指针走,左侧指针找大
        while (left < right && data[left] <= data[key])
        {
            left++;
        }
        
        //交换右侧指针和左侧指针的数据
        swap(&data[right], &data[left]);
    }
    //执行完循环后,交换key所在位置的数据和right与left指针相遇的位置的数值
    swap(&data[key], &data[left]);
    //返回交换后的key指向的元素的位置
    return left;
}

//Hoare版本
void QuickSort_Hoare(int* data, int left, int right)
{
    //当left和right指针指向同一个位置或后一个位置结束排序
    if (left >= right)
    {
        return;
    }

    //获取到当前key的位置
    int key = PartSort(data, left, right);

    QuickSort_Hoare(data, left, key - 1);
    QuickSort_Hoare(data, key + 1, right);
}

Hoare版本问题分析

  • 在上面的过程分析中,使用第一个元素的位置作为key的位置,也可以使用最后一个元素作为key的位置,但是需要注意的是,以key指向第一个元素的位置为例,left指针一定需要指向第一个元素,而不是从第二个元素开始,例如下面的情况:当key位置的数据比其他数据都小时,right找小将一直向key所在位置移动

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

  • 在判断left指针或者right指针是否需要移动时,需要包括等于的情况,否则会进入死循环,例如下面的情况:当leftright指针同时指向一个等于key所在位置的元素

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

  • 对于递归结束的条件来说,需要出现left指针的值大于或者等于right指针的值,而不是仅仅一个大于或者等于,因为返回相遇的位置,即返回left指针或者right指针的位置而不是实际返回key所在位置,在交换过程中,只是交换key对应位置的数值和相遇位置的数值,并没有改变key指向的位置
  • 对于left指针和right指针相遇的位置的数值一定比key所在位置的数值小的问题,下面是基本分析:

分析主问题之前,先分析rightleft指针先走的原因:在初始位置时,left指针和right指针各指向第一个元素和最后一个元素但是left指针与key指针指向的位置相同,此时让right指针先走,而不是left指针先走,反之同理,具体原因如下:

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

接下来分析当right指针比left指针先走时,两个指针相遇时一定相遇到一个比key小的数值的问题

两个指针相遇的方式有两种情况

  • 第一种情况:left指针向right指针移动与其相遇
  • 第二种情况:right指针向left指针移动与其相遇

对于第一种情况,分析如下:

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

对于第二种情况,分析如下:

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

挖坑法快速排序

挖坑法快速排序相较于Hoare版本的快速排序没有效率上的优化,但是在理解方式上相对简单,其基本思路为:在数据中随机取出一个数值放入key变量中,此时该数值的位置即为一个坑位,接下来left指针从第一个元素开始key值大的数值,right指针从最后一个元素找比key值小的数值,此时不用考虑left指针和right指针谁先走,考虑right指针先走,当right指针找到小时,将该值放置到hole所在位置,更新holeright指针的位置,接下来left指针找大,当left指针找到较key大的数值时,将该数值存入hole中,更新holeleft所在位置,如此往复,直到第一趟排序结束。接着进行左边部分的排序,方法如同第一趟排序,左边排序完毕后进行右边部分的排序,方法如同第二趟排序,直到最后全部排序完成后为止。具体思路如下:

📌

注意key是数值

//以下面的数组为例
int data[] = { 23,48,67,45,21,90,33,11 };

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

int PartSort_DigHole(int* data, int left, int right)
{
    int hole = left;
    int key = data[left];
    while (left < right)
    {
        while (left < right && data[right] >= key)
        {
            right--;
        }
        data[hole] = data[right];
        hole = right;
        while (left < right && data[left] <= key)
        {
            left++;
        }
        data[hole] = data[left];
        hole = left;
    }
    data[hole] = key;
    return hole;
}

//挖坑法
void QuickSort_DigHole(int* data, int left, int right)
{
    if (left >= right)
    {
        return;
    }

    int hole = PartSort_DigHole(data, left, right);

    QuickSort_DigHole(data, left, hole - 1);
    QuickSort_DigHole(data, hole + 1, right);
}

前后指针法快速排序

前后指针法相对Hoare版本和挖坑法也没有效率上的优化,但是理解相对容易,基本思路如下:在前后指针法中,有一个key指针,该指针指向一个随机的数值的下标位置,接下来是一个prev指针,指向数据的第一个元素的下标位置,以及一个cur指针指向第二个元素的下标位置,cur指针和prev指针向前遍历,当遇到比key小的数值时,prev指针先移动柜,再进行curprev进行对应位置的数值交换,接着cur指着移动,否则只让cur指针移动,当cur走到数据的结尾时结束循环,交换prevkey指针的数据,完成第一趟排序。接着进行左边部分的排序,方法如同第一趟排序,左边排序完毕后进行右边部分的排序,方法如同第二趟排序,直到最后全部排序完成后为止。具体思路如下:

📌

注意key是数值的下标,并且用leftright控制递归区间

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

int PartSort_Prev_postPointer(int *data, int left, int right)
{
    int key = left;
    int cur = left + 1;
    int prev = left;
    while (cur <= right)
    {
        //++prev != cur可以防止cur和自己本身交换导致多交换一次
        if (data[cur] < data[key] && ++prev != cur)
        {
            prev++;
            swap(&data[cur], &data[prev]);
        }
        cur++;
    }
    swap(&data[prev], &data[key]);
    return prev;
}

//前后指针法
void QuickSort_Prev_postPointer(int* data,int left, int right)
{
    if (left >= right)
    {
        return;
    }

    int key = PartSort_Prev_postPointer(data, left, right);

    QuickSort_Prev_postPointer(data, left, key - 1);
    QuickSort_Prev_postPointer(data, key + 1, right);
}

快速排序优化

在快速排序优化部分,采用三数取中的思路对快速排序有大量重复数据或者有序情况下进行优化,所谓三数取中,即第一个元素的位置和最后一个元素的位置加和取一半的数值在数据中的位置,但是此时需要注意的是key当前位置为mid所在位置,为了不改变原来的快速排序代码,获得中间值下标时,交换key位置的值和mid位置的值即可

//三数取中
int GetMidIndex(int* data, int left, int right)
{
    int mid = (left + right) / 2;
    //获取左、中、有三个数中的中间数
    if (data[left] > data[mid])
    {
        if (data[mid] > data[right])
        {
            //left>mid>right
            return mid;
        }
        else if (data[left] > data[right])
        {
            //left>right>mid
            return right;
        }
        else
        {
            //right>left>mid
            return left;
        }
    }
    else
    {
        if (data[mid] < data[right])
        {
            //right>mid>left
            return mid;
        }
        else if (data[right] > data[left])
        {
            //mid>right>left
            return right;
        }
        else
        {
            //mid>left>right
            return left;
        }
    }
}

以前后指针版本修改为例

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <assert.h>

void swap(int* num1, int* num2)
{
    int tmp = *num1;
    *num1 = *num2;
    *num2 = tmp;
}

//三数取中
int GetMidIndex(int* data, int left, int right)
{
    int mid = (left + right) / 2;
    //获取左、中、有三个数中的中间数
    if (data[left] > data[mid])
    {
        if (data[mid] > data[right])
        {
            //left>mid>right
            return mid;
        }
        else if (data[left] > data[right])
        {
            //left>right>mid
            return right;
        }
        else
        {
            //right>left>mid
            return left;
        }
    }
    else
    {
        if (data[mid] < data[right])
        {
            //right>mid>left
            return mid;
        }
        else if (data[right] > data[left])
        {
            //mid>right>left
            return right;
        }
        else
        {
            //mid>left>right
            return left;
        }
    }
}

int PartSort_Prev_postPointer(int *data, int left, int right)
{
    int mid = GetMidIndex(data, left, right);
    swap(&data[left], &data[mid]);
    int key = left;
    int cur = left + 1;
    int prev = left;
    while (cur <= right)
    {
        //++prev != cur可以防止cur和自己本身交换导致多交换一次
        if (data[cur] < data[key] && ++prev != cur)
        {
            swap(&data[cur], &data[prev]);
        }
        cur++;
    }
    swap(&data[prev], &data[key]);
    return prev;
}

//前后指针法
void QuickSort_Prev_postPointer(int* data,int left, int right)
{
    if (left >= right)
    {
        return;
    }

    int key = PartSort_Prev_postPointer(data, left, right);

    QuickSort_Prev_postPointer(data, left, key - 1);
    QuickSort_Prev_postPointer(data, key + 1, right);
}

int main()
{
    int data[] = { 23,48,67,45,21,90,33,11 };
    int sz = sizeof(data) / sizeof(int);
    QuickSort_Prev_postPointer(data, 0, sz - 1);
    for (int i = 0; i < sz; i++)
    {
        printf("%d ", data[i]);
    }

    return 0;
}
输出结果:
11 21 23 33 45 48 67 90

快速排序非递归版

由于递归的函数栈帧空间是在栈上创建的,而且栈上的空间较堆空间小,所以当数据量太大时,可以考虑用快速排序的非递归版,一般用栈来实现,基本思路如下:首先将数据的头和尾进行入栈操作,再在循环中通过出栈和获取栈顶元素控制左区间和右区间,可以先执行左区间或者右区间,本处以先右区间再左区间为例,通过需要拆分数据的部分出栈排序,再接着重复步骤最后排序完成,具体思路分析如下:

C语言分析基础排序算法——交换排序,数据结构与算法,c语言,算法,数据结构

void QuickSort_NotRecursion(int* data, int left, int right)
{
    ST st = { 0 };
    STInit(&st);
    //压入第一个元素和最后一个元素所在位置
    STPush(&st, left);
    STPush(&st, right);

    while (!STEmpty(&st))
    {
        //获取区间
        int right = STTop(&st);
        STPop(&st);
        int left = STTop(&st);
        STPop(&st);

        //单趟排序
        int key = PartSort_Hoare(data, left, right);

        //更新区间
        //先压右侧区间
        if (key + 1 < right)
        {
            STPush(&st, key + 1);
            STPush(&st, right);
        }

        //再压左侧区间
        if (left < key - 1)
        {
            STPush(&st, left);
            STPush(&st, key - 1);
        }
    }

    STDestroy(&st);
}

快速排序的时间复杂度为,空间复杂度为,属于不稳定算法文章来源地址https://www.toymoban.com/news/detail-839644.html

到了这里,关于C语言分析基础排序算法——交换排序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构——排序算法(C语言)

    本篇将详细讲一下以下排序算法: 直接插入排序 希尔排序 选择排序 快速排序 归并排序 计数排序 排序的概念 排序:所谓排序,就是使一串记录,按照其中的某个或某写的大小,按照递增或递减0排列起来的操作。 稳定性的概念 假定在待排序的记录序列中,存在多个

    2024年02月08日
    浏览(42)
  • 数据结构基础之排序算法

    在数据结构中,常见的排序算法有以下几种: 冒泡排序(Bubble Sort):通过比较相邻元素并交换它们的位置,每轮将最大(或最小)的元素冒泡到末尾,重复执行直到排序完成。 特点:简单易懂,但对于大型数据集效率较低。 时间复杂度: 最优情况:O(n)(当数组已经排序好

    2024年02月15日
    浏览(30)
  • 【数据结构】排序算法的稳定性分析

    💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃 个人主页 :阿然成长日记 👈点击可跳转 📆 个人专栏: 🔹数据结构与算法🔹C语言进阶 🚩 不能则学,不知则问,耻于问人,决无长进 🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍 前言: 前面我们已经

    2024年02月08日
    浏览(44)
  • 《数据结构与算法》之十大基础排序算法

    冒泡排序是一种交换排序,它的思路就是在待排序的数据中,两两比较相邻元素的大小,看是否满足大小顺序的要求,如果满足则不动,如果不满足则让它们互换。 然后继续与下一个相邻元素的比较,一直到一次遍历完成。一次遍历的过程就被成为一次冒泡,一次冒泡的结束

    2024年02月05日
    浏览(85)
  • 数据结构与算法——排序(C语言实现)

    ✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿 🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟 🌟🌟 追风赶月莫停留 🌟🌟 🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀 🌟🌟 平芜尽处是春山

    2024年04月09日
    浏览(39)
  • C++基础-介绍·数据结构·排序·算法

    C++是一门风格严谨又不失自由的开发语言,提供了完整的内存管理、支持函数式编程和面向对象编程,支持模板、多继承、多实现、重载、重写等多态特性。 优势在于目前90%的操作系统、数据库、应用基础架构、硬件嵌入式等都是使用C/C++制作的,而C++是对C的标准扩展,掌握

    2024年02月03日
    浏览(33)
  • 数据结构实验任务八:排序算法的实现与分析

    问题描述 统计成绩:给出 n 个学生的考试成绩表,每条信息由姓名和分数组成,试设 计一个算法: 1.按分数高低次序,打印出每个学生在考试中获得的名次,分数相同的为同 一名次; 2.按名次列出每个学生的姓名与分数。 输入要求 输入 n+1 行,前 n 行是 n 个学生的信息(姓

    2024年02月04日
    浏览(46)
  • 内部排序算法比较-数据结构C语言课设

    名称: 内部排序算法比较 内容: 在教科书中,各种内部排序算法的时间复杂的分析结果只给出了算法执行时间的阶,或大概执行时间。试通过随机数据比较各种算法的比较次数和移动次数,以取得直观感受。 任务: (1)对以下7中常会用的内部排序算法进行比较

    2024年02月12日
    浏览(43)
  • 数据结构与算法基础(王卓)(28):排序概述(分类)、直接插入排序思路

    目录 排序分类:(本章目录) 按数据存储介质:(学习内容) 内部排序: 外部排序: 按比较器个数:(学习内容) 串行排序: 并行排序: 按主要操作:(学习内容、里面的排序都会重点学) 比较排序: 基数排序: 按辅助空间: 原地排序: 非原地排序: 按稳定性: 稳

    2023年04月26日
    浏览(32)
  • 【数据结构】八大排序算法(内含思维导图和画图分析)

    作者主页: paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《JAVA数据结构》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将javaSE基础知识一网打尽,希望可以帮到读者们哦。 其他专栏:

    2024年02月08日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包