Merging Two Trees [duplicate] - c#

Does anyone know of an algorithm that will merge treenodes in the following way?
treeA
\ child a
\node(abc)
\ child b
\node(xyz)
+
treeB
\ child a
\node(qrs)
\ child b
\node(xyz)
\node(pdq)
\ child c
\node(pdq)
= // do merge
treeMerged
\ child a
\node(abc)
\node(qrs)
\ child b
\node(xyz)
\node(pdq)
\ child c
\node(pdq)
Any help would be greatly appreciated.

Well, once I actually took the time to think about it, the solution turns out to be far more simple than I anticipated. (I've posted the critical part of the code below)
private TreeNode DoMerge(TreeNode source, TreeNode target) {
if (source == null || target == null) return null;
foreach (TreeNode n in source.Nodes) {
// see if there is a match in target
var match = FindNode(n, target.Nodes); // match paths
if (match == null) { // no match was found so add n to the target
target.Nodes.Add(n);
} else {
// a match was found so add the children of match
DoMerge(n, match);
}
}
return target;
}
Still interested to know if someone has a better solution?

Ok, I'll admit, when I first started messing with this, I didn't think it would be too hard, so I figured I'll try to do it using LINQ. It came out to be nuts, but it works. I'm SURE there are more elegant and efficient algorithms, but here it is!
First, I have a ToEnumerable extension method on the TreeNodeCollection class:
public static class TreeNodeCollectionExtensions
{
public static IEnumerable<TreeNode> ToEnumerable(this TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
yield return node;
}
}
}
Then, I implement a custom comparer:
public class TreeNodeComparer : IEqualityComparer
{
public bool Equals(TreeNode x, TreeNode y)
{
return x.Text == y.Text;
}
public int GetHashCode(TreeNode obj)
{
return obj.Text.GetHashCode();
}
}
And finally, the crazyness:
private TreeView MergeTreeViews(TreeView tv1, TreeView tv2)
{
var result = new TreeView();
foreach (TreeNode node in tv2.Nodes)
{
result.Nodes.Add(node.Clone() as TreeNode);
}
foreach (TreeNode node in tv1.Nodes)
{
var nodeOnOtherSide = result.Nodes.ToEnumerable()
.SingleOrDefault(tr => tr.Text == node.Text);
if (nodeOnOtherSide == null)
{
TreeNode clone = node.Clone() as TreeNode;
result.Nodes.Add(clone);
}
else
{
var n = node.Nodes.ToEnumerable()
.Where(t => !(nodeOnOtherSide.Nodes.ToEnumerable()
.Contains(t, new TreeNodeComparer())));
foreach (TreeNode subNode in n)
{
TreeNode clone = subNode.Clone() as TreeNode;
nodeOnOtherSide.Nodes.Add(clone);
}
}
}
return result;
}
The way I coded it was that it returns a third "merged" treeView. You can change the code, so that it takes a third treeview as a parameter, so that you can pass in a treeView you may already have.
Again, I'm SURE there are better way to do this, but it SHOULD work.
One more thing I'd like to point out, this will only work for a TreeView that is two layers deep.

I came up with this recursive example, works perfect in C# (have been using it myself), note that you'll need to find a way to convert TreeNode.Nodes to an array:
public static TreeNode[] mergeTrees(TreeNode[] target, TreeNode[] source)
{
if (source == null || source.Length == 0)
{
return target;
}
if (target == null || target.Length == 0)
{
return source;
}
bool found;
foreach (TreeNode s in source)
{
found = false;
foreach (TreeNode t in target)
{
if (s.Text.CompareTo(t.Text) == 0)
{
found = true;
TreeNode[] updatedNodes = mergeTrees(Util.treeView2Array(t.Nodes), Util.treeView2Array(s.Nodes));
t.Nodes.Clear();
t.Nodes.AddRange(updatedNodes);
break;
}
}
if (!found)
{
TreeNode[] newNodes = new TreeNode[target.Length + 1];
Array.Copy(target, newNodes, target.Length);
newNodes[target.Length] = s;
target = newNodes;
}
}
return target;
}

If you are using the Node.Name attribute to set the actual path of the item, then a merge is somewhat simple.
First, create a TreeNodeCollection extension like so (this is needed to have a Case Sensitive Find() method for the TreeNodeCollection, which ensures that the Unique Path can be unique by Case as well) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TreeViewApp
{
public static class TreeNodeCollectionExtensions
{
public static TreeNode[] FindExact(this TreeNodeCollection coll, string keytofind)
{
TreeNode[] retval;
if (String.IsNullOrWhiteSpace(keytofind) || coll == null)
{
retval = new TreeNode[0];
}
else
{
TreeNode[] badfinds = coll.Find(keytofind, true);
List<TreeNode> goodfinds = new List<TreeNode>();
foreach (TreeNode bad in badfinds)
{
if (bad.Name == keytofind)
goodfinds.Add(bad);
}
retval = goodfinds.ToArray();
}
return retval;
}
}
}
Second, fill a treeview with your Source nodes...
Thrid, fill a treeview with your Target nodes...
Fourth, create an empty treeview.
and then, it's as simple as this:
private void btn_Merge_Click(object sender, EventArgs e)
{
//first merge
foreach (TreeNode sourceNode in this.treeview_Source.Nodes)
{
FindOrAdd(sourceNode, ref this.treeview_Merged);
}
//second merge
foreach (TreeNode targetNode in this.treeview_Target.Nodes)
{
FindOrAdd(targetNode, ref this.treeview_Merged);
}
}
private void FindOrAdd(TreeNode FindMe, ref TreeView InHere)
{
TreeNode[] found = InHere.Nodes.FindExact(FindMe.Name);
//if the node is not found, add it at the proper location.
if (found.Length == 0)
{
if (FindMe.Parent != null)
{
TreeNode[] foundParent = InHere.Nodes.FindExact(FindMe.Parent.Name);
if (foundParent.Length == 0)
InHere.Nodes.Add((TreeNode)FindMe.Clone());
else
foundParent[0].Nodes.Add((TreeNode)FindMe.Clone());
}
else
InHere.Nodes.Add((TreeNode)FindMe.Clone());
}
else
{
//if the item was found, check all children.
foreach (TreeNode child in FindMe.Nodes)
FindOrAdd(child, ref InHere);
}
}
Once again, this solution only works if you have unique paths... with the extension, it also accounts for uniqueness at the case level.
I posted this here in the hopes of helping someone who, like me, had to search for a solution for days on end without success and had to build my own.

Related

fastest starts with search algorithm

I need to implement a search algorithm which only searches from the start of the string rather than anywhere within the string.
I am new to algorithms but from what I can see it seems as though they go through the string and find any occurrence.
I have a collection of strings (over 1 million) which need to be searched everytime the user types a keystroke.
EDIT:
This will be an incremental search. I currently have it implemented with the following code and my searches are coming back ranging between 300-700ms from over 1 million possible strings. The collection isnt ordered but there is no reason it couldnt be.
private ICollection<string> SearchCities(string searchString) {
return _cityDataSource.AsParallel().Where(x => x.ToLower().StartsWith(searchString)).ToArray();
}
I've adapted the code from this article from Visual Studio Magazine that implements a Trie.
The following program demonstrates how to use a Trie to do fast prefix searching.
In order to run this program, you will need a text file called "words.txt" with a large list of words. You can download one from Github here.
After you compile the program, copy the "words.txt" file into the same folder as the executable.
When you run the program, type a prefix (such as prefix ;)) and press return, and it will list all the words beginning with that prefix.
This should be a very fast lookup - see the Visual Studio Magazine article for more details!
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
var trie = new Trie();
trie.InsertRange(File.ReadLines("words.txt"));
Console.WriteLine("Type a prefix and press return.");
while (true)
{
string prefix = Console.ReadLine();
if (string.IsNullOrEmpty(prefix))
continue;
var node = trie.Prefix(prefix);
if (node.Depth == prefix.Length)
{
foreach (var suffix in suffixes(node))
Console.WriteLine(prefix + suffix);
}
else
{
Console.WriteLine("Prefix not found.");
}
Console.WriteLine();
}
}
static IEnumerable<string> suffixes(Node parent)
{
var sb = new StringBuilder();
return suffixes(parent, sb).Select(suffix => suffix.TrimEnd('$'));
}
static IEnumerable<string> suffixes(Node parent, StringBuilder current)
{
if (parent.IsLeaf())
{
yield return current.ToString();
}
else
{
foreach (var child in parent.Children)
{
current.Append(child.Value);
foreach (var value in suffixes(child, current))
yield return value;
--current.Length;
}
}
}
}
public class Node
{
public char Value { get; set; }
public List<Node> Children { get; set; }
public Node Parent { get; set; }
public int Depth { get; set; }
public Node(char value, int depth, Node parent)
{
Value = value;
Children = new List<Node>();
Depth = depth;
Parent = parent;
}
public bool IsLeaf()
{
return Children.Count == 0;
}
public Node FindChildNode(char c)
{
return Children.FirstOrDefault(child => child.Value == c);
}
public void DeleteChildNode(char c)
{
for (var i = 0; i < Children.Count; i++)
if (Children[i].Value == c)
Children.RemoveAt(i);
}
}
public class Trie
{
readonly Node _root;
public Trie()
{
_root = new Node('^', 0, null);
}
public Node Prefix(string s)
{
var currentNode = _root;
var result = currentNode;
foreach (var c in s)
{
currentNode = currentNode.FindChildNode(c);
if (currentNode == null)
break;
result = currentNode;
}
return result;
}
public bool Search(string s)
{
var prefix = Prefix(s);
return prefix.Depth == s.Length && prefix.FindChildNode('$') != null;
}
public void InsertRange(IEnumerable<string> items)
{
foreach (string item in items)
Insert(item);
}
public void Insert(string s)
{
var commonPrefix = Prefix(s);
var current = commonPrefix;
for (var i = current.Depth; i < s.Length; i++)
{
var newNode = new Node(s[i], current.Depth + 1, current);
current.Children.Add(newNode);
current = newNode;
}
current.Children.Add(new Node('$', current.Depth + 1, current));
}
public void Delete(string s)
{
if (!Search(s))
return;
var node = Prefix(s).FindChildNode('$');
while (node.IsLeaf())
{
var parent = node.Parent;
parent.DeleteChildNode(node.Value);
node = parent;
}
}
}
}
A couple of thoughts:
First, your million strings need to be ordered, so that you can "seek" to the first matching string and return strings until you no longer have a match...in order (seek via C# List<string>.BinarySearch, perhaps). That's how you touch the least number of strings possible.
Second, you should probably not try to hit the string list until there's a pause in input of at least 500 ms (give or take).
Third, your queries into the vastness should be async and cancelable, because it's certainly going to be the case that one effort will be superseded by the next keystroke.
Finally, any subsequent query should first check that the new search string is an append of the most recent search string...so that you can begin your subsequent seek from the last seek (saving lots of time).
I suggest using linq.
string x = "searchterm";
List<string> y = new List<string>();
List<string> Matches = y.Where(xo => xo.StartsWith(x)).ToList();
Where x is your keystroke search text term, y is your collection of strings to search, and Matches is the matches from your collection.
I tested this with the first 1 million prime numbers, here is the code adapted from above:
Stopwatch SW = new Stopwatch();
SW.Start();
string x = "2";
List<string> y = System.IO.File.ReadAllText("primes1.txt").Split(' ').ToList();
y.RemoveAll(xo => xo == " " || xo == "" || xo == "\r\r\n");
List <string> Matches = y.Where(xo => xo.StartsWith(x)).ToList();
SW.Stop();
Console.WriteLine("matches: " + Matches.Count);
Console.WriteLine("time taken: " + SW.Elapsed.TotalSeconds);
Console.Read();
Result is:
matches: 77025
time taken: 0.4240604
Of course this is testing against numbers and I don't know whether linq converts the values before, or if numbers make any difference.

What can I do to improve the following code so that the result is a single `TreeView.AddRange()`

Just doing some final optimizations on my custom TreeView control, and it looks like I can optimize the load method a bit further. Here is the segment I am focused on which I feel can be optimized by building all the TreeNodes first, and then using a single TreeView.AddRange( nodes[] ) method.
// Create hierarchy and load into view
foreach (var id in _treeNodes.Keys)
{
var node = GetNode(id);
var obj = (T)node.Tag;
var parentId = getParentId(obj);
if (parentId.HasValue)
{
var parentNode = GetNode(parentId.Value);
if(parentNode == null)
{
Invoke((MethodInvoker)(() => Nodes.Add(node)));
} else
{
Invoke((MethodInvoker)(() => parentNode.Nodes.Add(node)));
}
}
else
{
Invoke((MethodInvoker)(() => Nodes.Add(node)));
}
}
_treeNodes is Dictionary<ulong, TreeNode>
GetNode() is :
if(_treeNodes.ContainsKey(id))
{
return _treeNodes[id];
} else
{
return null;
}
getParentId() is a delegate Func<NtfsUsnJournal.UsnEntry, ulong?> getParentId = (x => x.ParentFileReferenceNumber)
The code currently gets all the values from a dictionary list which is all the directories in the NTFS Journal, which happens very fast. The delay is that on each Node and the children nodes, it is being added to the TreeView directly.
What I would like to do, is build a list of root Nodes (containing all child nodes of course), and then pass that as an array of TreeNode[] to the .AddRange( TreeNode[] ) method in a single Invoke().
How can this code be modified to accomplish this ?
Figured it out, answer was staring me in the face :
List<TreeNode> _t = new List<TreeNode>();
foreach (var id in _treeNodes.Keys)
{
var node = GetNode(id);
var obj = (T)node.Tag;
var parentId = getParentId(obj);
if (parentId.HasValue)
{
var parentNode = GetNode(parentId.Value);
if(parentNode == null)
{
_t.Add(node);
} else
{
parentNode.Nodes.Add(node);
}
}
else
{
_t.Add(node);
}
}
Invoke((MethodInvoker)(() => Nodes.AddRange(_t.ToArray())));

Is ther any way to get access to a treeview node by giving number of node

I know that by using a tag or text one could search for a node and find it.
treeview1.Find(string name, bool searchAllChildren)
But in my code I have a for loop over integer number that does some computation and then I would like to copy the i-th node of a treeview to a new node. For example I want to give i = 3 and it should give me node5 with all children.
Lets we have a structure like the following figure in XML. My aim is to generate a treeview in the following way.
First, copy all nodes and children till nodeIV, then copy the nodes node1, .... node7 and save them under a condition, otherwise creat empty node instead.
-root
-nodeI
-nodeII
-nodeIII
-nodeIV
-node1
-children1
-children2
-children3
-node2
-node3
-childrenA
-childrenB
-childrenC
-node4
-node5
-node6
-children
-node7
-childrenG
-childrenR1
-childrenR2
-childrenR3
-children
Is there such a way or just only one can get access to a node by doing,
First, instead of reinventing the wheel, I would take the helper function from my answer to How to flatten tree via LINQ? which is very useful for any tree like structures:
public static class TreeUtils
{
public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
{
var stack = new Stack<IEnumerator<T>>();
var e = source.GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
yield return item;
var elements = elementSelector(item);
if (elements == null) continue;
stack.Push(e);
e = elements.GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
Then I would create a couple TreeView specific helpers:
public static class TreeViewUtils
{
public static IEnumerable<TreeNode> AsEnumerable(this TreeNodeCollection source)
{
return source.Cast<TreeNode>();
}
public static IEnumerable<TreeNode> All(this TreeNodeCollection source)
{
return source.AsEnumerable().Expand(node => node.Nodes.Count > 0 ? node.Nodes.AsEnumerable() : null);
}
public static TreeNode Find(this TreeNodeCollection source, int index)
{
return source.All().Skip(index).FirstOrDefault();
}
}
Now to get the i-th node of the tree view you can simply use
var node = treeview1.Nodes.Find(i);
Additionally you can get the i-th child node of any node like this
var childNode = node.Nodes.Find(i);
To conclude, I've could easily provided a recursive function that just solves the specific question with less code, but this little utility functions give you much more - foreach support, all nodes of a subtree DFT traversal, LINQ queries (like searching by Tag or some other criteria) etc.
UPDATE
Strange requirement nowadays, but here is the "raw" C# function (no LINQ, no extension methods, no iterator methods) doing just what you need
public static class TreeViewUtils
{
public static TreeNode FindNode(TreeNodeCollection nodes, int index)
{
int offset = -1;
return FindNode(nodes, ref offset, index);
}
private static TreeNode FindNode(TreeNodeCollection nodes, ref int offset, int index)
{
for (int i = 0; i < nodes.Count; i++)
{
var node = nodes[i];
if (++offset == index || (node = FindNode(node.Nodes, ref offset, index)) != null)
return node;
}
return null;
}
}
and the respective usage
var node = TreeViewUtils.FindNode(treeview1.Nodes, i);
or
var childNode = TreeViewUtils.FindNode(node.Nodes, i);

Bin Tree Post Order Traversal, No recursion, no node flag

Is there another way to do this? Just spent 2 hours trying to figure it out. I have a solution (see DumpPostOrder below) however, is there is a better or more efficient method? It feels like there may be. Rules are - no recursion, and the nodes cannot have a visited flag. Ie, you can only use left + right members.
My approach was to destroy the tree in the process. By setting the children of each side to null you can mark the node as traversed once, but I'm also looking at each node with children twice :(. Is there a better faster way? (Comments on my preorder and inorder implementations are appreciated but not necessary (ie, will vote, but not mark answer). Thanks!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BinaryTreeNoRecursion
{
public class TreeNode<T>
{
public T Value { get; set; }
public TreeNode<T> Left { get; set; }
public TreeNode<T> Right { get; set; }
public TreeNode(T inValue)
{
Value = inValue;
}
public TreeNode(TreeNode<T> left, TreeNode<T> right, T inValue)
{
Left = left;
Right = right;
Value = inValue;
}
}
public class BinaryTree<T>
{
private TreeNode<T> root;
public TreeNode<T> Root
{
get { return root; }
}
public BinaryTree(TreeNode<T> inRoot)
{
root = inRoot;
}
public void DumpPreOrder(T[] testme)
{
Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
stack.Push(root);
int count =0;
while (true)
{
if (stack.Count == 0) break;
TreeNode<T> temp = stack.Pop();
if (!testme[count].Equals(temp.Value)) throw new Exception("fail");
if (temp.Right != null)
{
stack.Push(temp.Right);
}
if (temp.Left != null)
{
stack.Push(temp.Left);
}
count++;
}
}
public void DumpPostOrder(T[] testme)
{
Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
TreeNode<T> node = root;
TreeNode<T> temp;
int count = 0;
while(node!=null || stack.Count!=0)
{
if (node!=null)
{
if (node.Left!=null)
{
temp = node;
node = node.Left;
temp.Left = null;
stack.Push(temp);
}
else
if (node.Right !=null)
{
temp = node;
node = node.Right;
temp.Right= null;
stack.Push(temp);
}
else //if the children are null
{
if (!testme[count].Equals(node.Value)) throw new Exception("fail");
count++;
if (stack.Count != 0)
{
node = stack.Pop();
}
else
{
node = null;
}
}
}
}
}
public void DumpInOrder(T[] testme)
{
Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
TreeNode<T> temp = root;
int count = 0;
while (stack.Count!=0 || temp!=null)
{
if (temp != null)
{
stack.Push(temp);
temp = temp.Left;
}
else
{
temp = stack.Pop();
if (!testme[count].Equals(temp.Value)) throw new Exception("fail");
count++;
temp = temp.Right;
}
}
}
}
class Program
{
static void Main(string[] args)
{
//create a simple tree
TreeNode<int> node = new TreeNode<int>(100);
node.Left = new TreeNode<int>(50);
node.Right = new TreeNode<int>(150);
node.Left.Left = new TreeNode<int>(25);
node.Left.Right = new TreeNode<int>(75);
node.Right.Left = new TreeNode<int>(125);
node.Right.Right = new TreeNode<int>(175);
node.Right.Left.Left = new TreeNode<int>(110);
int[] preOrderResult = { 100, 50, 25, 75, 150, 125, 110, 175};
int[] inOrderResult = { 25, 50, 75, 100, 110, 125, 150, 175};
int[] postOrderResult = { 25, 75, 50, 110, 125, 175, 150, 100 };
BinaryTree<int> binTree = new BinaryTree<int>(node);
//do the dumps, verify output
binTree.DumpPreOrder(preOrderResult);
binTree.DumpInOrder(inOrderResult);
binTree.DumpPostOrder(postOrderResult);
}
}
}
Seems to me that destroying the tree while traversing it is pretty brutal.
You are currently building a Collection of nodes visited.
You are marking nodes as visited by setting them to null.
Could you not instead check for visitation by checking for the node in your Collection? For efficiency you may need to not use a Stack, but that's an implementation detail.
You could map your binary tree to an array (similar to how you can map a heap to an array, as shown here), and do your post-order traversal there. The action of converting a binary tree to an array is probably going to utilize recursion, but if you're controlling how the tree is initially constructed (or if you're just looking for an intriguing thought), you could just construct it as an array, and trivialize your non-recursive post-order traversal (with no flags) problem.
Edit
I think this would be a viable option:
1) Keep a bi-directional linked list of pointers to nodes in the tree.
2) Start at the root node.
3) Append root pointer to list.
4) Go to right child.
5) Append current node pointer to list.
6) Repeat steps 4 and 5 until there doesn't exist a right child.
7) Write current node to post-order-traversal.
8) Set current node to last node in the list.
9) Go to left child.
10) Append current note pointer to list.
11) Repeat steps 4 through 10 until the list is empty.
Basically, this makes all of the nodes in the tree have a pointer to their parent.
Avoiding recursion in this case is probably a bad idea, as previously noted. The system call stack is designed to handle things like this. Destroying your tree is a form of marking nodes.
If you want to use your own stack, then you need to push a bit more more information than just the node. Remember that the system call stack contains the program counter as well as the function parameters (local variables as well bu that is not important here). We could push tuples of the form (PushMyChildren, node), (PrintMe, Node), and when we pop a node of the form (PushMyChildren, node) we push (PrintMe, Node), then (PushMyChildren, right child) and then (PushMyChildren, left child). If the left and right children don't exist don't push them. When we pop a node of the form (PrintMe, Node) we print the node. In pseudo C# (I don't know C# and don't have time to look up the correct types and Syntax).
public void DumpPostOrder(T[] testme)
{
enum StackState {printNode, pushChildren}
Stack< Pair<StackState, TreeNode<T> > > stack = new Stack< Tuple<StackState, TreeNode<T> > >();
stack.Push(new Pair(pushChildren, root);
while ( stack.Count != 0 ) {
Pair<StackState, TreeNode<T> > curr = stack.pop();
if (curr.First == printNode) {
// process the node in curr.Second
} else {
node = curr.Second;
stack.Push(new Pair(printNode, node));
if (node.Right != null) {
stack.Push(new Pair(pushChildren, node.Right))
}
if (node.Left != null) {
stack.Push(new Pair(pushChildren, node.Left))
}
}
}
I just made post-order in Java using traversal to width (using queue).
private void init(){
if (initialized) return;
stack = new Stack<>();
stack.push(root);
travers(root.right);
travers(root.left);
initialized = true;
}
private void travers(Node node){
if (node == null) return;
Queue<Node> queue = new LinkedList<>();
queue.add(node);
while (!queue.isEmpty()){
Node temp = queue.poll();
stack.push(temp);
if (temp.right != null) queue.add(temp.right);
if (temp.left != null) queue.add(temp.left);
}
}
public T next() {
return stack.pop().data;
}

Reverse a single chained List

I hope I am using the right terminology.
I have made a single-chained list.
class MyStack
{
public Node Initial { get; set; }
public MyStack()
{
Initial = null;
}
public void Push(int data)
{
var node = new Node { Data = data, Next = Initial };
Initial = node;
}
public int Pop()
{
int res = Initial.Data;
Initial = Initial.Next;
return res;
}
public int Sum()
{
int sum = 0;
Node currentNode = Initial;
while (currentNode != null)
{
sum += currentNode.Data;
currentNode = currentNode.Next;
}
return sum;
}
public int Count()
{
int count = 0;
Node currentNode = Initial;
while (currentNode != null)
{
count++;
currentNode = currentNode.Next;
}
return count;
}
public void PrintAll()
{
Node currentNode = Initial;
while(currentNode != null)
{
Console.WriteLine("tmp.Data = " + currentNode.Data);
currentNode = currentNode.Next;
}
}
}
public class Node
{
public int Data;
public Node Next;
}
Meaning you can do something like this:
var s = new MyStack();
s.Push(5);
s.Push(3);
s.Push(7);
s.PrintAll();
Console.WriteLine("Sum: " + s.Sum());
Console.WriteLine("Count: " + s.Count());
Now, I want to try and make a Reverse method. This seems to be working:
public void Reverse()
{
Node predesesor, location;
location = Initial;
predesesor = null;
while(Initial != null)
{
Initial = Initial.Next;
location.Next = predesesor;
predesesor = location;
location = Initial;
}
Initial = predesesor;
}
I am hardly able to see how it works, and it will be tough to maintain.
It seems more like a hack than anything else.
Can you offer any assistance?
It doesn't seem like a hack to me and I don't see what's there to maintain (it is either correct or not, what else would you do with it?). If you want to figure out how it works, "execute" each step on paper. Draw a list (e.g 1 -> 3 -> 5 -> 7 -> 9 -> NULL), mark out where all Nodes point at any time and start "single-stepping".
I couldn't think of a cleaner way to reverse a singly linked list. You need a reference to the next node (Initial at the beginning of the loop), before you can reverse the link between current node and previous node. You just won't be able to move on in the original list otherwise.
What you could do is fix the spelling of the variables and perhaps not use Initial in the loop itself (use a third variable, so the role of each variable is clearer) and only set Initial to the first Node in the reversed list at the end.
So, all in all:
public void Reverse() {
Node current = Initial, previous = null;
while (current) {
Node next = current.Next;
current.Next = previous;
previous = current;
current = next;
}
Initial = previous;
}
One solution would be to turn it into a doubly-linked list, and then work backwards using the previous node property:
public class Node
{
public int Data;
public Node Next;
public Node Previous;
}
There is already a doubly-linked list in the framework if you want to save yourself some effort.
you can do it recursivly:
a->b->c->d
a->null
b->null
c->null
c<-d
b<-c
a<-b
a<-b<-c<-d
public void Reverse()
{
Reverse(Initial);
}
private void Reverse(Node node)
{
if(node != null && node.Next != null)
{
//go deeper
Reverse(node.Next);
//swap
node.Next.Next = node
node.Next = null;
}
}
Instead of reinventing the wheel you should check, if there is already something you can use something from .Net Framework.
For example i would take here the LinkedList with the LinkedListNode. In other cases you could probably take the Queue or a Stack.
If you call it "nreverse" or "reverse in place" then any developer worth tuppence would recognise it as a classic algorithm rather than a hack.
It shouldn't require much maintenance, except maybe renaming any incorrectly spelled variables.
The following code might be a bit more intuitive:
public void Reverse()
{
MyStack reverse = new MyStack();
while (Initial != null)
{
reverse.Push(this.Pop());
}
Initial = reverse.Initial;
}
(Reverse is a member method of the MyStack class).
Of course, it does require twice the space compared with the original code.
stack s1
s1.push_front(...)
...
s1.push_front(...)
////////////////////////////////////////////////////////
void reverse(stack& to,stack_or_list& s )
while(!s.empty()){
to.push_front(s.pop_front());
}
}
now a series of to.pop_fronts gets you what you want
stack_or_list needs: pop_front empty
to needs: push_front,pop_front

Categories