【数据结构与算法】单链表的排序算法(选择,冒泡,递归)

这篇具有很好参考价值的文章主要介绍了【数据结构与算法】单链表的排序算法(选择,冒泡,递归)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
  • 选择排序
  • 冒泡排序
  • 快速排序
  • 合并两条链表并排序

选择排序

链表的选择排序思想与数组的排序类似,但是链表需要先找到里面最小或者最大的值,然后将这个值用改链语句进行操作

我们先看这个改链语句的操作(min是笔者打错了应该是max,但是图已经画好了就没有改)

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
移动q这个指针找到最大的min,然后利用i保存q的前一个节点这样就能找到min_on.

接下来进行改链语句的操作

min_on->next = min->next; // 1

min->next = tail->next; // 2

tail->next = min; //3

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
接下来将tail前移一位重复操作。

void insert(li *head)	//传进来一个有头节点的链表
{
    li* tail,*i,*min,*q,*min_on;
    /*注意条件是 tail&&tail->next 因为如果tail->next == null
     会使程序进入里面的for循环出现问题*/
    for(tail = head; tail&&tail->next; tail=tail->next)
    {
        min = tail->next;
        for(q = tail->next,i = tail; q; i=q,q=q->next)	//i是p的上一个节点
        {
            if(q->digit > min->digit) //寻找最大的数
            {
                min = q;
                min_on = i;	//保存min的上一个节点
            }
        }
        if(tail->next != min)    //如果找到比tail->next更小的 min那么就进行插入
        {
            min_on->next = min->next;
            min->next = tail->next;
            tail->next = min;
        }
    }
}

冒泡排序

冒泡排序最重要的一步就是将元素下沉,然后重新判断循环次数

在这里我们首先引入一个tail的变量

#例如2,4, 5,null 三个数由大到小排序

数字 2 4 5 null
p 1 tail

初始时令tail == null;让p从1位置开始移动

结束条件是p != tail,

这样第一次时:就能保证1交换两次,接下来将tail向前移动,让tail = null的前一个位置;

此时我们将2下沉到底部;数据变为:4,5,2

数字 4 5 2 null
p 1 tail

p继续从1 位置开始移动

第二次时就能保证4交换1次;数据就变成了5,4,2完成排序。

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
接下来我们看如何进行改链操作

p->next = q->next; //1

q->next = q->next->next; //2

p->next->next = q; //3

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
接下来移动q的位置使得p,q始终相邻.

q = p->next;

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
代码如下:

void bubbling(li *head)	//传进来一个有头节点的链表
{
    li *tail,*p,*q;
    tail = NULL;
    /*假定如果三个数排序,第二个数确定了那么
    第一个也就确定了,不需要对第一个数排序*/
    while((head->next->next) != tail) 
    {
        p = head;
        q = head->next;
        /*冒泡排序的本质将所找到的数都下沉,所以内层循环比外层小一个节点*/
        while((q->next) != tail)
        {
            if((q->digit) > (q->next->digit))   //不停判断两个相邻的数并且交换顺序
            {
                p->next = q->next;
                q->next = q->next->next;
                p->next->next = q;
                q = p->next;    //始终保存p,q是相邻的位置
            }
            q = q->next;
            p = p->next;
        }
        /*最重要的一步,将tail不停向前移动*/
        tail = q;   
    }
}

快速排序

数组快速排序的思想和链表的一样,主要问题就是存在改链的操作。

首先我们还是做一个类似二分法的递归操作,叫做"分", 接下来分别给两边节点排序

void quick_sort(node *head, node *tail)	//传进来一个有头节点的链表,初始时tail为NULL
{
    //头结点是空的或者表是空的或者表只有一个节点时候不用排
    //tail是链表的结束点,一开始等于NULL,后面等于privot
    if(!head || head->next == tail || head->next->next == tail)
    {
        return ;
    }
    //baisc前的节点都比basic小,baisc后的节点都比baisc大
    node *privot = partition(head, tail);  
    
    /*因为在"治"的操作中privot会变成下一个节点,
    所以此时和数组时不一样,不需要类似privot-1/+1的操作*/
    quick_sort(head, privot); //把head->next到privot前一个进行递归排序
    quick_sort(privot, tail); //从privot->next到tail前一个进行递归排序
}

接下来我们进行排序,首先选取一个基准点,如何将比基准点大/小的值放左边,比基准点小/大的放右边。

例如2,1,4,null的改链操作

先得到一个基准点 privot = head->next

privot->digit = 2;

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
接下来进行改链操作,假定为由小到大排序

 i->next = p->next;		//1

 p->next = head->next;		//2

 head->next = p;		//3

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
此时改链完成我们得到

单链表选择排序算法,数据结构与算法,排序算法,链表,算法,数据结构,c语言
那么如果后面的4还需要排序的话我们可以将 p = i->next 然后重复以上步骤进行排序。

"治"的代码如下:

node *partition(node *head, node *tail)	//结构体指针类型函数,需要一个结构体指针的返回值
{
    //头结点是空的或者表是空的或者表只有一个节点时候不用排
    //已经在调用函数前判断好了,进来的链表都是至少有两个元素的
    node *p, *i, *privot; 
 
    privot = head->next;  //privot是基准点
 
    //从privot后面开始遍历,找到比privot小的就插入到head后面,直到tail结束,i是p的前驱节点
    //这里head可以理解为本次待划分的链表的头结点,tail是链表的最后一个节点的下一个可以理解为NULL
    for(i = privot, p = privot->next; p && p != tail; p = i->next)
    {
        if(privot->digit < p->digit)  //用头插入法把所有比privot小插入到head后面
        {
            i->next = p->next;
            p->next = head->next;
            head->next = p;
        }
        else  //没有找到比privot小的就一直后移,i与p同时后移
        {
            i = i->next;  
        }
    }
    return privot;  
}

合并两条链表并排序

接下来我们练习一道例题,将两个链表合成为一个链表并使它有序

输出:

1 3 5 5 6

4 2 5 1 9

输出:

1 1 2 3 4 5 5 5 6 9

我们首先将两个链表连接

void sum(mlist *a,mlist *b)	 //传入两个带有头节点的链表
{
    mlist *p;
    p = a;
    while(p->next)
    {
        p = p->next;
    }

    //释放掉b链表的表头
    mlist *t = b;
    b = b->next;
    free(t);    

    p->next = b;    //连接a,b链表
}

然后我们就可以将链表进行排序了,完整的代码如下文章来源地址https://www.toymoban.com/news/detail-759821.html

#include <stdio.h>
#include <stdlib.h>
typedef struct _lis{
    int digit;
    struct _lis *next;
}mlist;

typedef struct _ls{
    mlist *head;
}helist;

void make(mlist *meter);   //制作链表
void sum(mlist *a,mlist *b); //链表合成
void output(mlist *meter);    //输出链表
void bubbling(mlist *head);    //冒泡排序

int main()
{
    helist a,b;
    a.head  = (mlist*)malloc(sizeof(mlist));
    a.head->next = NULL;
    b.head  = (mlist*)malloc(sizeof(mlist));
    b.head->next = NULL;

    printf("请输入a链表\n");
    make(a.head);	//制作链表
    printf("请输入b链表\n");
    make(b.head);    

    sum(a.head,b.head);	//链表连接
    bubbling(a.head);	//链表排序
    output(a.head);	//输出链表
}

void make(mlist *meter)	//制作
{
    int number;
    mlist *t;
    t = meter;          
    while(scanf("%d",&number) != EOF)	//尾插法制作一个链表
    {  
        mlist *p = (mlist*)malloc(sizeof(mlist));
        p->digit = number;
        p->next = NULL;

        t->next = p;
        t = p;
    }
}

void output(mlist *meter)	//输出
{
    for(mlist *i = meter->next; i; i=i->next)
    {
        printf("%d\t",i->digit);	//输出节点的值
    }    
    printf("\n");
}

void sum(mlist *a,mlist *b)	//连接
{
    mlist *p;
    p = a;
    while(p->next)
    {
        p = p->next;
    }

    //释放掉b链表的表头
    mlist *t = b;
    b = b->next;
    free(t);    

    p->next = b;    //连接a,b链表
}

void bubbling(mlist *head)	//排序,传进来一个有头节点的链表
{
    mlist *tail,*p,*q;
    tail = NULL;
    /*假定如果三个数排序,第二个数确定了那么
    第一个也就确定了,不需要对第一个数排序*/
    while((head->next->next) != tail) 
    {
        p = head;
        q = head->next;
        /*冒泡排序的本质将所找到的数都下沉,所以内层循环比外层小一个节点*/
        while((q->next) != tail)
        {
            if((q->digit) > (q->next->digit))   //不停判断两个相邻的数并且交换顺序
            {
                p->next = q->next;
                q->next = q->next->next;
                p->next->next = q;
                q = p->next;    //始终保存p,q是相邻的位置
            }
            q = q->next;
            p = p->next;
        }
        /*最重要的一步,将tail不停向前移动*/
        tail = q;   
    }
}

到了这里,关于【数据结构与算法】单链表的排序算法(选择,冒泡,递归)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • C语言简单的数据结构:单链表的有关算法题(2)

    接着我们介绍后面的三道题,虽然代码变多了但我们的思路更加通顺了 题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/ 创建新链表,遍历原链表,将节点值小的进行尾插到新链表中 这里要多次进行对NULL的判断,开始传入列表,中间newHead的判断,循环出来一个为NULL的判断

    2024年04月15日
    浏览(40)
  • 【数据结构与算法】排序算法:冒泡排序,冒泡排序优化,选择排序、选择排序优化

    目录 一、冒泡排序 1、冒泡排序思想 2、冒泡排序算法的性能分析 代码实现: 二、选择排序 1、选择排序思想 2、选择排序算法的性能分析  代码实现: 1、冒泡排序思想 冒泡排序的基本思想是通过相邻元素之间的比较和交换来逐步将最大(或最小)的元素移到右边(或左边

    2024年01月19日
    浏览(38)
  • 数据结构与算法—插入排序&选择排序

    目录 一、排序的概念 二、插入排序   1、直接插入排序  特性总结: 2、希尔排序 特性总结:  三、选择排序 1、直接选择排序  特性总结: 2、堆排序—排升序(建大堆) 向下调整函数 堆排序函数 特性总结: 代码完整版:   头文件  函数文件  测试文件 排序 :所谓排序,

    2024年01月20日
    浏览(43)
  • 【数据结构与算法】排序算法(选择排序,冒泡排序,插入排序,希尔排序)

    基本概念这了就不浪费时间解释了,这四种都是很简单的排序方式,本专栏后续文章会出归并排序,计数排序,快速排序,堆排序,桶排序等排序算法,今天这篇文章中给出选择排序,冒泡排序,插入排序和希尔排序的实现; 如果发现文章中有错误,还请大家指出来,我会非

    2024年02月15日
    浏览(49)
  • 数据结构算法--2 冒泡排序,选择排序,插入排序

    思想就是将相邻元素两两比较,当一个元素大于右侧相邻元素时,交换他们的位置,小于右侧元素时,位置不变,最终序列中的最大元素,像气泡一样,到了最右侧。 这时冒泡排序第一轮结束,数列最右侧元素9的位置可认为是一个有序区,有序区目前有一个元素. 第二轮排序

    2024年02月13日
    浏览(36)
  • 【数据结构】八大排序之简单选择排序算法

    🦄 个人主页 :修修修也 🎏 所属专栏 :数据结构 ⚙️ 操作环境 : Visual Studio 2022 目录 一.简单选择排序简介及思路 二.简单选择排序的代码实现 三.简单选择排序的优化 四.简单选择排序的时间复杂度分析 结语 简单选择排序算法(Simple Selection Sort) 是一种简单直观的 选择排序算

    2024年02月01日
    浏览(62)
  • 【数据结构与算法】:选择排序与快速排序

    🔥 个人主页 : Quitecoder 🔥 专栏 :数据结构与算法 我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:腾讯云 欢迎来到排序的第二个部分:选择排序与快速排序! 选择排序是一种简单直观的比较排序算法。该算法的基本思想是在每一轮中选出当前未排序部分的最

    2024年03月17日
    浏览(40)
  • 数据结构上机练习——单链表的基本操作、头文件、类定义、main函数、多种链表算法的实现,含注释

      头文件和源文件分开有很多好处:可以提高编译速度、提高代码的可维护性、提高代码的可重用性和可扩展性,同时也可以使代码结构更清晰,方便代码的管理和维护。 LinkList.h test.cpp                  (下面所有函数都默认在类中实现)   我们以

    2024年02月07日
    浏览(38)
  • 【数据结构】排序算法(一)—>插入排序、希尔排序、选择排序、堆排序

    👀 樊梓慕: 个人主页   🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.直接插入排序 2.希尔排序 3.直接选择排序 4.堆排序 本篇文章博主将介绍排序算法中的插入排序:直接

    2024年02月08日
    浏览(39)
  • 【数据结构】常见排序算法——常见排序介绍、选择排序(直接选择排序、堆排序)交换排序(冒泡排序)

      选择排序是一种简单但不高效的排序算法,其基本思想是从待排序的数据中选择最小(或最大)的元素放到已排序的数据末尾。具体操作步骤如下: (1)找到数据中最小的元素,并把它交换到第一个位置; (2)在剩下未排序的元素中找到最小的元素,并把它交换到已排

    2024年02月04日
    浏览(38)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包