合并 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]);
}