【转】链表归并排序插入排序

链表插入排序、链表归并排序

1.链表

1.1链表的存储表示


1

2

3

4

5

6

7

//链表的存储表示

typedef int ElemType;

typedef struct LNode

{

    ElemType data;

    struct LNode *next;

}LNode, *LinkList;

1.2基本操作

创建链表:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

/*

 * 创建链表。

 * 形参num为链表的长度,函数返回链表的头指针。

 */

LinkList CreatLink(int num)

{

    int i, data;

    //p指向当前链表中最后一个结点,q指向准备插入的结点。

    LinkList head = NULL, p = NULL, q;

    for (i = 0; i < num; i++)

    {

        scanf("%d", &data);

        q = (LinkList)malloc(sizeof(LNode));

        q->data = data;

        q->next = NULL;

        if (i == 0)

        {

            head = q;

        }

        else

        {

            p->next = q;

        }

        p = q;

    }

    return head;

}

输出链表:


1

2

3

4

5

6

7

8

9

10

11

12

/*

 * 输出链表结点值。

 */

int PrintLink(LinkList head)

{

    LinkList p;

    for (p = head; p ;p = p->next)

    {

        printf("%-3d ", p->data);

    }

    return 0;

}

2.链表插入排序

基本思想:假设前面n-1个结点有序,将第n个结点插入到前面结点的适当位置,使这n个结点有序。

实现方法:

将链表上第一个结点拆下来,成为含有一个结点的链表(head1),其余的结点自然成为另外一个链表(head2),此时head1为含有一个结点的有序链表;

将链表head2上第一个结点拆下来,插入到链表head1的适当位置,使head1仍有序,此时head1成为含有两个结点的有序链表;

依次从链表head2上拆下一个结点,插入到链表head1中,直到链表head2为空链表为止。最后,链表head1上含所有结点,且结点有序。

插入排序代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

/*

 * 链表插入排序(由小到大)。

 * 输入:链表的头指针,

 * 输出:排序后链表的头指针。

 * 实现方法:将原链表拆成两部分:链表1仍以head为头指针,链表结点有序。链表2以head2为头指针,链表结点无序。

 * 将链表2中的结点依次插入到链表1中,并保持链表1有序。

 * 最后链表1中包含所有结点,且有序。

 */

LinkList LinkInsertSort(LinkList head)

{

    //current指向当前待插入的结点。

    LinkList head2, current, p, q;

    if (head == NULL)

        return head;

    //第一次拆分。

    head2 = head->next;

    head->next = NULL;

    while (head2)

    {

        current = head2;

        head2 = head2->next;

        //寻找插入位置,插入位置为结点p和q中间。

        for (p = NULL, q = head; q && q->data <= current->data; p = q, q = q->next);

        if (q == head)

        {

            //将current插入最前面。

            head = current;

        }

        else

        {

            p->next = current;

        }

        current->next = q;

    }

    return head;

}

完整源代码:

/*
 * 链表插入排序,由小到大
 */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define TOTAL 10        //链表长度

//链表的存储表示
typedef int ElemType;
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode, *LinkList;

LinkList CreatLink(int num);
LinkList LinkInsertSort(LinkList head);
int PrintLink(LinkList head);

/*
 * 创建链表。
 * 形参num为链表的长度,函数返回链表的头指针。
 */
LinkList CreatLink(int num)
{
    int i, data;

    //p指向当前链表中最后一个结点,q指向准备插入的结点。
    LinkList head = NULL, p = NULL, q;

    for (i = 0; i < num; i++)
    {
        scanf("%d", &data);
        q = (LinkList)malloc(sizeof(LNode));
        q->data = data;
        q->next = NULL;
        if (i == 0)
        {
            head = q;
        }
        else
        {
            p->next = q;
        }
        p = q;
    }
    return head;
}

/*
 * 链表插入排序(由小到大)。
 * 输入:链表的头指针,
 * 输出:排序后链表的头指针。
 * 实现方法:将原链表拆成两部分:链表1仍以head为头指针,链表结点有序。链表2以head2为头指针,链表结点无序。
 * 将链表2中的结点依次插入到链表1中,并保持链表1有序。
 * 最后链表1中包含所有结点,且有序。
 */
LinkList LinkInsertSort(LinkList head)
{
    //current指向当前待插入的结点。
    LinkList head2, current, p, q;

    if (head == NULL)
        return head;

    //第一次拆分。
    head2 = head->next;
    head->next = NULL;

    while (head2)
    {
        current = head2;
        head2 = head2->next;

        //寻找插入位置,插入位置为结点p和q中间。
        for (p = NULL, q = head; q && q->data <= current->data; p = q, q = q->next);

        if (q == head)
        {
            //将current插入最前面。
            head = current;
        }
        else
        {
            p->next = current;
        }
        current->next = q;
    }
    return head;
}

/*
 * 输出链表结点值。
 */
int PrintLink(LinkList head)
{
    LinkList p;
    for (p = head; p ;p = p->next)
    {
        printf("%-3d ", p->data);
    }
    return 0;
}

int main()
{
    LinkList head;

    printf("输入Total个数以创建链表:\n");
    head = CreatLink(TOTAL);

    head = LinkInsertSort(head);
    printf("排序后:\n");
    PrintLink(head);
    putchar(‘\n‘);
    return 0;
}

3.链表归并排序

基本思想:如果链表为空或者含有一个结点,链表自然有序。否则,将链表分成两部分,对每一部分分别进行归并排序,然后将已排序的两个链表归并在一起。

归并排序代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/*

 * 链表归并排序(由小到大)。

 * 输入:链表的头指针,

 * 输出:排序后链表的头指针。

 * 递归实现方法:将链表head分为两部分,分别进行归并排序,再将排序后的两部分归并在一起。

 * 递归结束条件:进行递归排序的链表为空或者只有一个结点。

 */

LinkList LinkMergeSort(LinkList head)

{

    LinkList head1, head2;

    if (head == NULL || head->next == NULL)

        return head;

    LinkSplit(head, &head1, &head2);

    head1 = LinkMergeSort(head1);

    head2 = LinkMergeSort(head2);

    head = LinkMerge(head1, head2);

    return head;

}

其中链表分割函数如下,基本思想是利用slow/fast指针,具体实现方法见注释。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

/*

 * 链表分割函数。

 * 将链表head均分为两部分head1和head2,若链表长度为奇数,多出的结点从属于第一部分。

 * 实现方法:首先使指针slow/fast指向链首,

 * 然后使fast指针向前移动两个结点的同时,slow指针向前移动一个结点,

 * 循环移动,直至fast指针指向链尾。结束时,slow指向链表head1的链尾。

 */

int LinkSplit(LinkList head, LinkList *head1, LinkList *head2)

{

    LinkList slow, fast;

    if (head == NULL || head->next == NULL)

    {

        *head1 = head;

        *head2 = NULL;

        return 0;

    }

    slow = head;

    fast = head->next;

    while (fast)

    {

        fast = fast->next;

        if (fast)

        {

            fast = fast->next;

            slow = slow->next;

        }

    }

    *head1 = head;

    *head2 = slow->next;

    //注意:一定要将链表head1的链尾置空。

    slow->next = NULL;

    return 0;

}

链表归并函数有递归实现和非递归实现两种方法:

非递归实现:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

/*

 * 链表归并。

 * 将两个有序的链表归并在一起,使总链表有序。

 * 输入:链表head1和链表head2

 * 输出:归并后的链表

 * 实现方法:将链表head2中的结点依次插入到链表head1中的适当位置,使head1仍为有序链表。

 */

LinkList LinkMerge(LinkList head1, LinkList head2)

{

    LinkList p, q, t;

    if (!head1)

        return head2;

    if (!head2)

        return head1;

    //循环变量的初始化,q指向链表head1中的当前结点,p为q的前驱。

    p = NULL;

    q = head1;

    while (head2)

    {

        //t为待插入结点。

        t = head2;

        head2 = head2->next;

        //寻找插入位置,插入位置为p和q之间。

        for (;q && q->data <= t->data; p = q, q = q->next);

        if (p == NULL)

            head1 = t;

        else

            p->next = t;

        t->next = q;

        //将结点t插入到p和q之间后,使p重新指向q的前驱。

        p = t;

    }

    return head1;

}

递归实现:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

LinkList LinkMerge2(LinkList head1, LinkList head2)

{

    LinkList result;

    if (!head1)

        return head2;

    if (!head2)

        return head1;

    if (head1->data <= head2->data)

    {

        result = head1;

        result->next = LinkMerge(head1->next, head2);

    }

    else

    {

        result = head2;

        result->next = LinkMerge(head1, head2->next);

    }

    return result;

}

时间: 2024-09-30 06:54:38

【转】链表归并排序插入排序的相关文章

链表插入排序、链表归并排序

1.链表 1.1链表的存储表示 //链表的存储表示 typedef int ElemType; typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList; 1.2基本操作 创建链表: /* * 创建链表. * 形参num为链表的长度,函数返回链表的头指针. */ LinkList CreatLink(int num) { int i, data; //p指向当前链表中最后一个结点,q指向准备插入的结点.

leetcode——Insertion Sort List 对链表进行插入排序(AC)

Sort a linked list using insertion sort. class Solution { public: ListNode *insertionSortList(ListNode *head) { if(head == NULL || head->next == NULL) return head; ListNode *result; result->val = INT_MIN; result->next = NULL; ListNode *cur=head,*

c版基于链表的插入排序(改进版)

1. [代码][C/C++]代码 /** * @todo    c版基于链表的插入排序 * @author  Koma **/#include<stdio.h>#include<stdlib.h> typedef struct node{    int data;    struct node *next;}LNode, *LinkList; /** * 创建并初始化一个带头节点的链表 **/LinkList init() {    LinkList p, r, list;   

Leetcode:Sort List 对单链表归并排序

Sort a linked list in O(n log n) time using constant space complexity. 看到O(n log n)的排序算法,适合单链表的首先想到的就是归并排序 /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ cla

insertion Sort List (链表的插入排序) leecode java

逻辑简单,代码难写,基础不劳,leecode写注释不能出现中文,太麻烦,我写了大量注释,链表问题最重要的就是你那个指针式干啥的 提交地址https://oj.leetcode.com/problems/insertion-sort-list/ /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; *

【算法题 14 LeetCode 147 链表的插入排序】

算法题 14 LeetCode 147 链表的插入排序: 解题代码: # Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def insertionSortList(self, head): """ :type head: ListNode

147. 对链表进行插入排序

题目描述 对链表进行插入排序. 插入排序的动画演示如上.从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中. 插入排序算法: 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入. 重复直到所有输入数据插入完为止. 示例 1: 输入: 4->2->1->3 输出: 1-&g

[Leetcode]148. 排序链表(归并排序)

题目 在?O(n?log?n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: 输入: -1->5->3->4->0 输出: -1->0->3->4->5 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/sort-list 著作权归领扣网络所有.商业转载请联系官方授权,非商业转载请注

c++链表归并排序的迭代版本

之前用js写了个归并排序非递归版,而这一次,c++封装链表的时候也遇到了一个归并排序的接口.邓老师实现了递归版本的归并排序,但是递归的调用函数栈的累积是很占内存空间的.于是乎,那试试在链表结构上实现以下归并排序吧.但是一旦开始,就遇到难题了,在链表下,我们无法按索引访问,所以,在迭代过程中,左右序列就无法很好的用o(1)时间就解决.先看看我实现的代码吧,初步测试没问题,如果有什么问题,希望大神指出,不知为何,用c++写东西总觉得哪里有问题,即使程序可以运行. template<typename