链表排序算法

以下原理及实现均为个人理解,如有错误或更优解,欢迎留言指正!

排序算法概述

盗个图

转自:https://www.cnblogs.com/onepixel/articles/7674659.html

排序算法复杂度



由于是链表排序,首先定义链表节点数据结构

common.h

typedef struct Node LNode;

struct Node {
    int data;
    LNode *next;
    LNode *prev;
};
备注:以下排序算法默认由小到大排序

链表排序需要注意保证链表节点直接的连续性

  • 直接插入排序
算法简介

  1. 第一个链表节点,可以认为是已排序好;
  2. 从第二个节点开始进行排序操作,逐一向前遍历,对比节点值大小,遍历至第一个比它的值小的节点,把待排序节点插入到该节点后面;
  3. 依次对后续所有节点重复第2步操作,直至操作到最后一个节点。
算法实现
LNode* insert_sort(LNode *p)
{
    if(NULL == p) return p;

    LNode *tmp = NULL; //指向待排序节点,用于节点插入
    LNode *q = p, *t = q->next;// q指向待排序节点的前一个节点,t指向待排序节点
    while(t)
    {
        if(q->data < t->data)
        {
            tmp = t;
            t = t->next;
            if(t)
            {
                t->prev = q;
            }
            q->next = t;
            while(q && (q->data < tmp->data))
            {
                q = q->prev;
            }
            if(q)
            {
                tmp->next = q->next;
                q->next->prev = tmp;
                q->next = tmp;
                tmp->prev = q;
            }
            else
            {
                tmp->next = p;
                tmp->prev = NULL;
                p->prev = tmp;
                p = tmp;
            }
            if(t)
            {
                q = t->prev;
            }
        }
        else
        {
            t = t->next;
            q = q->next;
        }
    }

    return p;
}


  • 归并排序

算法简介

归并排序采用分治思想,首先使其子序列成为有序序列,然后再对子序列进行归并。

递归实现:

  1. 首先把链表分割为两个子链表(采用快慢指针找到链表中间节点),递归该分割过程,直至子链表只包含一个节点为止;
  2. 创建一个新的链表节点,指向排序好的链表;对分割得到的两个子链表逐一遍历对比,值小的节点插入到新链表后面;
  3. 两个子链表归并完成,且已完成对其排序,返回链表头指针给上层递归。
算法实现
LNode *list_split(LNode *head) //分割链表,返回后一个子链表的头指针
{
    if(NULL == head)
    {
        return head;
    }

    LNode *tmp = head;
    LNode *slow = head, *fast = head; //快慢指针找到原链表的中间节点
    while(fast)
    {
        fast = fast->next;
        if(fast)
        {
            fast = fast->next;
        }

        if(NULL == fast)
        {
            break;
        }
        slow = slow->next;
    }

    tmp = slow;
    slow = slow->next;//中间节点的下一个节点作为第二个子链表的头节点
    tmp->next = NULL; //保证每个子链表尾指针都指向NULL

    return slow;
}
LNode* merge(LNode *head1, LNode *head2)//对两个链表进行归并,合为一个有序链表
{
    if(NULL == head1) return head2;
    if(NULL == head2) return head1;

    LNode head; //定义一个有序链表的头节点
    LNode *tail = &head;

    while(head1 && head2)
    {
        if(head1->data < head2->data) //将小节点插入到有序链表后
        {
            tail->next = head1;
            head1 = head1->next;
        }
        else
        {
            tail->next = head2;
            head2 = head2->next;
        }
        tail = tail->next;
    }

    if(head1) //剩下的节点要保证连接到有序链表后
    {
        tail->next = head1;
    }
    if(head2)
    {
        tail->next = head2;
    }

    return head.next; //返回有序链表的头指针
}
LNode* merge_sort(LNode *head) //归并排序入口函数
{
    if(NULL == head || NULL == head->next) //递归分割链表,直至子链表只包含一个节点为止
    {
        return head;
    }

    LNode *head1 = head; //第一个子链表头指针即链表头指针
    LNode *head2 = list_split(head); //第二个子链表头指针为中间节点的下一个节点

    head1 = merge_sort(head1); //递归第一个子链表
    head2 = merge_sort(head2); //递归第二个子链表
    return merge(head1, head2); //归并,并返回排序后链表的头指针
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值