题目
该题来自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=2∑km∗n, 即为O(kn/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);
}
}