A Scapegoat Tree That Just Won't Balance - algorithm

So, I'm working on this project for Comp 272, Data Structures and Algorithms, and before anyone asks I have no one to help me. It's an online program through Athabasca University and for some unknown reason they didn't supply me with a tutor for this course, which is a first... So... Yeah. The question is as follows:
"(20 marks) Exercise 8.2. Illustrate what happens when the sequence 1, 5, 2, 4, 3 is added to an empty ScapegoatTree, and show where the credits described in the proof of Lemma 8.3 go, and how they are used during this sequence of additions."
This is my code, its complete and it compiles:
/*
Name: Westcott.
Assignment: 2, Question 3.
Date: 08-26-2022.
"(20 marks) Exercise 8.2. Illustrate what happens when the sequence 1, 5, 2, 4, 3 is added to an empty
ScapegoatTree, and show where the credits described in the proof of Lemma 8.3 go, and how they are used
during this sequence of additions."
*/
#include <iostream>
using namespace std;
class Node { // Originally I did this with Node as a subclass of sgTree but I found that this
public: // way was easier. This is actually my second attempt, from scratch, at doing this
int data; // problem. First version developed so many bugs I couldn't keep up with them.
Node* left;
Node* right;
Node* parent;
Node() : data(0), parent(NULL), left(NULL), right(NULL) {};
Node(int x) : data(x), parent(NULL), left(NULL), right(NULL) {};
~Node() {}; // Normally I would do a little more work on clean up but... Yea this problem didn't leave me much room.
Node* binarySearch(Node* root, int x); // The Node class only holds binarySearch in addition to its
// constructors/destructor, and of course the Node*'s left, right and parent.
};
class sgTree { // The sgTree keeps track of the root, n (the number of nodes in the tree), and q which is
public: // as Pat put it a 'high water mark'.
Node* root;
int n;
int q;
sgTree() : root(new Node()), n(1), q(1) {}
sgTree(int x) : root(new Node(x)), n(0), q(0) {}
~sgTree() {
delete root;
}
bool add(int x); // The add function is compounded, within it are findDepth and rebuild.
bool removeX(int x); // removeX works, but it didn't have a big part to play in this question,
int findDepth(Node* addedNode); // but I'll include it to maintain our sorted set interface.
void printTree(Node* u, int space) { // This was extra function I wrote to help me problem solve.
cout << "BINARY TREE DISPLAY" << endl; // this version only prints a title and then it calls printTreeSub on line 46.
cout << "________________________________________________\n\n" << endl;
printTreeSub(u, space);
cout << "________________________________________________\n\n" << endl;
}
int printTreeSub(Node* u, int space); // Function definition for this is on line 81.
int storeInArray(Node* ptr, Node* arr[], int i);// this is our function for storing all the elements of a tree in an array.
int size(Node* u); // this is size, defined on line 74.
void rebuild(Node* u); // And rebuild and buildBalanced are the stars of the show, defined on lines 262 and 282
Node* buildBalanced(Node** a, int i, int ns); // just above the main() funciton.
};
int log32(int q) { // As you can see there's two versions of this function.
int c = 0; // this is supposed to return the log of n to base 3/2.
while (q != 0) { // The version below I got from this website:
q = q / 2; // https://www.geeksforgeeks.org/scapegoat-tree-set-1-introduction-insertion/
c++; // It works fine but I prefer the one I wrote.
} // this is a much simpler function. It just divides q until its zero
return c; // and increments c on each division. Its not exact but it is based on what Pat said
} // in this lecture: https://www.youtube.com/watch?v=OGNUoDPVRCc&t=4852s
/*
static int const log32(int n)
{
double const log23 = 2.4663034623764317;
return (int)ceil(log23 * log(n));
}
*/
int sgTree::size(Node* u) {
if (u == NULL) {
return 0;
}
return 1 + size(u->left) + size(u->right); // Recursion in size();
}
int sgTree::printTreeSub(Node* u, int space) { // Here is my strange print function
if (u == NULL) return space; // I say strange because I'm not even 100% sure
space--; // how I got it to work. The order itself I worked out, but I built it
space -= printTreeSub(u->left, space); // and, originally, got a half decent tree, but then I just kept playing
if (u->right == NULL && u->left == NULL) { // around with increments, decrements, and returned values
cout << "\n\n\n" << u->data << "\n\n\n" << endl; // of space until it just sort of came together.
return 1; // Basically it prints the left most Node first and then prints every node
} // beneath that using recursion. I realized that by setting the for loop
for (int i = space; i >= 0; i--) { // on line 89 I could imitate different nodes having different heights in
cout << " "; // the tree. I figured that using n as an input I could take advantage of
} // the recursion to get an accurate tree. That much I understand.
cout << " " << u->data << "'s children are: "; // But it didn't work out quite how I wanted it to so I just kept playing
if (u->left != NULL) { // with space increments and decrements on different sides of the tree until
cout << u->left->data; // I got something pretty good.
}
else {
cout << "NULL";
}
if (u->right != NULL) {
cout << " and " << u->right->data;
}
else {
cout << " NULL";
}
cout << "\n\n" << endl;
space--;
space -= printTreeSub(u->right, space);
return 1;
}
int sgTree::storeInArray(Node* ptr, Node* a[], int i) { // This function took me a while to figure out.
if (ptr == NULL) { // The recursive insertions of values using i, when
return i; // i is defined by the very same recursion, makes this
} // a bit of a challenge to get your head around.
i = storeInArray(ptr->left, a, i); // Basically its just taking advantage on an inOrder
a[i] = ptr; // transversal to get the values stored into the array
i++; // in order from least to greatest.
return storeInArray(ptr->right, a, i);
}
Node* Node::binarySearch(Node* root, int x) { // I covered this in another question.
if (root->data == x) {
return root;
}
else if (x < root->data) {
if (root->left == NULL) {
return root;
}
return binarySearch(root->left, x);
}
else if (x > root->data) {
if (root->right == NULL) {
return root;
}
return binarySearch(root->right, x);
}
}
bool sgTree::add(int x) { // The add function itself isn't too difficult.
Node* addedNode = new Node(x); // We make a Node using our data, then we search for that Node
Node* parent = root->binarySearch(root, x); // in the tree. I amended binarySearch to return the parent
addedNode->parent = parent; // if it hits a NULL child, on lines 127 and 133.
if (x < parent->data) { // That way the new Node can just go into the returned parents child
parent->left = addedNode; // here is where we choose whether it enters the left or the right.
}
else if (x > parent->data) {
parent->right = addedNode;
}
int h = findDepth(addedNode); // We run findDepth() on the addedNode. I realize that this probably should
// have been a part of the binarySearch, it means we go down
if (h > log32(q)) { // the tree twice instead of once. I did look at changing binarySearch into searchAndDepth
// having binarySearch return an int for the height isn't a problem, but then that would
// mess up removeX and, I don't know. What's more important?
Node* w = addedNode->parent; // If this were going to be a database hosting millions of pieces of data I would give
while (3 * size(w) < 2 * size(w->parent)) { // that alot more consideration but, this is just an exercise after all so...
w = w->parent; // From there, we compare our height to the value output by log32(q) on line 152.
}
rebuild(w); // This expression 3 * size(w) < 2 * size(w->parent) is the formula on page 178 rewritten
//rebuild(root); // as a cross multiplication, clever. It keeps going up the tree until we find the scapegoat w.
// This is a much nicer result.
//See line 311.
} // Now, this is where my problems began. Pat says that this line should read: rebuild(w->parent);
n++; // but when I do that I get an error when w is the root. Because then w->parent is NULL. And in that case
q++; // line 258 throws an error because we're trying to set p equal to NULL's parent. It's not there.
return true; // So my work around was to just offset this by one and send rebuild(w). But that doesn't seem
} // to balance the tree just right. In fact, the best tree results when we replace w with root.
// and just rebalance the whole tree. But in any case, we increment n and q and lets pick this up on line 256.
int sgTree::findDepth(Node* addedNode) {
int d = 0;
while (addedNode != root) {
addedNode = addedNode->parent;
d++;
}
return d;
}
bool sgTree::removeX(int x) {
Node* u = root->binarySearch(root, x);
if (u->left == NULL && u->right == NULL) {
if (u == u->parent->left) {
u->parent->left = NULL;
}
if (u == u->parent->right) {
u->parent->right = NULL;
}
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
if (u->left != NULL && u->right == NULL) {
if (u->parent->left = u) {
u->parent->left = u->left;
}
else if (u->parent->right = u) {
u->parent->right = u->left;
}
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
if (u->left == NULL && u->right != NULL) {
if (u == u->parent->left) {
u->parent->left = u->right;
u->right->parent = u->parent;
}
else if (u == u->parent->right) {
u->parent->right = u->right;
u->right->parent = u->parent;
}
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
if (u->left != NULL && u->right != NULL) {
Node* X = u->right;
if (X->left == NULL) {
X->left = u->left;
if (u->parent != NULL) {
if (u->parent->right == u) {
u->parent->right == X;
}
else if (u->parent->left == u) {
u->parent->left = X;
}
}
else {
root = X;
}
X->parent = u->parent;
cout << u->data << " deleted" << endl;
n--;
delete u;
return true;
}
while (X->left != NULL) {
X = X->left;
}
X->parent->left = NULL;
X->left = u->left;
X->right = u->right;
if (u->parent != NULL) {
X->parent = u->parent;
}
cout << u->data << " deleted" << endl;
n--;
root = X;
delete u;
return true;
}
}
void sgTree::rebuild(Node* u) {
int ns = size(u); // Everything is pretty kosher here. Just get the number of nodes in the subtree.
Node* p = u->parent; // Originally I had n here instead of ns and... I don't want to talk about how long it took me to find that mistake...
/* It's funny because while writing the comments for this I'm like "Oh, hang on, if I just push the definition of p behind the if statement on line 262
and evaluate for whether or not u is NULL instead of p, that should solve all my problems! Yea, no, it doesn't. Because then for some reason it tries rebalancing
empty tree and... Yea I just have to stop myself from trying to fix this because everytime I do I get caught in an infinite loop of me chasing my tail in errors.
I think a solution could be found in buildBalanced, and I literally went through that function line by line, trying to comprehend a work around. I've included at
a photograph of that white board. Yea this is the code that Pat gave us... and its garbage. It doesn't work. Maybe its a C++ thing, I don't know... But I'm
getting frustrated again so I'm going to stop thinking about this part RIGHT HERE, and move on LOL*/
Node** a = new Node * [ns]; // a Node pointer-pointer array... again, another fine piece of code from the textbook. Sorry, trying to stay positive here.
storeInArray(u, a, 0); // See Line 112
if (p == NULL) { // Okay, once we have our array we use buildBalanced to rebuild the subtree with respect to which
root = buildBalanced(a, 0, ns); // child u is relative to its parent.
root->parent = NULL; // See line 281 for buildBalanced().
}
else if (p->right == u) {
p->right = buildBalanced(a, 0, ns);
p->right->parent = p;
}
else {
p->left = buildBalanced(a, 0, ns);
p->left->parent = p;
}
}
Node* sgTree::buildBalanced(Node** a, int i, int ns) { // This is without a doubt one of the hardest functions I've ever had
if (ns == 0) { // the displeasure of trying to understand... Trying to stay positive.
return NULL; // I've gone through it, in a line by line implementation of the array:
} // a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} you can find that analysis in
int m = ns / 2; // the photo buildBalanced_Analysis.
a[i + m]->left = buildBalanced(a, i, m); // As confusing as it is, I have to admit that it is a beautiful function.
if (a[i + m]->left != NULL) { // It basically uses the two integers i and m to simultaneously
a[i + m]->left->parent = a[i + m]; // regulate the organization of the new tree and to specifically
} // grab the right value from the array when its needed.
a[i + m]->right = buildBalanced(a, i + m + 1, ns - m - 1); // but trying to map this out didn't help me to solve the issues I've been having.
if (a[i + m]->right != NULL) {
a[i + m]->right->parent = a[i + m];
}
return a[i + m];
}
int main() {
sgTree newTree(1);
int a[] = { 5, 2, 4, 3 };
for (int i = 0; i < (sizeof(a) / sizeof(a[0])); i++) {
newTree.add(a[i]);
}
newTree.printTree(newTree.root, newTree.n);
/*
This is a nice test, when paired with rebuild(root), that too me is the only thing that approaches redeeming this whole question.
sgTree newTreeB(1);
int b[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int i = 0; i < (sizeof(b) / sizeof(b[0])); i++) {
newTreeB.add(b[i]);
}
newTreeB.printTree(newTreeB.root, newTreeB.n);
*/
}
Now the issue itself is not that hard to understand. My tree should look like this:
But instead, it looks like this, with 5 at the root and the values 1 and 4 as the leaves:
I'm confident that the problem lives somewhere around line 159 and in those first few calls to buildBalanced. The comments in the code itself elaborate more on the issue. I've spent days just pouring over this trying everything I can think of to make it work and... Yeah... I just can't figure it out.

Related

std::map not behaving properly as std:unordered_map

I am trying to solve this problem : https://leetcode.com/problems/3sum/
My idea: is to use 2 hash table (map): one for negative values & zeros , one for positive values.
a+b+c=0 --> a+b = -C
So iterate over the negative values , check for each positive value if the negative value exists -> then we have a 3sum.
The problem that I get is :
I am iterating over a map which has the frequency of occurrences of numbers inside a vector (in the function threeSum ) &
I decrement a number's frequency (number = -1 ) to 0:
Then I call a function which is supposed to check if the number is there or not;
But it's frequency is still 1 !!
If I use unordered_map , it works !
// vector::push_back
#include <iostream>
#include <vector>
#include <map>
using namespace std;
struct CountStruct{
int element1,element2;
int count1,count2;
};
void keepOriginalCount (map<int,int> &positive_sign, map<int,int> &negative_and_zero_sign, const CountStruct & originalCount)
{
if (originalCount.element1<0)
{
negative_and_zero_sign[originalCount.element1]=originalCount.count1;
}
else if (originalCount.element1>0)
{
positive_sign[originalCount.element1]=originalCount.count1;
}
if (originalCount.element2<0)
{
negative_and_zero_sign[originalCount.element2]=originalCount.count2;
}
else if (originalCount.element2>0)
{
positive_sign[originalCount.element2]=originalCount.count2;
}
}
bool findElement (map<int,int> &positive_sign, map<int,int> &negative_and_zero_sign, const int element ,const bool & hasZero)
{
cout<<"findElement: element="<<element<<endl;
if (element<0)
{
if(negative_and_zero_sign[element]>0)
{
cout<<"findElement: negative_and_zero_sign[element]="<<negative_and_zero_sign[element]<<endl;
return true;
}
else
{
return false;
}
}
else if (element>0)
{
if(positive_sign[element]>0)
{
return true;
}
else
{
return false;
}
}
else
{
if( hasZero == true)
{
return true;
}
else
{
return false;
}
}
}
void fillMaps (map<int,int> &positive_sign, map<int,int> &negative_and_zero_sign,vector<int>& nums , bool & hasZero , int &zeroCount)
{
for ( unsigned int i =0 ; i< nums.size();i++)
{
if(nums[i]<0)
{
cout<<"nums[i]"<<nums[i]<<endl;
negative_and_zero_sign[nums[i]]++;
}else if(nums[i]>0){
cout<<"nums[i]"<<nums[i]<<endl;
positive_sign[nums[i]]++;
}
else
{
cout<<"nums[i]"<<nums[i]<<endl;
hasZero=true;
zeroCount++;
}
}
}
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
map<int,int> positive_sign;
map<int,int> negative_and_zero_sign;
bool hasZero = false;
int zeroCount=0;
fillMaps(positive_sign,negative_and_zero_sign,nums,hasZero,zeroCount);
for(auto& itNegative : negative_and_zero_sign) {
if (itNegative.second <=0)
continue;
CountStruct originalCount;
originalCount.element1 = itNegative.first;
originalCount.count1 = itNegative.second;
cout<<"---------originalCount.element1 "<<originalCount.element1 <<endl;
cout<<"---******itNegative.first "<<itNegative.first <<endl;
cout<<"Before---******itNegative.second "<<itNegative.second <<endl;
itNegative.second--;
cout<<"After---******itNegative.second "<<itNegative.second <<endl;
cout<<"-----------------------------------------------------"<<endl;
for(auto& itPositive : positive_sign) {
if (itPositive.second <=0)
continue;
originalCount.element2 = itPositive.first;
originalCount.count2 = itPositive.second;
cout<<"+++******itPositive.first "<<itPositive.first <<endl;
cout<<"+++******itPositive.second "<<itPositive.second <<endl;
itPositive.second = itPositive.second - 1;
cout<<"+++******After : itPositive.second "<<itPositive.second <<endl;
// cout<<"--------originalCount.element2 "<<originalCount.element2 <<endl;
if (findElement (positive_sign,negative_and_zero_sign,(originalCount.element1+originalCount.element2)*-1,hasZero))
{
cout<<"Yahoo , element found"<<endl;
vector <int> temp;
temp.push_back(originalCount.element1);
temp.push_back(originalCount.element2);
temp.push_back( (originalCount.element1+originalCount.element2)*-1);
result.push_back(temp);
}
keepOriginalCount(positive_sign,negative_and_zero_sign, originalCount);
}
}
if(zeroCount >=3)
{
vector <int> temp;
temp.push_back(0);
temp.push_back(0);
temp.push_back(0);
result.push_back(temp);
}
return result ;
}
int main ()
{
vector<int> testV = {1,2,-2,-1};
auto x = threeSum(testV);
return 0;
}
output : [[-1,2,-1]] !! Should be null
Works with unordered_map
Your problem is not caused by unordered_map vs map. It's just a random coincidence with your current testvector and the (in principle) random order an unordered_map is traversed.
The real problem in your algorithm is, that you are restoring the original count for ALL values in the inner loop of your threeSum method.
Consider the following situation:
itNegative is currently pointing at the element -1 which has a frequency of 1.
you keep that frequency of 1 in originalElement.count1 and decrement the itNegative.second--, ie the frequency is 0
now the inner loop starts to run
itPositive points (for instance) to the element 1 which has a frequency of 1
you keep that frequency of 1 in originalElement.count2 and decrement the itPositive.second--, ie the frequency is 0
you search for 0 in both maps, but don't find anything
now you call keepOriginalCount which resets ALL frequencies to their original value (ie for both -1 and 1)
in the next iteration of the inner loop itPositive points to 2, itNegative still points to -1.
you now search for -1 ((2 + -1) * -1) and you find it, because keepOriginalCount from the prior step reset the frequency of -1 to 1.
The solution is, not to use keepOriginalCount in the inner loop, but just resetting the frequency of the element itPositive is currently pointing at. Reset the frequency of itNegative only after the inner loop is finished and you are advancing to the next element in the outer loop. You could even skip resetting the frequency of itNegative at all, because you already checked all possible combinations, where it could be part of a solution.
for(auto& itNegative : negative_and_zero_sign) {
if (itNegative.second <=0)
continue;
CountStruct originalCount;
originalCount.element1 = itNegative.first;
originalCount.count1 = itNegative.second;
itNegative.second--; //decrement the frequency of element1
for(auto& itPositive : positive_sign) {
if (itPositive.second <=0)
continue;
originalCount.element2 = itPositive.first;
originalCount.count2 = itPositive.second;
itPositive.second--; //decrement the frequency of element2
if (findElement (positive_sign,negative_and_zero_sign,(originalCount.element1+originalCount.element2) * -1,hasZero))
{
cout<<"Yahoo , element found " << originalCount.element1 << " "<< originalCount.element2 << endl;
vector <int> temp;
temp.push_back(originalCount.element1);
temp.push_back(originalCount.element2);
temp.push_back( (originalCount.element1+originalCount.element2) * -1);
result.push_back(temp);
}
itPositive.second++; //reset only the frequency of element2
}
itNegative.second++; //reset only the frequency of element1
}

Why am I keep getting WA for this solution for UVa 10511

I am trying to solve this problem, I think I have come up with a correct answer, but I am keep getting WA (wrong answer) response from the judge.
http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452
The problem distilled, is, given a 1 - * relationship between party and person, 1 - * relationship between person and club. Find a 1 - 1 relationship between person and club such that for all person related to a club, the number of persons belong to a any party is less than half of the number of club.
For example, let say we have
Person1 belongs to Party1 and Club1, Club2
Person2 belongs to Party2 and Club2, Club3
Person3 Belongs to Party3 and Club3, Club1
There are two assignments possible.
Person1 Club1
Person2 Club2
Person3 Club3
and
Person1 Club2
Person2 Club3
Person3 Club1
My idea is to model this problem as a maximum flow problem as follow:
For simplicity, let say there are two parties, four persons, and three clubs.
0 is the master source
1, 2 are the nodes representing the two parties
3, 4, 5, 6 are the nodes representing the four persons
7, 8, 9 are the nodes representing the three clubs.
10 is the master sink
master source connects to each party with capacity = (3 + 1)/2 - 1 = 1. That represents there can only be at most 1 person of 1 party representing in the council (or otherwise 2 will be equals to or more than half)
for each party person pair, have a link of capacity 1. That represents each person have only 1 party and used one seat in the previously allocated number.
for each person club pair, have a link of capacity 1. That represents each person can represent one club only.
Last but not least, all clubs goes to sink with capacity 1.
If the graph above has a maximum flow equals to the number of clubs - then there exist an assignment.
I can prove the design is correct as follow:
=>
If there exist a maximum flow of the size, each club node must be sending flow of value 1, implies each club node has exactly one person representing it. The representation respect the constraint of party participation as it has at most that many person in a party representing by the party node flow.
<=
If there is a representation, construct the flow as above, so that a flow exist. The flow is maximum because the maximal possible flow is constrainted by edge connecting to the sink.
So something must be wrong either with the arguments above, or with the implementation.
Without further ado, this is my source code:
#include "stdafx.h"
// http://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=1452
// #define LOG
#include "UVa10511.h"
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <queue>
using namespace std;
int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name);
int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name);
int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name);
int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst);
int UVa10511()
{
string line;
int number_of_test_cases;
cin >> number_of_test_cases;
getline(cin, line); // consume the blank link after the number of test cases
getline(cin, line); // consume the blank link before the first test case
for (int test_case = 0; test_case < number_of_test_cases; test_case++)
{
map<string, int> person_numbers;
map<int, string> person_namings;
map<string, int> party_numbers;
map<int, string> party_namings;
map<string, int> club_numbers;
map<int, string> club_namings;
vector<pair<int, int>> party_members;
vector<pair<int, int>> person_clubs;
while(getline(cin, line) && line != "" && line != " ")
{
string person_name;
string party_name;
string club_name;
stringstream sin(line);
sin >> person_name >> party_name;
int person_id = UVa10511_assign_person_number(person_numbers, person_namings, person_name);
int party_id = UVa10511_assign_party_number(party_numbers, party_namings, party_name);
party_members.push_back(pair<int, int>(party_id, person_id));
while(sin >> club_name)
{
int club_id = UVa10511_assign_club_number(club_numbers, club_namings, club_name);
person_clubs.push_back(pair<int, int>(person_id, club_id));
}
}
int number_of_parties = party_numbers.size();
int number_of_persons = person_numbers.size();
int number_of_clubs = club_numbers.size();
int number_of_nodes =
/* master source */ 1 +
/* parties */ number_of_parties +
/* person */ number_of_persons +
/* clubs */ number_of_clubs +
/* master sink */ 1;
vector<vector<int>> capacities;
vector<vector<int>> adjacency_list;
capacities.resize(number_of_nodes);
adjacency_list.resize(number_of_nodes);
for (int src = 0; src < number_of_nodes; src++)
{
capacities[src].resize(number_of_nodes);
for (int dst = 0; dst < number_of_nodes; dst++)
{
capacities[src][dst] = 0;
}
}
int max_party_participants = (number_of_clubs - 1) / 2; // Floor intended, not equal or more than half
for (int p = 0; p < number_of_parties; p++)
{
int party_node = p + 1;
capacities[0][party_node] = max_party_participants;
adjacency_list[0].push_back(party_node);
adjacency_list[party_node].push_back(0);
}
int person_node_start = 1 + number_of_parties;
for (vector<pair<int, int>>::iterator pmi = party_members.begin(); pmi != party_members.end(); pmi++)
{
int party_id = pmi->first;
int person_id = pmi->second;
int party_node = party_id + 1;
int person_node = person_node_start + person_id;
capacities[party_node][person_node] = 1;
adjacency_list[party_node].push_back(person_node);
adjacency_list[person_node].push_back(party_node);
}
int club_node_start = 1 + number_of_parties + number_of_persons;
for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
{
int person_id = pci->first;
int club_id = pci->second;
int person_node = person_node_start + person_id;
int club_node = club_node_start + club_id;
capacities[person_node][club_node] = 1;
adjacency_list[person_node].push_back(club_node);
adjacency_list[club_node].push_back(person_node);
}
for (int c = 0; c < number_of_clubs; c++)
{
int club_node = club_node_start + c;
capacities[club_node][number_of_nodes - 1] = 1;
adjacency_list[club_node].push_back(number_of_nodes - 1);
adjacency_list[number_of_nodes - 1].push_back(club_node);
}
#ifdef LOG
cout << "digraph {" << endl;
for (int src = 0; src < number_of_nodes; src++)
{
for (vector<int>::iterator di = adjacency_list[src].begin(); di != adjacency_list[src].end(); di++)
{
int dst = *di;
cout << src << "->" << dst << " [label=\"" << capacities[src][dst] << "\"];" << endl;
}
}
cout << "}" << endl;
#endif
int total_flow = UVa10511_Edmonds_Karps(capacities, adjacency_list, 0, number_of_nodes - 1);
if (test_case > 0)
{
cout << endl;
}
if (total_flow == number_of_clubs)
{
for (vector<pair<int, int>>::iterator pci = person_clubs.begin(); pci != person_clubs.end(); pci++)
{
int person_id = pci->first;
int club_id = pci->second;
int person_node = person_node_start + person_id;
int club_node = club_node_start + club_id;
if (capacities[person_node][club_node] == 0)
{
cout << person_namings[person_id] << " " << club_namings[club_id] << endl;
}
}
}
else
{
cout << "Impossible." << endl;
}
}
return 0;
}
int UVa10511_assign_party_number(map<string, int>& party_numbers, map<int, string>& party_namings, string party_name)
{
int party_number;
map<string, int>::iterator probe = party_numbers.find(party_name);
if (probe == party_numbers.end())
{
party_number = party_numbers.size();
party_numbers.insert(pair<string, int>(party_name, party_number));
party_namings.insert(pair<int, string>(party_number, party_name));
}
else
{
party_number = probe->second;
}
return party_number;
}
int UVa10511_assign_person_number(map<string, int>& person_numbers, map<int, string>& person_namings, string person_name)
{
int person_number;
map<string, int>::iterator probe = person_numbers.find(person_name);
if (probe == person_numbers.end())
{
person_number = person_numbers.size();
person_numbers.insert(pair<string, int>(person_name, person_number));
person_namings.insert(pair<int, string>(person_number, person_name));
}
else
{
person_number = probe->second;
}
return person_number;
}
int UVa10511_assign_club_number(map<string, int>& club_numbers, map<int, string>& club_namings, string club_name)
{
int club_number;
map<string, int>::iterator probe = club_numbers.find(club_name);
if (probe == club_numbers.end())
{
club_number = club_numbers.size();
club_numbers.insert(pair<string, int>(club_name, club_number));
club_namings.insert(pair<int, string>(club_number, club_name));
}
else
{
club_number = probe->second;
}
return club_number;
}
int UVa10511_Edmonds_Karps(vector<vector<int>>& capacities, vector<vector<int>>& adjacency_list, int src, int dst)
{
int total_flow = 0;
// Step 2: Edmonds Karp's
vector<int> parents; // Allow back-tracking the path found from bfs
int number_of_nodes = capacities.size();
parents.resize(number_of_nodes); // avoid reallocation
while (true)
{
// Step 2.1: Use BFS to find an augmenting flow
queue<int> bfs_queue;
for (int n = 0; n < number_of_nodes; n++)
{
parents[n] = -1; // indicating the node is not enqueued
}
parents[src] = -2; // indicating the node is enqueued but no actual parent because this is the root
bfs_queue.push(src);
while (bfs_queue.size() > 0)
{
int current = bfs_queue.front();
bfs_queue.pop();
for (vector<int>::iterator ni = adjacency_list[current].begin(); ni != adjacency_list[current].end(); ni++)
{
int neighbor = *ni;
if (parents[neighbor] == -1 && capacities[current][neighbor] > 0)
{
parents[neighbor] = current;
bfs_queue.push(neighbor);
if (neighbor == dst)
{
break;
}
}
}
if (parents[dst] != -1)
{
break;
}
}
if (parents[dst] == -1)
{
break;
}
else
{
// We have found an augmenting path, go through the path and find the max flow through this path
int cur = dst;
bool first = true;
int max_flow_through_path = 0;
while (true)
{
int src = parents[cur];
if (src != -2)
{
int dst = cur;
int available = capacities[src][dst];
#ifdef LOG
cout << src << "--" << available << "->" << dst << endl;
#endif
cur = parents[cur];
if (first)
{
max_flow_through_path = available;
first = false;
}
else
{
max_flow_through_path = min(max_flow_through_path, available);
}
}
else
{
break;
}
}
#ifdef LOG
cout << "flowing " << max_flow_through_path << endl << endl;
#endif
total_flow += max_flow_through_path;
// Flow the max flow through the augmenting path
cur = dst;
while (true)
{
int src = parents[cur];
if (src != -2)
{
capacities[src][cur] -= max_flow_through_path;
capacities[cur][src] += max_flow_through_path;
cur = parents[cur];
}
else
{
break;
}
}
}
}
return total_flow;
}
The source code is also posted in
https://github.com/cshung/Competition/blob/master/Competition/UVa10511.cpp
The same Edmonds Karps procedure is used to pass some other UVa problems, so I think it should be fine.
UVa820, UVa10480, UVa10779, UVa11506, UVa563 are all accepted with this Edmonds Karp procedure
(These code can be found in the Git repository as well)
I have even debugging the case where Edmond Karps make a wrong choice to being with a fixed it with an augmenting path for this test case
1
Person1 Party1 Club1 Club2
Person2 Party2 Club3
Person3 Party3 Club1
As my Edmond Karps used BFS in the adjacency list order, The chosen paths are
Master Source -> Party1 -> Person1 -> Club1 -> Master Sink
Master Source -> Party2 -> Person2 -> Club3 -> Master Sink
Master Source -> Party3 -> Person3 -> Club1 -> Person1 -> Club2 -> Master Sink [This used the reverse edge and proved going through reverse edge works]
Now I am really stuck, really don't know what's wrong, any help is appreciated.
Your thinking for this problem is correct, it is a typical problem that use maximum flow algorithm.
I have read your code over and over again, I can't find any mistake. Then I change the way you handle the input, then I got accept from UVA.
Just change the code
// you code
cin >> number_of_test_cases;
getline(cin, line); // consume the blank link before the first test case
getline(cin, line); // consume the blank link before the first test case
//line 43
while(getline(cin, line) && line != "" && line != " ")
// change to
scanf("%d\n", &number_of_test_cases);
//line 43
// while(getline(cin, line) && line.length() > 0)
After change the code, I got accept from uva .
Hope get accept response from you.

Reverse alternate elements and append to end of the list

Given a linked list as a->x->b->y->c->z , we need to reverse alternate element and append to end of list. That is , output it as a->b->c->z->y->x.
I have an O(n) solution but it takes extra memory , we take 2 lists and fill it with alternate elements respectively , so the two lists are a b c and x y z and then we will reverse the second list and append it to the tail of first so that it becomes a b c z y x .
My question is can we do it in place ? Or is there any other algorithm for the same ?
The basic idea:
Store x.
Make a point to b.
Make y point to the stored element (x).
Make b point to c.
etc.
At the end, make the last element at an odd position point to the stored element.
Pseudo-code: (simplified end-of-list check for readability)
current = startOfList
stored = NULL
while !endOfList
temp = current.next
current.next = current.next.next
temp.next = stored
stored = temp
current = current.next
current.next = stored
Complexity:
O(n) time, O(1) space.
Here is logic in recursion mode
public static Node alRev(Node head)
{
if (head == null) return head;
if (head.next != null)
{
if (head.next.next != null)
{
Node n = head.next;
head.next = head.next.next;
n.next = null;
Node temp = alRev(head.next);
if (temp != null){
temp.next = n;
return n;
}
}
else
return head.next;
}
else
return head;
return null;
}
This is a recent question from amazon interview, the Idea looks good and there seems to be no trick in it.
Java code with comments:
static void change(Node n)
{
if(n == null)
return;
Node current = n;
Node next = null, prev = null;
while(current != null && current.next != null)
{
// One of the alternate node which is to be reversed.
Node temp = current.next;
current.next = temp.next;
// Reverse the alternate node by changing its next pointer.
temp.next = next;
next = temp;
// This node will be used in the final step
// outside the loop to attach reversed nodes.
prev = current;
current = current.next;
}
// If there are odd number of nodes in the linked list.
if(current != null)
prev = current;
// Attach the reversed list to the unreversed list.
prev.next = next;
}
here the c code which don't uses any extra space for doing this..enjoy and have fun
in case of any doubt feel free to ask
#include<stdio.h>
#include<stdlib.h>
int n;
struct link
{
int val;
struct link *next;
};
void show(struct link *);
void addatbeg(struct link **p,int num)
{
struct link *temp,*help;
help=*p;
temp=(struct link *)malloc(sizeof(struct link));
temp->val=num;
temp->next=NULL;
if(help==NULL)
{
*p=temp;
}
else
{
temp->next=help;
*p=temp;
}
n++;
show(*p);
}
void revapp(struct link **p)
{
struct link *temp,*help,*q,*r;
r=NULL;
temp=*p;
help=*p;
while(temp->next!=NULL)
{
temp=temp->next;
q=r; //this portion will revrse the even position numbers
r=temp;
temp=temp->next;
//for making a connection between odd place numbers
if(help->next->next!=NULL)
{
help->next=temp;
help=help->next;
r->next=q;
}
else
{
r->next=q;
help->next=r;
show(*p);
return;
}
}
}
void show(struct link *q)
{
struct link *temp=q;
printf("\t");
while(q!=NULL )
{
printf("%d ->",q->val);
q=q->next;
if(q==temp)
{
printf("NULL\n");
return;
}
}
printf("NULL\n");
}
int main()
{
n=0;
struct link *p;
p=NULL;
// you can take user defined input but here i am solving it on predefined list
addatbeg(&p,8);
addatbeg(&p,7);
addatbeg(&p,6);
addatbeg(&p,5);
addatbeg(&p,4);
addatbeg(&p,3);
addatbeg(&p,2);
addatbeg(&p,1);
revapp(&p);
return 0;
}`

How to find validity of a string of parentheses, curly brackets and square brackets?

I recently came in contact with this interesting problem. You are given a string containing just the characters '(', ')', '{', '}', '[' and ']', for example, "[{()}]", you need to write a function which will check validity of such an input string, function may be like this:
bool isValid(char* s);
these brackets have to close in the correct order, for example "()" and "()[]{}" are all valid but "(]", "([)]" and "{{{{" are not!
I came out with following O(n) time and O(n) space complexity solution, which works fine:
Maintain a stack of characters.
Whenever you find opening braces '(', '{' OR '[' push it on the stack.
Whenever you find closing braces ')', '}' OR ']' , check if top of stack is corresponding opening bracket, if yes, then pop the stack, else break the loop and return false.
Repeat steps 2 - 3 until end of the string.
This works, but can we optimize it for space, may be constant extra space, I understand that time complexity cannot be less than O(n) as we have to look at every character.
So my question is can we solve this problem in O(1) space?
With reference to the excellent answer from Matthieu M., here is an implementation in C# that seems to work beautifully.
/// <summary>
/// Checks to see if brackets are well formed.
/// Passes "Valid parentheses" challenge on www.codeeval.com,
/// which is a programming challenge site much like www.projecteuler.net.
/// </summary>
/// <param name="input">Input string, consisting of nothing but various types of brackets.</param>
/// <returns>True if brackets are well formed, false if not.</returns>
static bool IsWellFormedBrackets(string input)
{
string previous = "";
while (input.Length != previous.Length)
{
previous = input;
input = input
.Replace("()", String.Empty)
.Replace("[]", String.Empty)
.Replace("{}", String.Empty);
}
return (input.Length == 0);
}
Essentially, all it does is remove pairs of brackets until there are none left to remove; if there is anything left the brackets are not well formed.
Examples of well formed brackets:
()[]
{()[]}
Example of malformed brackets:
([)]
{()[}]
Actually, there's a deterministic log-space algorithm due to Ritchie and Springsteel: http://dx.doi.org/10.1016/S0019-9958(72)90205-7 (paywalled, sorry not online). Since we need log bits to index the string, this is space-optimal.
If you're willing to accept one-sided error, then there's an algorithm that uses n polylog(n) time and polylog(n) space: http://www.eccc.uni-trier.de/report/2009/119/
If the input is read-only, I don't think we can do O(1) space. It is a well known fact that any O(1) space decidable language is regular (i.e writeable as a regular expression). The set of strings you have is not a regular language.
Of course, this is about a Turing Machine. I would expect it to be true for fixed word RAM machines too.
Edit: Although simple, this algorithm is actually O(n^2) in terms of character comparisons. To demonstrate it, one can simply generate a string as '(' * n + ')' * n.
I have a simple, though perhaps erroneous idea, that I will submit to your criticisms.
It's a destructive algorithm, which means that if you ever need the string it would not help (since you would need to copy it down).
Otherwise, the algorithm work with a simple index within the current string.
The idea is to remove pairs one after the others:
([{}()])
([()])
([])
()
empty -> OK
It is based on the simple fact that if we have matching pairs, then at least one is of the form () without any pair character in between.
Algorithm:
i := 0
Find a matching pair from i. If none is found, then the string is not valid. If one is found, let i be the index of the first character.
Remove [i:i+1] from the string
If i is at the end of the string, and the string is not empty, it's a failure.
If [i-1:i] is a matching pair, i := i-1 and back to 3.
Else, back to 1.
The algorithm is O(n) in complexity because:
each iteration of the loop removes 2 characters from the string
the step 2., which is linear, is naturally bound (i cannot grow indefinitely)
And it's O(1) in space because only the index is required.
Of course, if you can't afford to destroy the string, then you'll have to copy it, and that's O(n) in space so no real benefit there!
Unless, of course, I am deeply mistaken somewhere... and perhaps someone could use the original idea (there is a pair somewhere) to better effect.
I doubt you'll find a better solution, since even if you use internal functions to regexp or count occurrences, they still have a O(...) cost. I'd say your solution is the best :)
To optimize for space you could do some run-length encoding on your stack, but I doubt it would gain you very much, except in cases like {{{{{{{{{{}}}}}}}}}}.
http://www.sureinterview.com/shwqst/112007
It is natural to solve this problem with a stack.
If only '(' and ')' are used, the stack is not necessary. We just need to maintain a counter for the unmatched left '('. The expression is valid if the counter is always non-negative during the match and is zero at the end.
In general case, although the stack is still necessary, the depth of the stack can be reduced by using a counter for unmatched braces.
This is an working java code where I filter out the brackets from the string expression and then check the well formedness by replacing wellformed braces by nulls
Sample input = (a+{b+c}-[d-e])+[f]-[g] FilterBrackets will output = ({}[])[][] Then I check for wellformedness.
Comments welcome.
public class ParanString {
public static void main(String[] args) {
String s = FilterBrackets("(a+{b+c}-[d-e])[][]");
while ((s.length()!=0) && (s.contains("[]")||s.contains("()")||s.contains("{}")))
{
//System.out.println(s.length());
//System.out.println(s);
s = s.replace("[]", "");
s = s.replace("()", "");
s = s.replace("{}", "");
}
if(s.length()==0)
{
System.out.println("Well Formed");
}
else
{
System.out.println("Not Well Formed");
}
}
public static String FilterBrackets(String str)
{
int len=str.length();
char arr[] = str.toCharArray();
String filter = "";
for (int i = 0; i < len; i++)
{
if ((arr[i]=='(') || (arr[i]==')') || (arr[i]=='[') || (arr[i]==']') || (arr[i]=='{') || (arr[i]=='}'))
{
filter=filter+arr[i];
}
}
return filter;
}
}
The following modification of Sbusidan's answer is O(n2) time complex but O(log n) space simple.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
char opposite(char bracket) {
switch(bracket) {
case '[':
return ']';
case '(':
return ')';
}
}
bool is_balanced(int length, char *s) {
int depth, target_depth, index;
char target_bracket;
if(length % 2 != 0) {
return false;
}
for(target_depth = length/2; target_depth > 0; target_depth--) {
depth=0;
for(index = 0; index < length; index++) {
switch(s[index]) {
case '(':
case '[':
depth++;
if(depth == target_depth) target_bracket = opposite(s[index]);
break;
case ')':
case ']':
if(depth == 0) return false;
if(depth == target_depth && s[index] != target_bracket) return false;
depth--;
break;
}
}
}
}
void main(char* argv[]) {
char input[] = "([)[(])]";
char *balanced = is_balanced(strlen(input), input) ? "balanced" : "imbalanced";
printf("%s is %s.\n", input, balanced);
}
If you can overwrite the input string (not reasonable in the use cases I envision, but what the heck...) you can do it in constant space, though I believe the time requirement goes up to O(n2).
Like this:
string s = input
char c = null
int i=0
do
if s[i] isAOpenChar()
c = s[i]
else if
c = isACloseChar()
if closeMatchesOpen(s[i],c)
erase s[i]
while s[--i] != c ;
erase s[i]
c == null
i = 0; // Not optimal! It would be better to back up until you find an opening character
else
return fail
end if
while (s[++i] != EOS)
if c==null
return pass
else
return fail
The essence of this is to use the early part of the input as the stack.
I know I'm a little late to this party; it's also my very first post on StackOverflow.
But when I looked through the answers, I thought I might be able to come up with a better solution.
So my solution is to use a few pointers.
It doesn't even have to use any RAM storage, as registers can be used for this.
I have not tested the code; it's written it on the fly.
You'll need to fix my typos, and debug it, but I believe you'll get the idea.
Memory usage: Only the CPU registers in most cases.
CPU usage: It depends, but approximately twice the time it takes to read the string.
Modifies memory: No.
b: string beginning, e: string end.
l: left position, r: right position.
c: char, m: match char
if r reaches the end of the string, we have a success.
l goes backwards from r towards b.
Whenever r meets a new start kind, set l = r.
when l reaches b, we're done with the block; jump to beginning of next block.
const char *chk(const char *b, int len) /* option 2: remove int len */
{
char c, m;
const char *l, *r;
e = &b[len]; /* option 2: remove. */
l = b;
r = b;
while(r < e) /* option 2: change to while(1) */
{
c = *r++;
/* option 2: if(0 == c) break; */
if('(' == c || '{' == c || '[' == c)
{
l = r;
}
else if(')' == c || ']' == c || '}' == c)
{
/* find 'previous' starting brace */
m = 0;
while(l > b && '(' != m && '[' != m && '{' != m)
{
m = *--l;
}
/* now check if we have the correct one: */
if(((m & 1) + 1 + m) != c) /* cryptic: convert starting kind to ending kind and match with c */
{
return(r - 1); /* point to error */
}
if(l <= b) /* did we reach the beginning of this block ? */
{
b = r; /* set new beginning to 'head' */
l = b; /* obsolete: make left is in range. */
}
}
}
m = 0;
while(l > b && '(' != m && '[' != m && '{' != m)
{
m = *--l;
}
return(m ? l : NULL); /* NULL-pointer for OK */
}
After thinking about this approach for a while, I realized that it will not work as it is right now.
The problem will be that if you have "[()()]", it'll fail when reaching the ']'.
But instead of deleting the proposed solution, I'll leave it here, as it's actually not impossible to make it work, it does require some modification, though.
/**
*
* #author madhusudan
*/
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Main().validateBraces("()()()()(((((())))))()()()()()()()()");
// TODO code application logic here
}
/**
* #Use this method to validate braces
*/
public void validateBraces(String teststr)
{
StringBuffer teststr1=new StringBuffer(teststr);
int ind=-1;
for(int i=0;i<teststr1.length();)
{
if(teststr1.length()<1)
break;
char ch=teststr1.charAt(0);
if(isClose(ch))
break;
else if(isOpen(ch))
{
ind=teststr1.indexOf(")", i);
if(ind==-1)
break;
teststr1=teststr1.deleteCharAt(ind).deleteCharAt(i);
}
else if(isClose(ch))
{
teststr1=deleteOpenBraces(teststr1,0,i);
}
}
if(teststr1.length()>0)
{
System.out.println("Invalid");
}else
{
System.out.println("Valid");
}
}
public boolean isOpen(char ch)
{
if("(".equals(Character.toString(ch)))
{
return true;
}else
return false;
}
public boolean isClose(char ch)
{
if(")".equals(Character.toString(ch)))
{
return true;
}else
return false;
}
public StringBuffer deleteOpenBraces(StringBuffer str,int start,int end)
{
char ar[]=str.toString().toCharArray();
for(int i=start;i<end;i++)
{
if("(".equals(ar[i]))
str=str.deleteCharAt(i).deleteCharAt(end);
break;
}
return str;
}
}
Instead of putting braces into the stack, you could use two pointers to check the characters of the string. one start from the beginning of the string and the other start from end of the string. something like
bool isValid(char* s) {
start = find_first_brace(s);
end = find_last_brace(s);
while (start <= end) {
if (!IsPair(start,end)) return false;
// move the pointer forward until reach a brace
start = find_next_brace(start);
// move the pointer backward until reach a brace
end = find_prev_brace(end);
}
return true;
}
Note that there are some corner case not handled.
I think that you can implement an O(n) algorithm. Simply you have to initialise an counter variable for each type: curly, square and normal brackets. After than you should iterate the string and should increase the coresponding counter if the bracket is opened, otherwise to decrease it. If the counter is negative return false. AfterI think that you can implement an O(n) algorithm. Simply you have to initialise an counter variable for each type: curly, square and normal brackets. After than you should iterate the string and should increase the coresponding counter if the bracket is opened, otherwise to decrease it. If the counter is negative return false. After you count all brackets, you should check if all counters are zero. In that case, the string is valid and you should return true.
You could provide the value and check if its a valid one, it would print YES otherwise it would print NO
static void Main(string[] args)
{
string value = "(((([{[(}]}]))))";
List<string> jj = new List<string>();
if (!(value.Length % 2 == 0))
{
Console.WriteLine("NO");
}
else
{
bool isValid = true;
List<string> items = new List<string>();
for (int i = 0; i < value.Length; i++)
{
string item = value.Substring(i, 1);
if (item == "(" || item == "{" || item == "[")
{
items.Add(item);
}
else
{
string openItem = items[items.Count - 1];
if (((item == ")" && openItem == "(")) || (item == "}" && openItem == "{") || (item == "]" && openItem == "["))
{
items.RemoveAt(items.Count - 1);
}
else
{
isValid = false;
break;
}
}
}
if (isValid)
{
Console.WriteLine("Yes");
}
else
{
Console.WriteLine("NO");
}
}
Console.ReadKey();
}
var verify = function(text)
{
var symbolsArray = ['[]', '()', '<>'];
var symbolReg = function(n)
{
var reg = [];
for (var i = 0; i < symbolsArray.length; i++) {
reg.push('\\' + symbolsArray[i][n]);
}
return new RegExp('(' + reg.join('|') + ')','g');
};
// openReg matches '(', '[' and '<' and return true or false
var openReg = symbolReg(0);
// closeReg matches ')', ']' and '>' and return true or false
var closeReg = symbolReg(1);
// nestTest matches openSymbol+anyChar+closeSymbol
// and returns an obj with the match str and it's start index
var nestTest = function(symbols, text)
{
var open = symbols[0]
, close = symbols[1]
, reg = new RegExp('(\\' + open + ')([\\s\\S])*(\\' + close + ')','g')
, test = reg.exec(text);
if (test) return {
start: test.index,
str: test[0]
};
else return false;
};
var recursiveCheck = function(text)
{
var i, nestTests = [], test, symbols;
// nestTest with each symbol
for (i = 0; i < symbolsArray.length; i++)
{
symbols = symbolsArray[i];
test = nestTest(symbols, text);
if (test) nestTests.push(test);
}
// sort tests by start index
nestTests.sort(function(a, b)
{
return a.start - b.start;
});
if (nestTests.length)
{
// build nest data: calculate match end index
for (i = 0; i < nestTests.length; i++)
{
test = nestTests[i];
var end = test.start + ( (test.str) ? test.str.length : 0 );
nestTests[i].end = end;
var last = (nestTests[i + 1]) ? nestTests[i + 1].index : text.length;
nestTests[i].pos = text.substring(end, last);
}
for (i = 0; i < nestTests.length; i++)
{
test = nestTests[i];
// recursive checks what's after the nest
if (test.pos.length && !recursiveCheck(test.pos)) return false;
// recursive checks what's in the nest
if (test.str.length) {
test.str = test.str.substring(1, test.str.length - 1);
return recursiveCheck(test.str);
} else return true;
}
} else {
// if no nests then check for orphan symbols
var closeTest = closeReg.test(text);
var openTest = openReg.test(text);
return !(closeTest || openTest);
}
};
return recursiveCheck(text);
};
Using c# OOPS programming... Small and simple solution
Console.WriteLine("Enter the string");
string str = Console.ReadLine();
int length = str.Length;
if (length % 2 == 0)
{
while (length > 0 && str.Length > 0)
{
for (int i = 0; i < str.Length; i++)
{
if (i + 1 < str.Length)
{
switch (str[i])
{
case '{':
if (str[i + 1] == '}')
str = str.Remove(i, 2);
break;
case '(':
if (str[i + 1] == ')')
str = str.Remove(i, 2);
break;
case '[':
if (str[i + 1] == ']')
str = str.Remove(i, 2);
break;
}
}
}
length--;
}
if(str.Length > 0)
Console.WriteLine("Invalid input");
else
Console.WriteLine("Valid input");
}
else
Console.WriteLine("Invalid input");
Console.ReadKey();
This is my solution to the problem.
O(n) is the complexity of time without complexity of space.
Code in C.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool checkBraket(char *s)
{
int curly = 0, rounded = 0, squre = 0;
int i = 0;
char ch = s[0];
while (ch != '\0')
{
if (ch == '{') curly++;
if (ch == '}') {
if (curly == 0) {
return false;
} else {
curly--; }
}
if (ch == '[') squre++;
if (ch == ']') {
if (squre == 0) {
return false;
} else {
squre--;
}
}
if (ch == '(') rounded++;
if (ch == ')') {
if (rounded == 0) {
return false;
} else {
rounded--;
}
}
i++;
ch = s[i];
}
if (curly == 0 && rounded == 0 && squre == 0){
return true;
}
else {
return false;
}
}
void main()
{
char mystring[] = "{{{{{[(())}}]}}}";
int answer = checkBraket(mystring);
printf("my answer is %d\n", answer);
return;
}

Merge Sort a Linked List

I was recently brushing up on some fundamentals and found merge sorting a linked list to be a pretty good challenge. If you have a good implementation then show it off here.
Wonder why it should be big challenge as it is stated here, here is a straightforward implementation in Java with out any "clever tricks".
//The main function
public static Node merge_sort(Node head)
{
if(head == null || head.next == null)
return head;
Node middle = getMiddle(head); //get the middle of the list
Node left_head = head;
Node right_head = middle.next;
middle.next = null; //split the list into two halfs
return merge(merge_sort(left_head), merge_sort(right_head)); //recurse on that
}
//Merge subroutine to merge two sorted lists
public static Node merge(Node a, Node b)
{
Node dummyHead = new Node();
for(Node current = dummyHead; a != null && b != null; current = current.next;)
{
if(a.data <= b.data)
{
current.next = a;
a = a.next;
}
else
{
current.next = b;
b = b.next;
}
}
dummyHead.next = (a == null) ? b : a;
return dummyHead.next;
}
//Finding the middle element of the list for splitting
public static Node getMiddle(Node head)
{
if(head == null)
return head;
Node slow = head, fast = head;
while(fast.next != null && fast.next.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
A simpler/clearer implementation might be the recursive implementation, from which the NLog(N) execution time is more clear.
typedef struct _aList {
struct _aList* next;
struct _aList* prev; // Optional.
// some data
} aList;
aList* merge_sort_list_recursive(aList *list,int (*compare)(aList *one,aList *two))
{
// Trivial case.
if (!list || !list->next)
return list;
aList *right = list,
*temp = list,
*last = list,
*result = 0,
*next = 0,
*tail = 0;
// Find halfway through the list (by running two pointers, one at twice the speed of the other).
while (temp && temp->next)
{
last = right;
right = right->next;
temp = temp->next->next;
}
// Break the list in two. (prev pointers are broken here, but we fix later)
last->next = 0;
// Recurse on the two smaller lists:
list = merge_sort_list_recursive(list, compare);
right = merge_sort_list_recursive(right, compare);
// Merge:
while (list || right)
{
// Take from empty lists, or compare:
if (!right) {
next = list;
list = list->next;
} else if (!list) {
next = right;
right = right->next;
} else if (compare(list, right) < 0) {
next = list;
list = list->next;
} else {
next = right;
right = right->next;
}
if (!result) {
result=next;
} else {
tail->next=next;
}
next->prev = tail; // Optional.
tail = next;
}
return result;
}
NB: This has a Log(N) storage requirement for the recursion. Performance should be roughly comparable with the other strategy I posted. There is a potential optimisation here by running the merge loop while (list && right), and simple appending the remaining list (since we don't really care about the end of the lists; knowing that they're merged suffices).
Heavily based on the EXCELLENT code from: http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
Trimmed slightly, and tidied:
typedef struct _aList {
struct _aList* next;
struct _aList* prev; // Optional.
// some data
} aList;
aList *merge_sort_list(aList *list,int (*compare)(aList *one,aList *two))
{
int listSize=1,numMerges,leftSize,rightSize;
aList *tail,*left,*right,*next;
if (!list || !list->next) return list; // Trivial case
do { // For each power of two<=list length
numMerges=0,left=list;tail=list=0; // Start at the start
while (left) { // Do this list_len/listSize times:
numMerges++,right=left,leftSize=0,rightSize=listSize;
// Cut list into two halves (but don't overrun)
while (right && leftSize<listSize) leftSize++,right=right->next;
// Run through the lists appending onto what we have so far.
while (leftSize>0 || (rightSize>0 && right)) {
// Left empty, take right OR Right empty, take left, OR compare.
if (!leftSize) {next=right;right=right->next;rightSize--;}
else if (!rightSize || !right) {next=left;left=left->next;leftSize--;}
else if (compare(left,right)<0) {next=left;left=left->next;leftSize--;}
else {next=right;right=right->next;rightSize--;}
// Update pointers to keep track of where we are:
if (tail) tail->next=next; else list=next;
// Sort prev pointer
next->prev=tail; // Optional.
tail=next;
}
// Right is now AFTER the list we just sorted, so start the next sort there.
left=right;
}
// Terminate the list, double the list-sort size.
tail->next=0,listSize<<=1;
} while (numMerges>1); // If we only did one merge, then we just sorted the whole list.
return list;
}
NB: This is O(NLog(N)) guaranteed, and uses O(1) resources (no recursion, no stack, nothing).
One interesting way is to maintain a stack, and only merge if the list on the stack has the same number of elements, and otherwise push the list, until you run out of elements in the incoming list, and then merge up the stack.
The simplest is from
Gonnet + Baeza Yates Handbook of Algorithms. You call it with the number of sorted elements you want, which recursively gets bisected until it reaches a request for a size one list which you then just peel off the front of the original list. These all get merged up into a full sized sorted list.
[Note that the cool stack-based one in the first post is called the Online Mergesort and it gets the tiniest mention in an exercise in Knuth Vol 3]
Here's an alternative recursive version. This does not need to step along the list to split it: we supply a pointer to a head element (which is not part of the sort) and a length, and the recursive function returns a pointer to the end of the sorted list.
element* mergesort(element *head,long lengtho)
{
long count1=(lengtho/2), count2=(lengtho-count1);
element *next1,*next2,*tail1,*tail2,*tail;
if (lengtho<=1) return head->next; /* Trivial case. */
tail1 = mergesort(head,count1);
tail2 = mergesort(tail1,count2);
tail=head;
next1 = head->next;
next2 = tail1->next;
tail1->next = tail2->next; /* in case this ends up as the tail */
while (1) {
if(cmp(next1,next2)<=0) {
tail->next=next1; tail=next1;
if(--count1==0) { tail->next=next2; return tail2; }
next1=next1->next;
} else {
tail->next=next2; tail=next2;
if(--count2==0) { tail->next=next1; return tail1; }
next2=next2->next;
}
}
}
I'd been obsessing over optimizing clutter for this algorithm and below is what I've finally arrived at. Lot of other code on Internet and StackOverflow is horribly bad. There are people trying to get middle point of the list, doing recursion, having multiple loops for left over nodes, maintaining counts of ton of things - ALL of which is unnecessary. MergeSort naturally fits to linked list and algorithm can be beautiful and compact but it's not trivial to get to that state.
Below code maintains minimum number of variables and has minimum number of logical steps needed for the algorithm (i.e. without making code unmaintainable/unreadable) as far as I know. However I haven't tried to minimize LOC and kept as much white space as necessary to keep things readable. I've tested this code through fairly rigorous unit tests.
Note that this answer combines few techniques from other answer https://stackoverflow.com/a/3032462/207661. While the code is in C#, it should be trivial to convert in to C++, Java, etc.
SingleListNode<T> SortLinkedList<T>(SingleListNode<T> head) where T : IComparable<T>
{
int blockSize = 1, blockCount;
do
{
//Maintain two lists pointing to two blocks, left and right
SingleListNode<T> left = head, right = head, tail = null;
head = null; //Start a new list
blockCount = 0;
//Walk through entire list in blocks of size blockCount
while (left != null)
{
blockCount++;
//Advance right to start of next block, measure size of left list while doing so
int leftSize = 0, rightSize = blockSize;
for (;leftSize < blockSize && right != null; ++leftSize)
right = right.Next;
//Merge two list until their individual ends
bool leftEmpty = leftSize == 0, rightEmpty = rightSize == 0 || right == null;
while (!leftEmpty || !rightEmpty)
{
SingleListNode<T> smaller;
//Using <= instead of < gives us sort stability
if (rightEmpty || (!leftEmpty && left.Value.CompareTo(right.Value) <= 0))
{
smaller = left; left = left.Next; --leftSize;
leftEmpty = leftSize == 0;
}
else
{
smaller = right; right = right.Next; --rightSize;
rightEmpty = rightSize == 0 || right == null;
}
//Update new list
if (tail != null)
tail.Next = smaller;
else
head = smaller;
tail = smaller;
}
//right now points to next block for left
left = right;
}
//terminate new list, take care of case when input list is null
if (tail != null)
tail.Next = null;
//Lg n iterations
blockSize <<= 1;
} while (blockCount > 1);
return head;
}
Points of interest
There is no special handling for cases like null list of list of 1 etc required. These cases "just works".
Lot of "standard" algorithms texts have two loops to go over leftover elements to handle the case when one list is shorter than other. Above code eliminates need for it.
We make sure sort is stable
The inner while loop which is a hot spot evaluates 3 expressions per iteration on average which I think is minimum one can do.
Update: #ideasman42 has translated above code to C/C++ along with suggestions for fixing comments and bit more improvement. Above code is now up to date with these.
I decided to test the examples here, and also one more approach, originally written by Jonathan Cunningham in Pop-11. I coded all the approaches in C# and did a comparison with a range of different list sizes. I compared the Mono eglib approach by Raja R Harinath, the C# code by Shital Shah, the Java approach by Jayadev, the recursive and non-recursive versions by David Gamble, the first C code by Ed Wynn (this crashed with my sample dataset, I didn't debug), and Cunningham's version. Full code here: https://gist.github.com/314e572808f29adb0e41.git.
Mono eglib is based on a similar idea to Cunningham's and is of comparable speed, unless the list happens to be sorted already, in which case Cunningham's approach is much much faster (if its partially sorted, the eglib is slightly faster). The eglib code uses a fixed table to hold the merge sort recursion, whereas Cunningham's approach works by using increasing levels of recursion - so it starts out using no recursion, then 1-deep recursion, then 2-deep recursion and so on, according to how many steps are needed to do the sort. I find the Cunningham code a little easier to follow and there is no guessing involved in how big to make the recursion table, so it gets my vote. The other approaches I tried from this page were two or more times slower.
Here is the C# port of the Pop-11 sort:
/// <summary>
/// Sort a linked list in place. Returns the sorted list.
/// Originally by Jonathan Cunningham in Pop-11, May 1981.
/// Ported to C# by Jon Meyer.
/// </summary>
public class ListSorter<T> where T : IComparable<T> {
SingleListNode<T> workNode = new SingleListNode<T>(default(T));
SingleListNode<T> list;
/// <summary>
/// Sorts a linked list. Returns the sorted list.
/// </summary>
public SingleListNode<T> Sort(SingleListNode<T> head) {
if (head == null) throw new NullReferenceException("head");
list = head;
var run = GetRun(); // get first run
// As we progress, we increase the recursion depth.
var n = 1;
while (list != null) {
var run2 = GetSequence(n);
run = Merge(run, run2);
n++;
}
return run;
}
// Get the longest run of ordered elements from list.
// The run is returned, and list is updated to point to the
// first out-of-order element.
SingleListNode<T> GetRun() {
var run = list; // the return result is the original list
var prevNode = list;
var prevItem = list.Value;
list = list.Next; // advance to the next item
while (list != null) {
var comp = prevItem.CompareTo(list.Value);
if (comp > 0) {
// reached end of sequence
prevNode.Next = null;
break;
}
prevItem = list.Value;
prevNode = list;
list = list.Next;
}
return run;
}
// Generates a sequence of Merge and GetRun() operations.
// If n is 1, returns GetRun()
// If n is 2, returns Merge(GetRun(), GetRun())
// If n is 3, returns Merge(Merge(GetRun(), GetRun()),
// Merge(GetRun(), GetRun()))
// and so on.
SingleListNode<T> GetSequence(int n) {
if (n < 2) {
return GetRun();
} else {
n--;
var run1 = GetSequence(n);
if (list == null) return run1;
var run2 = GetSequence(n);
return Merge(run1, run2);
}
}
// Given two ordered lists this returns a list that is the
// result of merging the two lists in-place (modifying the pairs
// in list1 and list2).
SingleListNode<T> Merge(SingleListNode<T> list1, SingleListNode<T> list2) {
// we reuse a single work node to hold the result.
// Simplifies the number of test cases in the code below.
var prevNode = workNode;
while (true) {
if (list1.Value.CompareTo(list2.Value) <= 0) {
// list1 goes first
prevNode.Next = list1;
prevNode = list1;
if ((list1 = list1.Next) == null) {
// reached end of list1 - join list2 to prevNode
prevNode.Next = list2;
break;
}
} else { // same but for list2
prevNode.Next = list2;
prevNode = list2;
if ((list2 = list2.Next) == null) {
prevNode.Next = list1;
break;
}
}
}
// the result is in the back of the workNode
return workNode.Next;
}
}
Here is my implementation of Knuth's "List merge sort" (Algorithm 5.2.4L from Vol.3 of TAOCP, 2nd ed.). I'll add some comments at the end, but here's a summary:
On random input, it runs a bit faster than Simon Tatham's code (see Dave Gamble's non-recursive answer, with a link) but a bit slower than Dave Gamble's recursive code. It's harder to understand than either. At least in my implementation, it requires each element to have TWO pointers to elements. (An alternative would be one pointer and a boolean flag.) So, it's probably not a useful approach. However, one distinctive point is that it runs very fast if the input has long stretches that are already sorted.
element *knuthsort(element *list)
{ /* This is my attempt at implementing Knuth's Algorithm 5.2.4L "List merge sort"
from Vol.3 of TAOCP, 2nd ed. */
element *p, *pnext, *q, *qnext, head1, head2, *s, *t;
if(!list) return NULL;
L1: /* This is the clever L1 from exercise 12, p.167, solution p.647. */
head1.next=list;
t=&head2;
for(p=list, pnext=p->next; pnext; p=pnext, pnext=p->next) {
if( cmp(p,pnext) > 0 ) { t->next=NULL; t->spare=pnext; t=p; }
}
t->next=NULL; t->spare=NULL; p->spare=NULL;
head2.next=head2.spare;
L2: /* begin a new pass: */
t=&head2;
q=t->next;
if(!q) return head1.next;
s=&head1;
p=s->next;
L3: /* compare: */
if( cmp(p,q) > 0 ) goto L6;
L4: /* add p onto the current end, s: */
if(s->next) s->next=p; else s->spare=p;
s=p;
if(p->next) { p=p->next; goto L3; }
else p=p->spare;
L5: /* complete the sublist by adding q and all its successors: */
s->next=q; s=t;
for(qnext=q->next; qnext; q=qnext, qnext=q->next);
t=q; q=q->spare;
goto L8;
L6: /* add q onto the current end, s: */
if(s->next) s->next=q; else s->spare=q;
s=q;
if(q->next) { q=q->next; goto L3; }
else q=q->spare;
L7: /* complete the sublist by adding p and all its successors: */
s->next=p;
s=t;
for(pnext=p->next; pnext; p=pnext, pnext=p->next);
t=p; p=p->spare;
L8: /* is this end of the pass? */
if(q) goto L3;
if(s->next) s->next=p; else s->spare=p;
t->next=NULL; t->spare=NULL;
goto L2;
}
There's a non-recursive linked-list mergesort in mono eglib.
The basic idea is that the control-loop for the various merges parallels the bitwise-increment of a binary integer. There are O(n) merges to "insert" n nodes into the merge tree, and the rank of those merges corresponds to the binary digit that gets incremented. Using this analogy, only O(log n) nodes of the merge-tree need to be materialized into a temporary holding array.
A tested, working C++ version of single linked list, based on the highest voted answer.
singlelinkedlist.h:
#pragma once
#include <stdexcept>
#include <iostream>
#include <initializer_list>
namespace ythlearn{
template<typename T>
class Linkedlist{
public:
class Node{
public:
Node* next;
T elem;
};
Node head;
int _size;
public:
Linkedlist(){
head.next = nullptr;
_size = 0;
}
Linkedlist(std::initializer_list<T> init_list){
head.next = nullptr;
_size = 0;
for(auto s = init_list.begin(); s!=init_list.end(); s++){
push_left(*s);
}
}
int size(){
return _size;
}
bool isEmpty(){
return size() == 0;
}
bool isSorted(){
Node* n_ptr = head.next;
while(n_ptr->next != nullptr){
if(n_ptr->elem > n_ptr->next->elem)
return false;
n_ptr = n_ptr->next;
}
return true;
}
Linkedlist& push_left(T elem){
Node* n = new Node;
n->elem = elem;
n->next = head.next;
head.next = n;
++_size;
return *this;
}
void print(){
Node* loopPtr = head.next;
while(loopPtr != nullptr){
std::cout << loopPtr->elem << " ";
loopPtr = loopPtr->next;
}
std::cout << std::endl;
}
void call_merge(){
head.next = merge_sort(head.next);
}
Node* merge_sort(Node* n){
if(n == nullptr || n->next == nullptr)
return n;
Node* middle = getMiddle(n);
Node* left_head = n;
Node* right_head = middle->next;
middle->next = nullptr;
return merge(merge_sort(left_head), merge_sort(right_head));
}
Node* getMiddle(Node* n){
if(n == nullptr)
return n;
Node* slow, *fast;
slow = fast = n;
while(fast->next != nullptr && fast->next->next != nullptr){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
Node* merge(Node* a, Node* b){
Node dummyHead;
Node* current = &dummyHead;
while(a != nullptr && b != nullptr){
if(a->elem < b->elem){
current->next = a;
a = a->next;
}else{
current->next = b;
b = b->next;
}
current = current->next;
}
current->next = (a == nullptr) ? b : a;
return dummyHead.next;
}
Linkedlist(const Linkedlist&) = delete;
Linkedlist& operator=(const Linkedlist&) const = delete;
~Linkedlist(){
Node* node_to_delete;
Node* ptr = head.next;
while(ptr != nullptr){
node_to_delete = ptr;
ptr = ptr->next;
delete node_to_delete;
}
}
};
}
main.cpp:
#include <iostream>
#include <cassert>
#include "singlelinkedlist.h"
using namespace std;
using namespace ythlearn;
int main(){
Linkedlist<int> l = {3,6,-5,222,495,-129,0};
l.print();
l.call_merge();
l.print();
assert(l.isSorted());
return 0;
}
Simplest Java Implementation:
Time Complexity: O(nLogn) n = number of nodes. Each iteration through the linked list doubles the size of the sorted smaller linked lists. For example, after the first iteration, the linked list will be sorted into two halves. After the second iteration, the linked list will be sorted into four halves. It will keep sorting up to the size of the linked list. This will take O(logn) doublings of the small linked lists' sizes to reach the original linked list size. The n in nlogn is there because each iteration of the linked list will take time proportional to the number of nodes in the originial linked list.
class Node {
int data;
Node next;
Node(int d) {
data = d;
}
}
class LinkedList {
Node head;
public Node mergesort(Node head) {
if(head == null || head.next == null) return head;
Node middle = middle(head), middle_next = middle.next;
middle.next = null;
Node left = mergesort(head), right = mergesort(middle_next), node = merge(left, right);
return node;
}
public Node merge(Node first, Node second) {
Node node = null;
if (first == null) return second;
else if (second == null) return first;
else if (first.data <= second.data) {
node = first;
node.next = merge(first.next, second);
} else {
node = second;
node.next = merge(first, second.next);
}
return node;
}
public Node middle(Node head) {
if (head == null) return head;
Node second = head, first = head.next;
while(first != null) {
first = first.next;
if (first != null) {
second = second.next;
first = first.next;
}
}
return second;
}
}
Another example of a non-recursive merge sort for linked lists, where the functions are not part of a class. This example code and HP / Microsoft std::list::sort both use the same basic algorithm. A bottom up, non-recursive, merge sort that uses a small (26 to 32) array of pointers to the first nodes of a list, where array[i] is either 0 or points to a list of size 2 to the power i. On my system, Intel 2600K 3.4ghz, it can sort 4 million nodes with 32 bit unsigned integers as data in about 1 second.
typedef struct NODE_{
struct NODE_ * next;
uint32_t data;
}NODE;
NODE * MergeLists(NODE *, NODE *); /* prototype */
/* sort a list using array of pointers to list */
/* aList[i] == NULL or ptr to list with 2^i nodes */
#define NUMLISTS 32 /* number of lists */
NODE * SortList(NODE *pList)
{
NODE * aList[NUMLISTS]; /* array of lists */
NODE * pNode;
NODE * pNext;
int i;
if(pList == NULL) /* check for empty list */
return NULL;
for(i = 0; i < NUMLISTS; i++) /* init array */
aList[i] = NULL;
pNode = pList; /* merge nodes into array */
while(pNode != NULL){
pNext = pNode->next;
pNode->next = NULL;
for(i = 0; (i < NUMLISTS) && (aList[i] != NULL); i++){
pNode = MergeLists(aList[i], pNode);
aList[i] = NULL;
}
if(i == NUMLISTS) /* don't go beyond end of array */
i--;
aList[i] = pNode;
pNode = pNext;
}
pNode = NULL; /* merge array into one list */
for(i = 0; i < NUMLISTS; i++)
pNode = MergeLists(aList[i], pNode);
return pNode;
}
/* merge two already sorted lists */
/* compare uses pSrc2 < pSrc1 to follow the STL rule */
/* of only using < and not <= */
NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL; /* destination head ptr */
NODE **ppDst = &pDst; /* ptr to head or prev->next */
if(pSrc1 == NULL)
return pSrc2;
if(pSrc2 == NULL)
return pSrc1;
while(1){
if(pSrc2->data < pSrc1->data){ /* if src2 < src1 */
*ppDst = pSrc2;
pSrc2 = *(ppDst = &(pSrc2->next));
if(pSrc2 == NULL){
*ppDst = pSrc1;
break;
}
} else { /* src1 <= src2 */
*ppDst = pSrc1;
pSrc1 = *(ppDst = &(pSrc1->next));
if(pSrc1 == NULL){
*ppDst = pSrc2;
break;
}
}
}
return pDst;
}
Visual Studio 2015 changed std::list::sort to be based on iterators instead of lists, and also changed to a top down merge sort, which requires the overhead of scanning. I initially assumed that the switch to top down was needed to work with the iterators, but when it was asked about again, I investigated this and determined that the switch to the slower top down method was not needed, and bottom up could be implemented using the same iterator based logic. The answer in this link explains this and provide a stand-alone example as well as a replacement for VS2019's std::list::sort() in the include file "list".
`std::list<>::sort()` - why the sudden switch to top-down strategy?
This is the entire Piece of code which shows how we can create linklist in java and sort it using Merge sort. I am creating node in MergeNode class and there is another class MergesortLinklist where there is divide and merge logic.
class MergeNode {
Object value;
MergeNode next;
MergeNode(Object val) {
value = val;
next = null;
}
MergeNode() {
value = null;
next = null;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public MergeNode getNext() {
return next;
}
public void setNext(MergeNode next) {
this.next = next;
}
#Override
public String toString() {
return "MergeNode [value=" + value + ", next=" + next + "]";
}
}
public class MergesortLinkList {
MergeNode head;
static int totalnode;
public MergeNode getHead() {
return head;
}
public void setHead(MergeNode head) {
this.head = head;
}
MergeNode add(int i) {
// TODO Auto-generated method stub
if (head == null) {
head = new MergeNode(i);
// System.out.println("head value is "+head);
return head;
}
MergeNode temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = new MergeNode(i);
return head;
}
MergeNode mergesort(MergeNode nl1) {
// TODO Auto-generated method stub
if (nl1.next == null) {
return nl1;
}
int counter = 0;
MergeNode temp = nl1;
while (temp != null) {
counter++;
temp = temp.next;
}
System.out.println("total nodes " + counter);
int middle = (counter - 1) / 2;
temp = nl1;
MergeNode left = nl1, right = nl1;
int leftindex = 0, rightindex = 0;
if (middle == leftindex) {
right = left.next;
}
while (leftindex < middle) {
leftindex++;
left = left.next;
right = left.next;
}
left.next = null;
left = nl1;
System.out.println(left.toString());
System.out.println(right.toString());
MergeNode p1 = mergesort(left);
MergeNode p2 = mergesort(right);
MergeNode node = merge(p1, p2);
return node;
}
MergeNode merge(MergeNode p1, MergeNode p2) {
// TODO Auto-generated method stub
MergeNode L = p1;
MergeNode R = p2;
int Lcount = 0, Rcount = 0;
MergeNode tempnode = null;
while (L != null && R != null) {
int val1 = (int) L.value;
int val2 = (int) R.value;
if (val1 > val2) {
if (tempnode == null) {
tempnode = new MergeNode(val2);
R = R.next;
} else {
MergeNode store = tempnode;
while (store.next != null) {
store = store.next;
}
store.next = new MergeNode(val2);
R = R.next;
}
} else {
if (tempnode == null) {
tempnode = new MergeNode(val1);
L = L.next;
} else {
MergeNode store = tempnode;
while (store.next != null) {
store = store.next;
}
store.next = new MergeNode(val1);
L = L.next;
}
}
}
MergeNode handle = tempnode;
while (L != null) {
while (handle.next != null) {
handle = handle.next;
}
handle.next = L;
L = null;
}
// Copy remaining elements of L[] if any
while (R != null) {
while (handle.next != null) {
handle = handle.next;
}
handle.next = R;
R = null;
}
System.out.println("----------------sorted value-----------");
System.out.println(tempnode.toString());
return tempnode;
}
public static void main(String[] args) {
MergesortLinkList objsort = new MergesortLinkList();
MergeNode n1 = objsort.add(9);
MergeNode n2 = objsort.add(7);
MergeNode n3 = objsort.add(6);
MergeNode n4 = objsort.add(87);
MergeNode n5 = objsort.add(16);
MergeNode n6 = objsort.add(81);
MergeNode n7 = objsort.add(21);
MergeNode n8 = objsort.add(16);
MergeNode n9 = objsort.add(99);
MergeNode n10 = objsort.add(31);
MergeNode val = objsort.mergesort(n1);
System.out.println("===============sorted values=====================");
while (val != null) {
System.out.println(" value is " + val.value);
val = val.next;
}
}
}
I don't see any C++ solutions posted here. So, here it goes. Hope it helps someone.
class Solution {
public:
ListNode *merge(ListNode *left, ListNode *right){
ListNode *head = NULL, *temp = NULL;
// Find which one is the head node for the merged list
if(left->val <= right->val){
head = left, temp = left;
left = left->next;
}
else{
head = right, temp = right;
right = right->next;
}
while(left && right){
if(left->val <= right->val){
temp->next = left;
temp = left;
left = left->next;
}
else{
temp->next = right;
temp = right;
right = right->next;
}
}
// If some elements still left in the left or the right list
if(left)
temp->next = left;
if(right)
temp->next = right;
return head;
}
ListNode* sortList(ListNode* head){
if(!head || !head->next)
return head;
// Find the length of the list
int length = 0;
ListNode *temp = head;
while(temp){
length++;
temp = temp->next;
}
// Reset temp
temp = head;
// Store half of it in left and the other half in right
// Create two lists and sort them
ListNode *left = temp, *prev = NULL;
int i = 0, mid = length / 2;
// Left list
while(i < mid){
prev = temp;
temp = temp->next;
i++;
}
// The end of the left list should point to NULL
if(prev)
prev->next = NULL;
// Right list
ListNode *right = temp;
// Sort left list
ListNode *sortedLeft = sortList(left);
// Sort right list
ListNode *sortedRight = sortList(right);
// Merge them
ListNode *sortedList = merge(sortedLeft, sortedRight);
return sortedList;
}
};
Here is the Java Implementation of Merge Sort on Linked List:
Time Complexity: O(n.logn)
Space Complexity: O(1) - Merge sort implementation on Linked List avoids the O(n) auxiliary storage cost normally associated with the
algorithm
class Solution
{
public ListNode mergeSortList(ListNode head)
{
if(head == null || head.next == null)
return head;
ListNode mid = getMid(head), second_head = mid.next; mid.next = null;
return merge(mergeSortList(head), mergeSortList(second_head));
}
private ListNode merge(ListNode head1, ListNode head2)
{
ListNode result = new ListNode(0), current = result;
while(head1 != null && head2 != null)
{
if(head1.val < head2.val)
{
current.next = head1;
head1 = head1.next;
}
else
{
current.next = head2;
head2 = head2.next;
}
current = current.next;
}
if(head1 != null) current.next = head1;
if(head2 != null) current.next = head2;
return result.next;
}
private ListNode getMid(ListNode head)
{
ListNode slow = head, fast = head.next;
while(fast != null && fast.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
Hey I know that this is a bit late an answer but got a fast simple one.
The code is in F# but will goes in any language. Since this is an uncommen language of the ML family, I'll give some point to enhance the readability.
F# are nesting done by tabulating. the last line of code in a function (nested part) are the return value. (x, y) is a tuple, x::xs is a list of the head x and tail xs (where xs can be empty), |> take the result of last line an pipe it as argument to the expression right of it (readability enhancing) and last (fun args -> some expression) are a lambda function.
// split the list into a singleton list
let split list = List.map (fun x -> [x]) lst
// takes to list and merge them into a sorted list
let sort lst1 lst2 =
// nested function to hide accumulator
let rec s acc pair =
match pair with
// empty list case, return the sorted list
| [], [] -> List.rev acc
| xs, [] | [], xs ->
// one empty list case,
// append the rest of xs onto acc and return the sorted list
List.fold (fun ys y -> y :: ys) acc xs
|> List.rev
// general case
| x::xs, y::ys ->
match x < y with
| true -> // cons x onto the accumulator
s (x::acc) (xs,y::ys)
| _ ->
// cons y onto the accumulator
s (y::acc) (x::xs,ys)
s [] (lst1, lst2)
let msort lst =
let rec merge acc lst =
match lst with
| [] ->
match acc with
| [] -> [] // empty list case
| _ -> merge [] acc
| x :: [] -> // single list case (x is a list)
match acc with
| [] -> x // since acc are empty there are only x left, hence x are the sorted list.
| _ -> merge [] (x::acc) // still need merging.
| x1 :: x2 :: xs ->
// merge the lists x1 and x2 and add them to the acummulator. recursiv call
merge (sort x1 x2 :: acc) xs
// return part
split list // expand to singleton list list
|> merge [] // merge and sort recursively.
It is important to notice that this is fully tail recursive so no possibility of stack overflow, and by first expanding the list to a singleton list list in one go we, lower the constant factor on the worst cost. Since merge are working on list of list, we can recursively merge and sort the inner list until we get to the fix point where all inner list are sorted into one list and then we return that list, hence collapsing from a list list to a list again.
Here is the solution using Swift Programming Language.
//Main MergeSort Function
func mergeSort(head: Node?) -> Node? {
guard let head = head else { return nil }
guard let _ = head.next else { return head }
let middle = getMiddle(head: head)
let left = head
let right = middle.next
middle.next = nil
return merge(left: mergeSort(head: left), right: mergeSort(head: right))
}
//Merge Function
func merge(left: Node?, right: Node?) -> Node? {
guard let left = left, let right = right else { return nil}
let dummyHead: Node = Node(value: 0)
var current: Node? = dummyHead
var currentLeft: Node? = left
var currentRight: Node? = right
while currentLeft != nil && currentRight != nil {
if currentLeft!.value < currentRight!.value {
current?.next = currentLeft
currentLeft = currentLeft!.next
} else {
current?.next = currentRight
currentRight = currentRight!.next
}
current = current?.next
}
if currentLeft != nil {
current?.next = currentLeft
}
if currentRight != nil {
current?.next = currentRight
}
return dummyHead.next!
}
And here are the Node Class & getMiddle Method
class Node {
//Node Class which takes Integers as value
var value: Int
var next: Node?
init(value: Int) {
self.value = value
}
}
func getMiddle(head: Node) -> Node {
guard let nextNode = head.next else { return head }
var slow: Node = head
var fast: Node? = head
while fast?.next?.next != nil {
slow = slow.next!
fast = fast!.next?.next
}
return slow
}
public int[] msort(int[] a) {
if (a.Length > 1) {
int min = a.Length / 2;
int max = min;
int[] b = new int[min];
int[] c = new int[max]; // dividing main array into two half arrays
for (int i = 0; i < min; i++) {
b[i] = a[i];
}
for (int i = min; i < min + max; i++) {
c[i - min] = a[i];
}
b = msort(b);
c = msort(c);
int x = 0;
int y = 0;
int z = 0;
while (b.Length != y && c.Length != z) {
if (b[y] < c[z]) {
a[x] = b[y];
//r--
x++;
y++;
} else {
a[x] = c[z];
x++;
z++;
}
}
while (b.Length != y) {
a[x] = b[y];
x++;
y++;
}
while (c.Length != z) {
a[x] = c[z];
x++;
z++;
}
}
return a;
}

Resources