[作业]合并K个升序链表

题目

该题来自leetcode
合并K个升序链表

结果

1, 4, 7, 10
3, 89, 111, 120
6, 12, 21, 30, 32
merge result:
1, 3, 4, 6, 7, 10, 12, 21, 30, 32, 89, 111, 120

代码

方案1

不考虑效率的话,最简单方法是一个一个链表合并,前面合并后,再合并后面的,假设各链表长是n, 有k个链表,总遍历数为 2n + (3n) + …+ kn
∑ m = 2 k m ∗ n \displaystyle \sum_{m=2}^{k} m*n m=2kmn, 即为O(k
n/2 + k2n/2-n)

#include <iostream>
#include <string>
#include <sstream>

class EList {
public:
	
	typedef int value_type;
	
	struct ListNode {
		value_type value = 0;
		ListNode* prev = nullptr;
		ListNode* next = nullptr;
	};

	ListNode* first_node = nullptr;
	ListNode* last_node = nullptr;
	std::size_t count;

	EList() = default;

	EList(std::initializer_list<value_type> lst) {
		this->count = lst.size();
		if (lst.size() > 0) {
			auto it = lst.begin();
			this->first_node = new ListNode{ *it, nullptr, nullptr };
			ListNode* cur = this->first_node;
			++it;
			for (; it != lst.end(); ++it) {
				ListNode* next = new ListNode{ *it, cur, nullptr };
				cur->next = next;
				cur = next;
			}
			last_node = cur;
		}
	}

	~EList() {
		ListNode* cur = first_node;
		while (cur) {
			ListNode* temp = cur;
			cur = cur->next;
			delete temp;
		}
		first_node = nullptr;
		count = 0;
	}

	void append(EList* other) {
		ListNode* ocur = other->first_node;
		ListNode* cur = this->first_node;
		while (ocur) {
			while (cur) {
				if (cur->value > ocur->value) {
					break;
				}
				cur = cur->next;
			}
			if (cur) {
				ListNode* n = new ListNode{ ocur->value, cur->prev, cur };
				if (cur->prev) 
					cur->prev->next = n;
				else 
					first_node = n;
				cur->prev = n;
			}
			else {
				ListNode* n = new ListNode{ ocur->value, last_node, nullptr };
				if (!first_node) {
					first_node = n;
				}
				if (last_node)
					last_node->next = n;
				last_node = n;
				cur = n;
			}
			ocur = ocur->next;
		}
		count += other->count;
	}

	std::string to_string() const {
		std::stringstream strstr;
		ListNode* cur = this->first_node;
		while (cur != last_node) {
			strstr << cur->value << ", ";
			cur = cur->next;
		}
		if (last_node)
			strstr << last_node->value;

		return strstr.str();
	}
	
	void append2(std::vector<EList> lsts) {
		// 方案1调用的方法
		for (auto it = lsts.begin(); it != lsts.end(); ++it) {
			this->append(&(*it));
		}
	}

};

方案2

咱们可以先两两小的合并,再把合并成大的,假每个链的长度都是n, 算法规模是O(logk * kn)

void append1(std::vector<EList>& lsts) {
	if (lsts.size() == 0)
		return;
	if (lsts.size() == 1) {
		this->append(&lsts[0]);
		return;
	}
	std::size_t count = lsts.size();
	auto it = lsts.begin();
	while ( it != lsts.end()) {
		auto next_it = it + 1;
		if (next_it == lsts.end())
			break;
		it->append(&(*next_it));
		it = lsts.erase(next_it);
	}
	this->append1(lsts);
}

对比

方案2 比方案1 快了近一倍,各跑一千次,其时间对比如下

“lst.append1” 67
“lst.append2” 162

对比代码

void test_append_k_list() {
	EList lst1 = { 1, 4, 7, 10 };
	EList lst2 = { 3, 89, 111, 120 };
	EList lst3 = { 6, 12, 21, 30, 32 };

	const int test_count = 1000;
	{
		EList lst;
		std::vector<EList> tl = { lst1, lst2, lst3 };
		TEST_FUN(lst.append1, test_count, tl);
	}

	{
		EList lst;
		std::vector<EList> tl = { lst1, lst2, lst3 };
		TEST_FUN(lst.append2, test_count, tl);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值