Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A merge sort of list with O(1) memory overhead #219

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 93 additions & 16 deletions epi_judge_cpp_solutions/sort_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,104 @@

#include "list_node.h"
#include "test_framework/generic_test.h"
#define main _main
#include "sorted_lists_merge.cc"
#undef main

shared_ptr<ListNode<int>> StableSortList(shared_ptr<ListNode<int>> L) {
// Base cases: L is empty or a single node, nothing to do.
if (L == nullptr || L->next == nullptr) {
return L;

typedef shared_ptr<ListNode<int>> IntNode;

static inline void Append(IntNode **tailpp, IntNode node) {
**tailpp = node;
*tailpp = &node->next;
}

static inline void Merge(IntNode *src1p, IntNode *src2p, IntNode **destTailp, size_t len)
{
size_t n1 = 0, n2 = 0;
IntNode src1 = *src1p, src2 = *src2p, *destTail = *destTailp;

while (n1 < len || n2 < len) {
if (n1 == len || src1 == nullptr) {
if (n2 == len || src2 == nullptr) {
break;
}
while (n2++ < len && src2) {
Append(&destTail, src2);
src2 = src2->next;
}
} else {
if (n2 == len || src2 == nullptr) {
while (n1++ < len && src1) {
Append(&destTail, src1);
src1 = src1->next;
}
} else {
if (src1->data <= src2->data) {
++n1;
Append(&destTail, src1);
src1 = src1->next;
} else {
++n2;
Append(&destTail, src2);
src2 = src2->next;
}
}
}
}

// Find the midpoint of L using a slow and a fast pointer.
shared_ptr<ListNode<int>> pre_slow = nullptr, slow = L, fast = L;
while (fast && fast->next) {
pre_slow = slow;
fast = fast->next->next, slow = slow->next;
*src1p = src1;
*src2p = src2;
*destTail = nullptr; // mark the dest list as terminated
*destTailp = destTail;
}

IntNode StableSortList(IntNode L) {
size_t curSrcSize = 1;
size_t total = 0, n;
IntNode head = L;
IntNode src1 = nullptr, src2 = nullptr;
IntNode *srcTail1 = &src1, *srcTail2 = &src2;

// split L into src1 and src2
while (head) {
Append(&srcTail1, head);
head = head->next;
++total;
if (head) {
Append(&srcTail2, head);
head = head->next;
++total;
}
}
*srcTail1 = nullptr;
*srcTail2 = nullptr;

if (pre_slow) {
pre_slow->next = nullptr; // Splits the list into two equal-sized lists.
while (curSrcSize < total) {
IntNode dest1 = nullptr, *destTail1 = &dest1;
IntNode dest2 = nullptr, *destTail2 = &dest2;
size_t iter = 0;

// get sorted items of at most curSrcSize items from src1 & src2
// and put them to dest1 and dest2 alternately
n = 0;
while (n < total) {
Merge(&src1, &src2, &destTail1, curSrcSize);
n += curSrcSize;
if (n < total) {
Merge(&src1, &src2, &destTail2, curSrcSize);
n += curSrcSize;
}
++iter;
}
curSrcSize *= 2;
src1 = dest1;
src2 = dest2;
if (iter == 1) {
break;
}
}
return MergeTwoSortedLists(StableSortList(L), StableSortList(slow));

// now src1 and src2 has one single sorted run, make the final merge
IntNode dest = nullptr, *destTail = &dest;
Merge(&src1, &src2, &destTail, total);
return dest;
}

int main(int argc, char* argv[]) {
Expand Down