I wrote some code and have some problems, but the most important question is: why is the array not working with AddNode? I know I am close to solving this problem, but I hope for a little hint.
Next question: the code for Min and Max value is good. How can I move it to Class Node?
And the last question: how to make Class Depth for tree?
class Node
{
public Node LeftNode { get; set; }
public Node MiddleNode { get; set; }
public Node RightNode { get; set; }
public int Value { get; set; }
public void AddNode(int value)
{
if (value < this.Value)
{
if (LeftNode != null)
{
LeftNode.AddNode(value);
return;
}
LeftNode = new Node(value);
return;
}
if (value > Value)
{
if (RightNode != null)
{
RightNode.AddNode(value);
return;
}
RightNode = new Node(value);
return;
}
if (MiddleNode != null)
{
MiddleNode.AddNode(value);
return;
}
MiddleNode = new Node(value);
}
public Node(int value)
{
this.Value = value;
}
public override string ToString()
{
return $"Value: {Value}";
}
public string SortedString(Array arr)
{
Array.Sort(arr);
foreach (int val in arr)
{
Console.WriteLine(val);
}
return "";
}
public int ValueCount(int value)
{
if (value < Value)
{
if (LeftNode == null)
{
return -1;
}
return LeftNode.ValueCount(value);
}
if (value > Value)
{
if (RightNode == null)
{
return -1;
}
return RightNode.ValueCount(value);
}
if (MiddleNode != null)
{
return 1 + MiddleNode.ValueCount(value);
}
return 1;
}
internal int Next(int min, int max)
{
Random rnd = new Random();
return rnd.Next(min, max);
}
}
class Program
{
static void Main(string[] args)
{
var arr = new int[1000];
var rnd = new Node(1);
for (int i = 0; i < arr.Length; i++)
{
rnd.AddNode(arr[i]);
//Console.WriteLine(arr[i]);
}
for(int i = 0; i < arr.Length; i++)
{
arr[i] = rnd.Next(1, 100);
Console.WriteLine(arr[i]);
}
min = arr[0];
max = arr[0];
for (int i = 1; i < arr.Length; i++)
{
if (min > arr[i])
min = arr[i];
if (max < arr[i])
max = arr[i];
}
Console.WriteLine("największa liczba" + " " + max);
Console.WriteLine("najmniejsza liczba" + " " + min);
Array.Sort(arr);
foreach (int value in arr)
{
Console.WriteLine(value);
}
Console.WriteLine(rnd.ValueCount(6));
Console.WriteLine(rnd.ToString());
}
}
To be honest - your code is a bit confusing.
first of all - why do you have a pointer (ref) to a middle node ? A binary tree defines each node to have at most 2 children (left \ right).
If you wish to handle duplicate values you can either choose a strategy that defines one of the children to also includes equals, or better use ref count (e.g.: each node has both a value and a counter for this value).
re Min \ Max - if your tree is a BST (which it seems to be the case), you can easily implement this through simple tree traversing either to the left (for Min value) or to the right (for max value).
I've tried creating linked list/node classes and I'm not sure where to go next. My attempts haven't went well because after creating the classes I'm just not sure what the next step is.
I'm trying to create a program that has a dinosaur node which saves information about the dinosaur such as id, species etc and I want to allow the user to create and remove dinosaurs from the list. So I need to allow the user to input data, I assume there's a way to make dino id get set automatically but I'm not to sure.
I've included the LinkedList.cs and the Node.cs so you can see where I'm going but I have no idea what to do within my program class to utilise the linked list and achieve what I'm trying to do.
Added Program.cs class incase that helps identify/show where I am within the program/what I need to do.
Linked List Class:
using System;
using System.Collections.Generic;
using System.Runtime.ExceptionServices;
using System.Text;
namespace JurrasicFinal
{
public class LinkedList
{
private Node head;
private int count;
public LinkedList()
{
this.head = null;
this.count = 0;
}
public bool Empty
{
get { return this.count == 0; }
}
public int Count
{
get { return this.count; }
}
public object this[int index]
{
get { return this.Get(index); }
}
public object Add(int index, object o)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (index > count)
index = count;
Node current = this.head;
if (this.Empty || index == 0)
{
this.head = new Node(o, this.head);
}
else
{
for (int i = 0; i < index - 1; i++)
{
current = current.Next;
current.Next = new Node(o, current.Next);
}
}
count++;
return o;
}
public object Add(object o)
{
return this.Add(count, o);
}
public object Remove(int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (this.Empty)
return null;
if (index >= this.count)
index = count - 1;
Node current = this.head;
object result = null;
if (index == 0)
{
result = current.Data;
this.head = current.Next;
}
else
{
for (int i = 0; index < index - 1; i++) ;
current = current.Next;
result = current.Next.Data;
current.Next = current.Next.Next;
}
count--;
return result;
}
public void Clear()
{
this.head = null;
this.count = 0;
}
public int IndexOf(object o)
{
Node current = this.head;
for (int i = 0; i < this.count; i++)
{
if (current.Data.Equals(o))
return i;
current = current.Next;
}
return -1;
}
public bool Contains(object o)
{
return this.IndexOf(o) >= 0;
}
public object Get(int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (this.Empty)
return null;
if (index >= this.count)
index = this.count - 1;
Node current = this.head;
for (int i = 0; i < index; i++)
current = current.Next;
return current.Data;
}
}
}
Node Class:
using System;
using System.Collections.Generic;
using System.Text;
namespace JurrasicFinal
{
public class Node
{
private object data;
private Node next;
private string DinoSpecies;
private string DinoName;
public Node(object data, Node next)
{
this.data = data;
this.next = next;
}
public object Data
{
get { return this.data; }
set { this.data = value; }
}
public Node Next
{
get { return this.next; }
set { this.next = value; }
}
}
}
Program Class:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq.Expressions;
namespace JurrasicFinal
{
class Program
{
class Dinosaur
{
public string Name;
public string Classification;
public char Sex;
}
static void Main(string[] args)
{
LinkedList<Dinosaur> DinoList = new LinkedList<Dinosaur>();
Dinosaur Dino1 = new Dinosaur();
Dino1.Name = "Tyrannosaurus Rex";
Dino1.Classification = "Carnivorous";
Dino1.Sex = 'M';
Dinosaur Dino2 = new Dinosaur();
Dino2.Name = "Velociraptor";
Dino2.Classification = "Carnivorous";
Dino2.Sex = 'F';
Dinosaur Dino3 = new Dinosaur();
Dino3.Name = "Procompsognathus";
Dino3.Classification = "Carnivorous";
Dino3.Sex = 'M';
void printList()
{
Console.WriteLine("Current Queue: ");
Console.WriteLine("\n");
foreach (Dinosaur d in DinoList)
{
Console.WriteLine("Name: " + d.Name);
Console.WriteLine("Classification: " + d.Classification);
Console.WriteLine("Sex " + d.Sex);
Console.WriteLine("\n");
}
Console.WriteLine(Dino1.Name + Dino1.Sex);
}
DinoList.AddLast(Dino1);
DinoList.AddLast(Dino2);
DinoList.AddLast(Dino3);
printList();
Console.WriteLine(DinoList.Count);
FileStream fileStream = File.OpenWrite("E:/Work/Dinosaur.txt");
BinaryWriter writer = new BinaryWriter(fileStream);
foreach (Dinosaur d in DinoList)
{
writer.Write(d.Name);
writer.Write(d.Classification);
writer.Write(d.Sex);
}
writer.Close();
Console.WriteLine("Reading Back From File");
FileStream file = File.OpenRead("E:/Work/Dinosaur.txt");
BinaryReader reader = new BinaryReader(file);
for (int i = 1; i < 3; i++)
{
Dinosaur d = new Dinosaur();
d.Name = reader.ReadString();
d.Classification = reader.ReadString();
d.Sex = reader.ReadChar();
DinoList.AddLast(d);
}
reader.Close();
Console.ReadKey();
}
}
}
I think you might be looking for something like this, which hangs on user input and tries to do simple validation. I made it a bit overly complex to demonstrate some options.
class Sample
{
private static int index = 0;
static void Main(string[] args)
{
LinkedList<Dinosaur> DinoList = new LinkedList<Dinosaur>();
while (true)
{
var dino = new Dinosaur();
dino.Name = GetInput("Enter dino name (q to quit): ");
if (dino.Name == "q" || dino.Name == "Q")
{
break;
}
dino.Classification = GetInput("Enter dino classification: ");
char[] sexes = new char[] {'F', 'f', 'M', 'm'};
while (true)
{
Console.WriteLine("Enter dino sex (M/F): ");
dino.Sex = (char) Console.Read();
if (sexes.Contains(dino.Sex))
{
break;
}
}
int inputIndex = default;
while (true)
{
var indexString = GetInput($"Enter 0-index list position (max {DinoList.Count})");
inputIndex = Convert.ToInt32(indexString);
if (inputIndex <= DinoList.Count)
{
break;
}
}
DinoList.Add(inputIndex, dino);
index++;
Console.WriteLine("Dinosaurs:");
Console.WriteLine(new string('-', 30));
for (var i = 0; i < DinoList.Count; i++)
{
var dinosaur = (Dinosaur) DinoList.Get(i);
Console.WriteLine("Name: " + dinosaur.Name);
Console.WriteLine("Classification: " + dinosaur.Classification);
Console.WriteLine("Sex: " + dinosaur.Sex);
}
}
}
private static string GetInput(string prompt)
{
Console.WriteLine(prompt);
var input = Console.ReadLine();
while (string.IsNullOrWhiteSpace(input))
{
input = Console.ReadLine();
}
return input;
}
}
Note that you have to make your LinkedList and Node into LinkedList<T> and Node<T> but they converted directly, so it's just a bit of typing.
Hope it helps!
Edit: Add classes provided in question, modified to be generic.
public class Node<T>
{
private object data;
private Node<T> next;
private string DinoSpecies;
private string DinoName;
public Node(object data, Node<T> next)
{
this.data = data;
this.next = next;
}
public object Data
{
get { return this.data; }
set { this.data = value; }
}
public Node<T> Next
{
get { return this.next; }
set { this.next = value; }
}
}
public class LinkedList<T>
{
private Node<T> head;
private int count;
public LinkedList()
{
this.head = null;
this.count = 0;
}
public bool Empty
{
get { return this.count == 0; }
}
public int Count
{
get { return this.count; }
}
public object this[int index]
{
get { return this.Get(index); }
}
public object Add(int index, object o)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (index > count)
index = count;
Node<T> current = this.head;
if (this.Empty || index == 0)
{
this.head = new Node<T>(o, this.head);
}
else
{
for (int i = 0; i < index - 1; i++)
{
current = current.Next;
current.Next = new Node<T>(o, current.Next);
}
}
count++;
return o;
}
public object Add(object o)
{
return this.Add(count, o);
}
public object Remove(int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (this.Empty)
return null;
if (index >= this.count)
index = count - 1;
Node<T> current = this.head;
object result = null;
if (index == 0)
{
result = current.Data;
this.head = current.Next;
}
else
{
for (int i = 0; index < index - 1; i++) ;
current = current.Next;
result = current.Next.Data;
current.Next = current.Next.Next;
}
count--;
return result;
}
public void Clear()
{
this.head = null;
this.count = 0;
}
public int IndexOf(object o)
{
Node<T> current = this.head;
for (int i = 0; i < this.count; i++)
{
if (current.Data.Equals(o))
return i;
current = current.Next;
}
return -1;
}
public bool Contains(object o)
{
return this.IndexOf(o) >= 0;
}
public object Get(int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (this.Empty)
return null;
if (index >= this.count)
index = this.count - 1;
Node<T> current = this.head;
for (int i = 0; i < index; i++)
current = current.Next;
return current.Data;
}
}
Our teacher asked us to implement the class LinkedList. I was able to implement everything he asked for. But he gave us a bonus question that I was not able to solving.
He asked us to implement this fonction:
public void add(float x, int pos)
{
// Add x at the position pos, pos = 0 refer to the first element.
}
He also demanded that his code verifies the following UnitTest:
public class UnitTest1
{
private MyList l;
public UnitTest1()
{
l = new MyList();
for (int i = 0; i < 10; ++i)
{
l.add(i * i);
}
for (int i = 0; i < 10; ++i)
{
l.add(i * i);
}
}
[TestMethod]
public void TestAdd()
{
Assert.AreEqual(l.count(), 20);
}
[TestMethod]
public void TestGet()
{
for (int i = 0; i < 10; ++i)
{
Assert.AreEqual(l.get(i), (9 - i) * (9 - i));
}
for (int i = 10; i < 20; ++i)
{
Assert.AreEqual(l.get(i), (19 - i) * (19 - i));
}
}
[TestMethod]
public void TestFind()
{
int k;
for (int i = 0; i < 100; ++i)
{
for (k = 0; k < 10; ++k)
{
if (k * k == i)
{
Assert.AreEqual(l.find(i), true);
break;
}
}
if (k == 10)
{
Assert.AreEqual(l.find(i), false);
}
}
}
[TestMethod]
public void TestStats()
{
Assert.AreEqual(l.max(), 81);
float s = 0;
for (int i = 0; i < 10; ++i)
{
s += i * i + i * i;
}
Assert.AreEqual(l.sum(), s);
Assert.AreEqual(l.average(), s / 20);
}
[TestMethod]
public void TestCountValue()
{
MyList l1 = new MyList();
for (int i = 0; i < 10; ++i)
{
l1.add(i);
l1.add(i * i);
}
Assert.AreEqual(l1.count(-1), 0);
Assert.AreEqual(l1.count(0), 2);
Assert.AreEqual(l1.count(1), 2);
Assert.AreEqual(l1.count(2), 1);
Assert.AreEqual(l1.count(3), 1);
Assert.AreEqual(l1.count(4), 2);
Assert.AreEqual(l1.count(5), 1);
Assert.AreEqual(l1.count(6), 1);
Assert.AreEqual(l1.count(7), 1);
Assert.AreEqual(l1.count(8), 1);
Assert.AreEqual(l1.count(9), 2);
Assert.AreEqual(l1.count(10), 0);
Assert.AreEqual(l1.count(16), 1);
}
[TestMethod]
public void TestRemoveFirst()
{
MyList l1 = new MyList();
for (int i = 0; i < 10; ++i)
{
l1.add(i);
l1.add(i * i);
}
Assert.AreEqual(l1.count(81), 1);
l1.removeFirst();
Assert.AreEqual(l1.count(), 19);
Assert.AreEqual(l1.count(81), 0);
Assert.AreEqual(l1.count(-1), 0);
Assert.AreEqual(l1.count(0), 2);
Assert.AreEqual(l1.count(1), 2);
Assert.AreEqual(l1.count(2), 1);
Assert.AreEqual(l1.count(3), 1);
Assert.AreEqual(l1.count(4), 2);
Assert.AreEqual(l1.count(5), 1);
Assert.AreEqual(l1.count(6), 1);
Assert.AreEqual(l1.count(7), 1);
Assert.AreEqual(l1.count(8), 1);
Assert.AreEqual(l1.count(9), 2);
Assert.AreEqual(l1.count(10), 0);
Assert.AreEqual(l1.count(16), 1);
}
[TestMethod]
public void TestInsert()
{
MyList l1 = new MyList();
for (int i = 9; i >= 0; --i)
{
l1.add(i);
}
for (int i = 0; i <= 10; ++i)
{
l1.add(i, 2 * i);
}
for (int i = 0; i < 10; ++i)
{
Assert.AreEqual(l1.get(2 * i), i, "i=" + i);
Assert.AreEqual(l1.get(2 * i + 1), i);
}
Assert.AreEqual(l1.get(20), 10);
}
}
That's what I was capable of:
public class MyList
{
class Element
{
public float value;
public Element next;
}
Element first;
public MyList()
{
first = null;
}
public void add(float x)
{
Element e = new Element();
e.value = x;
e.next = first;
first = e;
}
public float get(int i)
{
if (first == null)
{
throw new Exception("Empty list... no elements inside");
}
Element tmp = first;
for (int j = 0; j < i; ++j)
{
tmp = tmp.next;
if (tmp == null)
{
throw new Exception("...");
}
}
return tmp.value;
}
public void print()
{
Element e = first;
while (e != null)
{
Console.WriteLine(e.value);
e = e.next;
}
}
public bool find(float x)
{
Element e = first;
while (e != null)
{
if (e.value == x)
{
return true;
}
e = e.next;
}
return false;
}
public float max()
{
float G = 0;
for (Element e = first; e != null; e = e.next)
{
if (e.value > G)
{
G = e.value;
}
}
return G;
}
public int count()
{
Element e = first;
int c = 0;
while (e != null)
{
c++;
e = e.next;
}
return c;
}
public int count(float x)
{
int c = 0;
for (Element e = first; e != null; e = e.next)
{
if (e.value == x)
{
c++;
}
}
return c;
}
public float sum()
{
float S = 0;
for (Element e = first; e != null; e = e.next)
{
S += e.value;
}
return S;
}
public float average()
{
return sum() / count();
}
public void removeFirst()
{
Element e = first;
first = e.next;
}
public void add(float x, int pos)
{
//I have absolutely no idea how to implement this fonction.
}
}
It will be similar to the code in the get() method.
Break your problem down into smaller problems
Does pos = 0?
if so, create a new root and point it to the old root
if not, loop (pos) times and create a new element. Then set the next property of the new element to the next property of the current element. Set the current element next property to your new element
.
public void add(float x, int pos)
{
if(pos == 0)
{
// create a new root and point the new root to the existing root
}
else
{
Element tmp = first;
for(int i = 0; i < pos; i++)
{
tmp = tmp.next;
}
// create new element
// set new element next property to tmp.next
// set tmp.next to new element
}
}
I have simple binary search tree
public class BNode
{
public int item;
public BNode right;
public BNode left;
public BNode(int item)
{
this.item = item;
}
}
public class BTree
{
private BNode _root;
private int _count;
private IComparer<int> _comparer = Comparer<int>.Default;
public BTree()
{
_root = null;
_count = 0;
}
public bool Add(int Item)
{
if (_root == null)
{
_root = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(_root, Item);
}
}
private bool Add_Sub(BNode Node, int Item)
{
if (_comparer.Compare(Node.item, Item) < 0)
{
if (Node.right == null)
{
Node.right = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(Node.right, Item);
}
}
else if (_comparer.Compare(Node.item, Item) > 0)
{
if (Node.left == null)
{
Node.left = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(Node.left, Item);
}
}
else
{
return false;
}
}
public void Print()
{
Print(_root, 4);
}
public void Print(BNode p, int padding)
{
if (p != null)
{
if (p.right != null)
{
Print(p.right, padding + 4);
}
if (padding > 0)
{
Console.Write(" ".PadLeft(padding));
}
if (p.right != null)
{
Console.Write("/\n");
Console.Write(" ".PadLeft(padding));
}
Console.Write(p.item.ToString() + "\n ");
if (p.left != null)
{
Console.Write(" ".PadLeft(padding) + "\\\n");
Print(p.left, padding + 4);
}
}
}
}
where I can insert values like
BTree btr = new BTree();
btr.Add(6);
btr.Add(2);
btr.Add(3);
btr.Add(11);
btr.Add(30);
btr.Add(9);
btr.Add(13);
btr.Add(18);
I want to display my tree within my console application. I have a btr.Print(); which displays my tree from left to right (6 is the root) - but I'm not happy with it.
Question: Is there a better way to display this tree within a console application? Even a improvement of this Print() would help me.
I've ended up with the following method that allows you to print arbitrary subtree:
public static class BTreePrinter
{
class NodeInfo
{
public BNode Node;
public string Text;
public int StartPos;
public int Size { get { return Text.Length; } }
public int EndPos { get { return StartPos + Size; } set { StartPos = value - Size; } }
public NodeInfo Parent, Left, Right;
}
public static void Print(this BNode root, string textFormat = "0", int spacing = 1, int topMargin = 2, int leftMargin = 2)
{
if (root == null) return;
int rootTop = Console.CursorTop + topMargin;
var last = new List<NodeInfo>();
var next = root;
for (int level = 0; next != null; level++)
{
var item = new NodeInfo { Node = next, Text = next.item.ToString(textFormat) };
if (level < last.Count)
{
item.StartPos = last[level].EndPos + spacing;
last[level] = item;
}
else
{
item.StartPos = leftMargin;
last.Add(item);
}
if (level > 0)
{
item.Parent = last[level - 1];
if (next == item.Parent.Node.left)
{
item.Parent.Left = item;
item.EndPos = Math.Max(item.EndPos, item.Parent.StartPos - 1);
}
else
{
item.Parent.Right = item;
item.StartPos = Math.Max(item.StartPos, item.Parent.EndPos + 1);
}
}
next = next.left ?? next.right;
for (; next == null; item = item.Parent)
{
int top = rootTop + 2 * level;
Print(item.Text, top, item.StartPos);
if (item.Left != null)
{
Print("/", top + 1, item.Left.EndPos);
Print("_", top, item.Left.EndPos + 1, item.StartPos);
}
if (item.Right != null)
{
Print("_", top, item.EndPos, item.Right.StartPos - 1);
Print("\\", top + 1, item.Right.StartPos - 1);
}
if (--level < 0) break;
if (item == item.Parent.Left)
{
item.Parent.StartPos = item.EndPos + 1;
next = item.Parent.Node.right;
}
else
{
if (item.Parent.Left == null)
item.Parent.EndPos = item.StartPos - 1;
else
item.Parent.StartPos += (item.StartPos - 1 - item.Parent.EndPos) / 2;
}
}
}
Console.SetCursorPosition(0, rootTop + 2 * last.Count - 1);
}
private static void Print(string s, int top, int left, int right = -1)
{
Console.SetCursorPosition(left, top);
if (right < 0) right = left + s.Length;
while (Console.CursorLeft < right) Console.Write(s);
}
}
As you can see, I've added some parameters that affect the formatting. By default it produces the most compact representation.
In order to play with it, I've modified the BTree class as follows:
public class BTree
{
// ...
public BNode Root { get { return _root; } }
public void Print()
{
Root.Print();
}
}
Using your sample data, here are some results:
btr.Root.Print();
btr.Root.Print(textFormat: "(0)", spacing: 2);
UPDATE: IMO the default format above is compact and readable, but just for fun, adjusted the algorithm to produce more "graphical" output (textFormat and spacing parameters removed):
public static class BTreePrinter
{
class NodeInfo
{
public BNode Node;
public string Text;
public int StartPos;
public int Size { get { return Text.Length; } }
public int EndPos { get { return StartPos + Size; } set { StartPos = value - Size; } }
public NodeInfo Parent, Left, Right;
}
public static void Print(this BNode root, int topMargin = 2, int leftMargin = 2)
{
if (root == null) return;
int rootTop = Console.CursorTop + topMargin;
var last = new List<NodeInfo>();
var next = root;
for (int level = 0; next != null; level++)
{
var item = new NodeInfo { Node = next, Text = next.item.ToString(" 0 ") };
if (level < last.Count)
{
item.StartPos = last[level].EndPos + 1;
last[level] = item;
}
else
{
item.StartPos = leftMargin;
last.Add(item);
}
if (level > 0)
{
item.Parent = last[level - 1];
if (next == item.Parent.Node.left)
{
item.Parent.Left = item;
item.EndPos = Math.Max(item.EndPos, item.Parent.StartPos);
}
else
{
item.Parent.Right = item;
item.StartPos = Math.Max(item.StartPos, item.Parent.EndPos);
}
}
next = next.left ?? next.right;
for (; next == null; item = item.Parent)
{
Print(item, rootTop + 2 * level);
if (--level < 0) break;
if (item == item.Parent.Left)
{
item.Parent.StartPos = item.EndPos;
next = item.Parent.Node.right;
}
else
{
if (item.Parent.Left == null)
item.Parent.EndPos = item.StartPos;
else
item.Parent.StartPos += (item.StartPos - item.Parent.EndPos) / 2;
}
}
}
Console.SetCursorPosition(0, rootTop + 2 * last.Count - 1);
}
private static void Print(NodeInfo item, int top)
{
SwapColors();
Print(item.Text, top, item.StartPos);
SwapColors();
if (item.Left != null)
PrintLink(top + 1, "┌", "┘", item.Left.StartPos + item.Left.Size / 2, item.StartPos);
if (item.Right != null)
PrintLink(top + 1, "└", "┐", item.EndPos - 1, item.Right.StartPos + item.Right.Size / 2);
}
private static void PrintLink(int top, string start, string end, int startPos, int endPos)
{
Print(start, top, startPos);
Print("─", top, startPos + 1, endPos);
Print(end, top, endPos);
}
private static void Print(string s, int top, int left, int right = -1)
{
Console.SetCursorPosition(left, top);
if (right < 0) right = left + s.Length;
while (Console.CursorLeft < right) Console.Write(s);
}
private static void SwapColors()
{
var color = Console.ForegroundColor;
Console.ForegroundColor = Console.BackgroundColor;
Console.BackgroundColor = color;
}
}
and the result is:
This is my take at it:
I've added PrintPretty to BNode, and I've removed the second Print function you had in BTree.
(Edit: I made the tree more lisible by changing the original chars to draw the branches of the tree)
static void Main(string[] args)
{
BTree btr = new BTree();
btr.Add(6);
btr.Add(2);
btr.Add(3);
btr.Add(11);
btr.Add(30);
btr.Add(9);
btr.Add(13);
btr.Add(18);
btr.Print();
}
public class BNode
{
public int item;
public BNode right;
public BNode left;
public BNode(int item)
{
this.item = item;
}
public void PrintPretty(string indent, bool last)
{
Console.Write(indent);
if (last)
{
Console.Write("└─");
indent += " ";
}
else
{
Console.Write("├─");
indent += "| ";
}
Console.WriteLine(item);
var children = new List<BNode>();
if (this.left != null)
children.Add(this.left);
if (this.right != null)
children.Add(this.right);
for (int i = 0; i < children.Count; i++)
children[i].PrintPretty(indent, i == children.Count - 1);
}
}
public class BTree
{
private BNode _root;
private int _count;
private IComparer<int> _comparer = Comparer<int>.Default;
public BTree()
{
_root = null;
_count = 0;
}
public bool Add(int Item)
{
if (_root == null)
{
_root = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(_root, Item);
}
}
private bool Add_Sub(BNode Node, int Item)
{
if (_comparer.Compare(Node.item, Item) < 0)
{
if (Node.right == null)
{
Node.right = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(Node.right, Item);
}
}
else if (_comparer.Compare(Node.item, Item) > 0)
{
if (Node.left == null)
{
Node.left = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(Node.left, Item);
}
}
else
{
return false;
}
}
public void Print()
{
_root.PrintPretty("", true);
}
}
This is the result (more compact, as I mentioned):
Edit: the following code has been modified in order to show the info about left-right:
static void Main(string[] args)
{
BTree btr = new BTree();
btr.Add(6);
btr.Add(2);
btr.Add(3);
btr.Add(11);
btr.Add(30);
btr.Add(9);
btr.Add(13);
btr.Add(18);
btr.Print();
}
public enum NodePosition
{
left,
right,
center
}
public class BNode
{
public int item;
public BNode right;
public BNode left;
public BNode(int item)
{
this.item = item;
}
private void PrintValue(string value, NodePosition nodePostion)
{
switch (nodePostion)
{
case NodePosition.left:
PrintLeftValue(value);
break;
case NodePosition.right:
PrintRightValue(value);
break;
case NodePosition.center:
Console.WriteLine(value);
break;
default:
throw new NotImplementedException();
}
}
private void PrintLeftValue(string value)
{
Console.ForegroundColor = ConsoleColor.Magenta;
Console.Write("L:");
Console.ForegroundColor = (value == "-") ? ConsoleColor.Red : ConsoleColor.Gray;
Console.WriteLine(value);
Console.ForegroundColor = ConsoleColor.Gray;
}
private void PrintRightValue(string value)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("R:");
Console.ForegroundColor = (value == "-") ? ConsoleColor.Red : ConsoleColor.Gray;
Console.WriteLine(value);
Console.ForegroundColor = ConsoleColor.Gray;
}
public void PrintPretty(string indent, NodePosition nodePosition, bool last, bool empty)
{
Console.Write(indent);
if (last)
{
Console.Write("└─");
indent += " ";
}
else
{
Console.Write("├─");
indent += "| ";
}
var stringValue = empty ? "-" : item.ToString();
PrintValue(stringValue, nodePosition);
if(!empty && (this.left != null || this.right != null))
{
if (this.left != null)
this.left.PrintPretty(indent, NodePosition.left, false, false);
else
PrintPretty(indent, NodePosition.left, false, true);
if (this.right != null)
this.right.PrintPretty(indent, NodePosition.right, true, false);
else
PrintPretty(indent, NodePosition.right, true, true);
}
}
}
public class BTree
{
private BNode _root;
private int _count;
private IComparer<int> _comparer = Comparer<int>.Default;
public BTree()
{
_root = null;
_count = 0;
}
public bool Add(int Item)
{
if (_root == null)
{
_root = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(_root, Item);
}
}
private bool Add_Sub(BNode Node, int Item)
{
if (_comparer.Compare(Node.item, Item) < 0)
{
if (Node.right == null)
{
Node.right = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(Node.right, Item);
}
}
else if (_comparer.Compare(Node.item, Item) > 0)
{
if (Node.left == null)
{
Node.left = new BNode(Item);
_count++;
return true;
}
else
{
return Add_Sub(Node.left, Item);
}
}
else
{
return false;
}
}
public void Print()
{
_root.PrintPretty("", NodePosition.center, true, false);
}
}
The result:
If your tree is in the form of a QuickGraph IBidirectionalGraph, you could print it recursively like this:
static void PrintVertex<TVertex>(IBidirectionalGraph<TVertex, IEdge<TVertex>> graph, TVertex vertex, Func<TVertex, string> labelSelector, bool[] isLastVertexIntendations = null)
{
var prefix = string.Concat(Enumerable.Concat(
/*up to last*/isLastVertexIntendations.NeverNull().Reverse().Skip(1).Reverse().Select(isLast => isLast ? " " : "│ "),
/*last*/isLastVertexIntendations.NeverNull().Reverse().Take(1).Select(isLast => isLast ? "└─" : "├─")
));
Console.Write(prefix);
Console.WriteLine(labelSelector(vertex));
var edges = graph.OutEdges(vertex);
foreach (var edge in edges)
{
PrintVertex(graph, edge.Target, labelSelector, isLastVertexIntendations: isLastVertexIntendations.NeverNull().Concat(new[] { edge == edges.Last() }).ToArray());
}
}
I'm having an issue inserting a new object into a linked list. I use a custom method called Insert that takes the object type and the index where it should be placed. However, when I insert the object, the list doesn't update. Any idea why?
The list:
GenericLinkedList<string> bet = new GenericLinkedList<string>();
bet.Add("a");
bet.Add("b");
bet.Add("c");
bet.Add("d");
//bet.Remove();
bet.Insert("x", 2);
The Generic Linked List Class:
public class GenericLinkedList<T> where T : IComparable<T>
{
public GenericLinkedList()
{
count = 0;
head = null;
}
#region Nested Node Class
private class Node<T>
{
private T data;
public T Data
{
get { return data; }
set { data = value; }
}
private Node<T> next;
public Node<T> Next
{
get { return next; }
set { next = value; }
}
public Node<T> Previous { get; set; }
public Node(T obj_t)
{
next = null;
data = obj_t;
}
public Node()
{
next = null;
}
}
#endregion
private Node<T> head;
private Node<T> tail;
private int count;
public int Count
{
get
{
int num;
if (count < 0)
num = 0;
else {
num = count;
}
return num;
}
}
}
The Insert Method:
public void Insert(T data, int index)
{
Node<T> replacedItem = new Node<T>();
Node<T> newItem = new Node<T>(data);
if (head == null)
{
head = new Node<T>(data);
tail = head;
}
else
{
Node<T> current = head;
Node<T> tempNode = new Node<T>();
if (index > 0 && index <= count + 1)
{
int c = 0;
while (current != null)
{
if (c == index)
{
tempNode = current;
current = newItem;
current.Next = tempNode;
}
else
{
current = current.Next;
}
c++;
}
}
count++;
}
}
The Add Method:
public void Add(T data)
{
count++;
if (head == null)
{
head = new Node<T>(data);
tail = head;
}
else
{
tail.Next = new Node<T>(data);
tail.Next.Previous = tail;
tail = tail.Next;
}
}
Need to add count++ in case head is null. Also count++ should go inside if(index>0&&index<=count+1)
public void Insert(T data, int index)
{
Node<T> replacedItem = new Node<T>();
Node<T> newItem = new Node<T>(data);
if (head == null)
{
head = new Node<T>(data);
tail = head;
count++;
}
else
{
Node<T> current = head;
Node<T> tempNode = new Node<T>();
if (index > 0 && index <= count + 1)
{
int c = 0;
while (current != null)
{
if (c == index)
{
tempNode = current;
current = newItem;
current.Next = tempNode;
}
else
{
current = current.Next;
}
c++;
}
count++;
}
}
}
See if this helps.
You not correctly add new item in your Insert method
in this place
tempNode = current; // save pointer to current item
current = newItem; // save in current new item
current.Next = tempNode; //set next to counter
but you don't change link from previous element, so when you again go from head you just miss your added item.
You need change this code something like
public void Insert(T data, int index)
{
Node<T> replacedItem = new Node<T>();
Node<T> newItem = new Node<T>(data);
if (head == null)
{
head = new Node<T>(data);
tail = head;
count++;
}
else
{
Node<T> current = head;
Node<T> tempNode = new Node<T>();
if (index > 0 && index <= count + 1)
{
int c = 0;
while (current != null)
{
if (c == index)
{
tempNode = current;
current = newItem;
//update link from previous element
if(tempNode.Previous != null)
tempNode.Previous.Next = current;
current.Next = tempNode;
current.Previous = tempNode.Previous;
tempNode.Previous = current;
count++;
break;
}
else
{
current = current.Next;
}
c++;
}
}
}
}