鏈表插入排序、鏈表歸併排序

來源:互聯網
上載者:User

鏈表插入排序、鏈表歸併排序
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指向準備插入的結點。    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;}輸出鏈表:  * 輸出鏈表結點值。 */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仍以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.鏈表歸併排序基本思想:如果鏈表為空白或者含有一個結點,鏈表自然有序。否則,將鏈表分成兩部分,對每一部分分別進行歸併排序,然後將已排序的兩個鏈表歸併在一起。歸併排序代碼: /* * 鏈表歸併排序(由小到大)。 * 輸入:鏈表的頭指標, * 輸出:排序後鏈表的頭指標。 * 遞迴實現方法:將鏈表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指標,具體實現方法見注釋。 /* * 鏈表分割函數。 * 將鏈表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;}鏈表歸併函數有遞迴實現和非遞迴實現兩種方法:非遞迴實現: /* * 鏈表歸併。 * 將兩個有序的鏈表歸併在一起,使總鏈表有序。 * 輸入:鏈表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;}遞迴實現: 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;}完整原始碼:* 鏈表歸併排序,由小到大。*/#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 LinkMergeSort(LinkList head);LinkList LinkMerge(LinkList head1, LinkList head2);LinkList LinkMerge2(LinkList head1, LinkList head2);int LinkSplit(LinkList head, LinkList *head1, LinkList *head2);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;} /** 輸出鏈表結點值。*/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 = LinkMergeSort(head);    printf("排序後:\n");    PrintLink(head);    putchar('\n');    return 0;} /* * 鏈表歸併排序(由小到大)。 * 輸入:鏈表的頭指標, * 輸出:排序後鏈表的頭指標。 * 遞迴實現方法:將鏈表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);        //非遞迴實現    //head = LinkMerge2(head1, head2);    //遞迴實現    return head;} /* * 鏈表歸併。 * 將兩個有序的鏈表歸併在一起,使總鏈表有序。 * 輸入:鏈表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;} 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;} /* * 鏈表分割函數。 * 將鏈表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;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.