合并K个有序链表---附OC实现

合并 k 个排序链表,返回合并后的排序链表。 

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

方式1: 比较笨,不管顺序如何,把所有的链表合成一个链表,然后对这一个链表进行排序,结果就是一个有序的链表了.

方式2:每次都找个这k个链表中的最小值,然后找出的最小值拼接成一个链表即可.

方式3:对第二种方法的优化,采用小顶堆找出最小值,然后在拼接成链表,与第二种相比,相对于方式2可以降低程序的时间复杂度.

方式4:上篇文章我们已经知道了怎么合并2个有序链表,多次调用合并2个有序链表,所有后面的链表都和第一个链表合并,最终的合并结果就在第一个链表上.

方式5:对第4种方式的优化,采用了归并分治的思想优化第4种方式,相邻的2个链表合并,比如:假设有0-5个链表,第一轮0-1合并存放到0, 2-3合并存放到2,4-5合并存放到4;然后第二轮,0-2合并存放到0,4不动;第三轮0-4合并存放到0,此时没有其他链表了,最终结果在0号链表上.


方式2:找个这k个链表中的最小值, 然后最小值的节点后移,如果没有了后续就移除此节点,然后找出的最小值拼接成一个链表即可.

#import <Foundation/Foundation.h>

@interface Node : NSObject

@property (nonatomic,assign) NSInteger data ;
@property (nonatomic,nullable,strong) Node * next ;
+ (instancetype)nodeWithData:(NSInteger)data;
+ (instancetype)nodeWithDataArray:(NSArray<NSNumber *> *)dataArray;

@end


#import "Node.h"

@implementation Node
/// 便利化构造方法,数组转成链表
+ (instancetype)nodeWithDataArray:(NSArray<NSNumber *> *)dataArray{
    
    Node * firstNode = nil;

    Node * preNode = nil;
    for (int i = 0; i<dataArray.count; i++) {
        
        Node * node = [Node nodeWithData:dataArray[i].integerValue];
        preNode.next = node;
        
        if (firstNode == nil) {
            firstNode = node;
        }
        preNode = node;
        
    }
    return firstNode;
}


+ (instancetype)nodeWithData:(NSInteger)data {
    
    Node * n = [[self alloc] init];
    n.data = data;
    return n;
    
}

- (NSString *)description {
    return [NSString stringWithFormat:@"%@ %@" ,@(self.data),self.next];
}

@end

------------------------------------------------------
#import <Foundation/Foundation.h>
#import "Node.h"
 
NSMutableArray * minArray = nil;
/// 找到最小节点
Node * findMinNode() {
    
    Node * minNode =  nil;
    for (int i = 0; i<minArray.count; i++) {
        Node * node = minArray[i];
        if (minNode == nil) {
            minNode = node;
        }
        
        if (minNode.data > node.data) {
            minNode = node;
        }
        
    }

    return minNode;
}
 
 
/// 合并k个有序链表
Node * mergeKLists(NSArray<Node *> *list) {
    
    Node * resutl = nil;
    Node * preNode = nil;
    
    minArray = [list mutableCopy];
    while (minArray.count>0) {
        // 不断找出最小的node,拼接到result后面
        Node * minNode =  findMinNode();
        //使minArray中的元素前移,如果为nil,就移出此元素
        if (minNode.next == nil) {
            [minArray removeObject:minNode];
        } else {
            NSUInteger minIndex = [minArray indexOfObject:minNode];
            minArray[minIndex] = minNode.next;
        }

        if (resutl == nil) {
            resutl = minNode;
        }
        
        preNode.next = minNode;
        preNode = minNode;
    }
    
    NSLog(@"%@",resutl);
    return resutl;
}
 
 
 
int main(){
    
    Node * firstNode = [Node nodeWithDataArray:@[@(1),@(13),@(15),@(23)]];
    Node * secondNode = [Node nodeWithDataArray:@[@(2),@(5),@(8),@(13)]];
    Node * thirdNode = [Node nodeWithDataArray:@[@(4),@(5),@(18),@(23),@(45),]];
    Node * fourNode = [Node nodeWithDataArray:@[@(-3),@(6),@(13),@(19),@(35),]];
 
    mergeKLists(@[firstNode,secondNode,thirdNode,fourNode]);
 
}
 
 

 

iOS虽然没有堆结构,但是怕什么,自己写一个堆结构不就完了 ,
采用最小堆的思想,将K个链表的头节点放入堆中,pop时返回队首元素,并把该队首元素的下一节点放入堆中,直至堆为空。

如何实现堆结构 : https://blog.csdn.net/u014600626/article/details/103752297

#import <Foundation/Foundation.h>
#import "Node.h"


// 实现堆结构,这部分可以各处复用
// 存放数据的数组和数组中的有效数据量
Node * a[51] = {};
int indexNum = 0;
 
// 重新构造小顶堆的方法 : 比较并调整使当前节点的值小于左右叶子
void rebuildHeap() {
    
    // 从第一个有叶子的节点开始
    for (int i = indexNum/2-1; i>=0; i--) {
        int left = 2*i+1;
        int right = 2*i+2;
        
        // 保证 i<左叶子,
        if (a[i].data>a[left].data) {
            Node * temp = a[i];
            a[i] = a[left];
            a[left] = temp;
        }
        // 保证i<右叶子
        if (a[right] && a[i].data>a[right].data) {
            Node * temp = a[i];
            a[i] = a[right];
            a[right] = temp;
        }
        
    }
}
 
// 把数字放入堆中,需要重新构造堆
void push(Node * num) {
    a[indexNum] = num;
    indexNum ++;
    rebuildHeap();
}
// 把堆顶元素弹出,最后一个元素放到初始位置,然后重新构造堆
Node * pop() {
    
    if (indexNum == 0) {
        NSLog(@"已经是空堆了");
        return 0;
    }
    
    Node * result = a[0];
    indexNum--;
    a[0] = a[indexNum];
    rebuildHeap();
    return result;
}


/// 合并k个有序链表
Node * mergeKLists(NSArray<Node *> *list) {
    
    Node * resutl = nil;
    Node * preNode = nil;
    
    /// 构建堆
    for (Node * n in list) {
        push(n);
    }
    
    while (indexNum>0) {
        
        Node * minNode =  pop();
        
        if (minNode.next) {
            push(minNode.next);
        }
        
        if (resutl == nil) {
            resutl = minNode;
        }
        
        preNode.next = minNode;
        preNode = minNode;
    }
    
    NSLog(@"%@",resutl);
    return resutl;
}

int main(){
    
    Node * firstNode = [Node nodeWithDataArray:@[@(1),@(13),@(15),@(23)]];
    Node * secondNode = [Node nodeWithDataArray:@[@(2),@(5),@(8),@(13)]];
    Node * thirdNode = [Node nodeWithDataArray:@[@(4),@(5),@(18),@(23),@(45),]];
    Node * fourNode = [Node nodeWithDataArray:@[@(-3),@(6),@(13),@(19),@(35),]];
    
    mergeKLists(@[firstNode,secondNode,thirdNode,fourNode]);

}
 
 

 


分治法 , 首先实现一个合并2个有序链表的方法,然后把K个链表的合并变成2个链表的合并.直到最后结束

#import <Foundation/Foundation.h>
#import "Node.h"
 

/// 把2个有序链表合成一个有序链表
Node * mergeTwoList(Node * first,Node * second) {
    
    if (second == nil) {
        return first;
    }
    if (first == nil) {
        return second;
    }
    Node * resutl = nil;
    Node * preNode = nil;
    // 找出较小元素,放到result中
    while (first && second) {
        Node * minNode = nil;
        if (first.data > second.data) {
            minNode = second;
            second = second.next;
        } else {
            minNode = first;
            first = first.next;
        }
        
        if (resutl == nil) {
            resutl = minNode;
        }
        preNode.next = minNode;
        preNode = minNode;
        
    }
    
    if (first == nil) {
        preNode.next = second;
    }
    if (second == nil) {
        preNode.next = first;
    }
    
    return resutl;
}
 
/// 合并k个有序链表
Node * mergeKLists(NSArray<Node *> *list) {
    
    NSMutableArray<Node *> * array  = [list mutableCopy];
    while (array.count>1) {
        // 开始元素与最后一个合并,合并结果放到开始的位置
        for (int i = 0; i<array.count;i++) {
            array[i] = mergeTwoList(array[i], array[array.count-1]);
            [array removeLastObject];
        }
    }
    NSLog(@"%@",array.firstObject);
    return array.firstObject;
}
 
 
 
int main(){
    
    Node * firstNode = [Node nodeWithDataArray:@[@(1),@(13),@(15),@(23)]];
    Node * secondNode = [Node nodeWithDataArray:@[@(2),@(5),@(8),@(13)]];
    Node * thirdNode = [Node nodeWithDataArray:@[@(4),@(5),@(18),@(23),@(45),]];
    Node * fourNode = [Node nodeWithDataArray:@[@(-3),@(6),@(13),@(19),@(35),]];
    mergeKLists(@[firstNode,secondNode,thirdNode,fourNode]);
 
}
 


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值