K个有序链表的归并排序(C语言)

归并算法时间复杂度:O(NlogN)

注意:断链和合并的思想

两个链表的归并:

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

typedef struct listNode{
        int val;
        struct listNode* next;
}ListNode;
 ListNode* mergeNode(ListNode* left, ListNode* right) {

        if(left == NULL) {
                 return right;
        }
        if(right == NULL) {
                return left;
        }
        //如果左边值比右值大,将将右链接到左链后边
        if(left->val < right->val) {
                left->next = mergeNode(left->next, right);
                 return left;
        }else {  如果左边值比右值,将将左链接到右链后边
                right->next = mergeNode(left, right->next);
                return right;
        }
}
ListNode* sortList(ListNode* head){
	   ListNode *fastNode,*slowNode,*breakNode,*left,*right;
        if(head == NULL || head->next == NULL) {
        return head;
        }
        //找中间位置元素进行合并
         fastNode = head;
         slowNode = head;
         breakNode = head;

        //整个思想很有意思,可以保证slowNode始终处在中间的位置,breakNode处于断链的位置
        while(fastNode && fastNode->next) {
                fastNode = fastNode->next->next;
                breakNode = slowNode;
                slowNode = slowNode->next;
        }
        breakNode->next = NULL;
         left = sortList(head);
         right = sortList(slowNode);
        //采用分治法将左右节点排序
         mergeNode(left, right);

}
int main(){
	    int i ;
        ListNode *LN,*p,*LTemp;
        int w[4] ={4,2,1,3};
        LN = (ListNode *)malloc(sizeof(ListNode));
        p = LN;
        p->val = w[0];
        p->next = NULL;
        for(i = 1; i< 4; i++){
                LTemp= (ListNode *)malloc(sizeof(ListNode));
                LTemp->val = w[i];
                LTemp ->next =NULL;
                p->next = LTemp;
                p= LTemp;
        }
        LN=  sortList(LN);
        while(LN){
                printf("%d ",LN->val);
                LN= LN->next;
                
        }
        printf("\n");
        return 0;

}


K个有序链表的归并排序:

//合并多个链表,采用归并的思想,将链表数组对半归并,不产生新链表,直接节点
//先是合并两个链表
struct ListNode* mergeTwoLists(struct ListNode* L1, struct ListNode* L2){
        if(L1 == NULL) {
                 return L2;
        }
        if(L2 == NULL) {
                return L1;
        }
        //如果左边值比右值大,将将右链接到左链后边
        if(L1->val < L2->val) {
                L1->next = mergeTwoLists(L1->next, L2);
                 return L1;
        }else {  如果左边值比右值,将将左链接到右链后边
                L2->next = mergeTwoLists(L1, L2->next);
                return L2;
        }
}

//第二种方式归并
//先是合并两个链表
struct ListNode* mergeTwoLists(struct ListNode* L1, struct ListNode* L2){
        struct ListNode head;
    
        if(!L1) return L2;
        if(!L2) return L1;

        //如何保证头节点不发生改变
        head.next = L1;
        //将L1指向head,这样比较时L1 ->next 就i是原来L1的第一个节点
        L1 = &head;

        //将L2接到L1后边,遍历L2
        while( L2 != NULL){
                //保存L1后边的节点
                struct ListNode *p = NULL;
                struct ListNode *q = NULL;
                
                p = L1->next;
                q = L2 ->next;
                //合并L1和L2
                if(L1->next == NULL){
                      L1 ->next = L2;
                      break;
                }
                if(p->val >= L2->val){
                        L1->next= L2;
                        L2 ->next = p;
                        L2 = q;   
                }
                L1 =L1 ->next;
                
        }
        return head.next;
}


//分开一个链表
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
        struct ListNode *L1, *L2;
        int mid;
        if(listsSize == 0){
            return NULL;
        } else if(listsSize ==1) 
        {
                return lists[0];
        }
        else if(listsSize == 2) {
                return mergeTwoLists(lists[0], lists[1]);
        }   
        mid = (listsSize+1)/2;
        L1 =  mergeKLists(&lists[0],mid);
        L2 =  mergeKLists(&lists[mid],listsSize - mid);
        return mergeTwoLists(L1, L2); 
}

 

转载于:https://my.oschina.net/1024and1314/blog/3094624

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值