I created a custom linked list on a whiteboard, for learning purposes.
CustDoublyLinkedList class with the nested Node class, but when it is time to insert, at the specified index method must loop through until it get to an index to insert. I want to insert directly without using loop as my Add or PushFront methods work.
I also added some more method like IndexOf and Contain methods for the list
CustDoublyLinkedList<int> myList = new();
myList.Add(12);
myList.Add(13);
myList.Add(14);
myList.Add(45);
myList.Add(28);
myList.Add(120);
myList.PushFront(32);
myList.Insert(3,1500);
for (int i = 0; i < myList.Count; i++)
{
Console.WriteLine(myList[i]);
}
class CustDoublyLinkedList<T>
{
private class Node
{
public T Element { get; set; }
public Node NextNode { get; set; }
public Node PrevNode { get; set; }
public Node(T data)
{
this.Element = data;
this.PrevNode = null;
this.NextNode = null;
}
public Node(T data, Node prevNode): this(data)
{
prevNode.NextNode = this;
}
public Node(T data, Node prevNode, Node nextNode) : this(data, prevNode)
{
nextNode.PrevNode = this;
}
}
private Node head;
private Node tail;
private int counter;
public CustDoublyLinkedList()
{
this.head = null;
this.tail = null;
this.counter = 0;
}
public void Insert(int index, T item)
{
if (index == 0)
{
throw new ArgumentOutOfRangeException("You Can Push with PushFront Method at Index: " + index);
}
if (index < 0 || index >= this.counter)
{
throw new ArgumentOutOfRangeException("invalid Index: " + index);
}
Node newNode = new(item);
Node currentNode = this.head;
for (int i = 0; i < index - 1; i++)
{
currentNode = currentNode.NextNode;
}
newNode.NextNode = currentNode.NextNode;
newNode.PrevNode = currentNode.PrevNode;
currentNode.NextNode = newNode;
this.counter++;
}
public void Add(T item)
{
if (this.head == null)
{
this.head = new(item);
this.tail = this.head;
}
else
{
Node newNode = new(item, this.tail);
this.tail = newNode;
}
this.counter++;
}
public void PushFront(T item)
{
Node newNode = new(item);
newNode.NextNode = this.head;
newNode.PrevNode = null;
if(this.head != null)
{
this.head.PrevNode = newNode;
}
this.head = newNode;
this.counter++;
}
public bool Contain(T item)
{
int index = IndexOf(item);
if (index != -1)
{
return true;
}
return false;
}
public int IndexOf(T item)
{
Node currentNode = this.head;
int index = 0;
while(currentNode != null)
{
if (object.Equals(currentNode.Element, item))
{
return index;
}
currentNode = currentNode.NextNode;
index++;
}
return -1;
}
public int Count
{
get { return this.counter; }
}
public T this[int index]
{
get
{
if (index < 0 || index >= this.counter)
{
throw new IndexOutOfRangeException("Invalid Index: " + index);
}
Node currentNode = this.head;
for (int i = 0; i < index; i++)
{
currentNode = currentNode.NextNode;
}
return currentNode.Element;
}
set
{
if (index < 0 || index >= this.counter)
{
throw new IndexOutOfRangeException("Invalid Index: " + index);
}
Node currentNode = this.head;
for (int i = 0; i < index; i++)
{
currentNode = currentNode.NextNode;
}
currentNode.Element = value;
}
}
}
You are looking for a Skip List
With this you can drive your insert requirement to O(log N) on average while still maintaining a linked list structure
How can I swap two elements of a two-linked list(by switching links)? I realized that I need to consider four cases: change with the first / last elements, change neighboring elements, and all other cases.
The cell structure is as follows:
public class Item<T>
{
private T _Data;
private Item<T> _Next;
private Item<T> _Prev;
public T Value
{
get { return _Data; }
set { this._Data = value; }
}
public Item(T Data)
{
this._Data = Data;
}
public Item()
{
this._Data = default;
}
public Item<T> Next
{
get { return this._Next; }
set { this._Next = value; }
}
public Item<T> Prev
{
get { return this._Prev; }
set { this._Prev = value; }
}
}
This is an implementation attempt. What's wrong?(Here I also do insert sort, but it all depends on the exchange of two elements)
public override D_List<T> Sorting(D_List<T> a)
{
for (int top = 1; top < a.Count; top++)
{
int k = top;
while (k > 0 && a[k-1] > a[k])
{
k--;
}
if (k == 0)
{
a[top].Prev.Next = a[top].Next;
a[top].Next.Prev = a[top].Prev;
a[top].Next = a[k];
a[top].Prev = null;
a[k].Prev = a[top];
}
else if(k == a.Count - 2)
{
a[k].Prev.Next = a[top];
a[top].Prev = a[k].Prev;
a[k].Next = null;
a[k].Prev = a[top];
}
else if(k+1 == top)//стоят подряд
{
a[k].Prev.Next = a[top];
a[top].Prev = a[k].Prev;
a[k].Next = a[top].Next;
a[top].Next = a[k];
a[k].Next.Prev = a[k];
}
else
{
a[k].Prev = a[top];
a[top].Prev.Next = a[top].Next;
a[top].Next.Prev = a[top].Prev;
a[top].Prev = a[k].Prev;
a[top].Next = a[k];
a[top].Next.Prev = a[top];
}
}
return a;
}
I have a created a Node Builder to fetch how n elements are connected to one another. It is a parent child hierarchy represented in Node Tree.
I am using tree builder like below code to find best two chains.
Below is the code:
public class NodeBuilder
{
private readonly List<IItem> _nestedItems;
private readonly IFactory<IItem> _factory;
private readonly NodeEqualityComparer _comparer;
private readonly List<Node> _nodes;
private WeightedComparer _weightedComparer;
private NodeComparer _nodeComparer;
private readonly NodeItemComparer _nodeItemComparer;
public NodeBuilder(List<IItem> nestedItems, IFactory<IItem> factory)
{
_nestedItems = nestedItems;
_factory = factory;
_comparer = new NodeEqualityComparer();
_nodeComparer = new NodeComparer();
_nodes = new List<Node>();
_weightedComparer=new WeightedComparer();
_nodeItemComparer = new NodeItemComparer(_factory.Comparer);
}
public IEnumerable<List<int>> GetTopChains(int collections)
{
if (_nodes.Count == 0) BuildNodes(collections);
var collection= GetIndexes().ToList();
collection.Sort(_weightedComparer);
return collection.Take(collections);
}
public class WeightedComparer : IComparer<List<int>>
{
public int Compare(List<int> x, List<int> y)
{
if (x == y) return 0;
if (x == null) return 1;
if (y == null) return -1;
return y.Count - x.Count;
}
}
private IEnumerable<List<int>> GetIndexes()
{
Dictionary<IItem,List<int>> indexers = new Dictionary<IItem, List<int>>();
_nodes.Sort(_nodeItemComparer);
foreach (var node in _nodes)
{
List< int> indexs=new List<int>();
int currSize = node.ChainSize;
var temp = node;
while (temp != null)
{
int index = _nestedItems.IndexOf(temp.Item);
if (index != -1) indexs.Add(index);
currSize--;
var temps = new List<Node>(temp.Childs.Where(x => x.ChainSize == currSize));
temps.Sort(_nodeComparer);
Dictionary<Node,List<int>> subIndexes = new Dictionary<Node, List<int>>();
if (!temps.Any()) temp = null;
foreach (var subTemp in temps)
{
var key = subTemp.Item;
if (indexers.ContainsKey(key))
{
var newList = new List<int>();
newList.AddRange(indexs);
newList.AddRange(indexers[key]);
subIndexes.Add(subTemp, newList);
}
if (subIndexes[subTemp].Count == node.ChainSize)
{
temp = subTemp;
indexers.Remove(subTemp.Item);
}
else
{
temp = null;
}
}
}
indexs = indexs.Distinct().ToList();
indexers.Add(node.Item,indexs);
}
return indexers.Values;
}
private void BuildNodes(int collections)
{
int total = _factory.TotalItems;
for (int i = collections * _factory.TotalItems - 1; i >= 0; i--)
{
var searchNode = new Node(_nestedItems[i], _factory.EqualityComparer);
Node node1 = _nodes.SingleOrDefault(x => _comparer.Equals(x, searchNode));
if (node1 == null)
{
node1 = searchNode;
node1.ChainSize = total;
_nodes.Add(node1);
}
}
for (int i = 0; i < collections * _factory.TotalItems; i++)
{
var searchNode = new Node(_nestedItems[i], _factory.EqualityComparer);
Node node1 = _nodes.SingleOrDefault(x => _comparer.Equals(x, searchNode));
for (int j = 0; j < collections * _factory.TotalItems; j++)
{
searchNode = new Node(_nestedItems[j], _factory.EqualityComparer);
Node node2 = _nodes.SingleOrDefault(x => _comparer.Equals(x, searchNode));
if (node2 == null)
{
node2 = searchNode;
_nodes.Add(node2);
}
if (_nestedItems[i].Constraint(_nestedItems[j]))
{
if (node1 != null)
{
int temp = node1.ChainSize - 1;
node2.ChainSize = temp;`enter code here`
if (!node1.Childs.Contains(node2, new NodeEqualityComparer()))
node1.Childs.Add(node2);
}
}
}
}
}
}
public class NodeItemComparer:IComparer<Node>
{
private readonly IComparer<IItem> _factoryComparer;
public NodeItemComparer(IComparer<IItem> factoryComparer)
{
_factoryComparer = factoryComparer;
}
public int Compare(Node x, Node y)
{
if (x == null & y == null) return 0;
if (x == y) return 0;
if (x == null) return 1;
if (y == null) return -1;
return _factoryComparer.Compare(y.Item, x.Item);
}
}
public class NodeComparer:IComparer<Node>
{
public int Compare(Node x, Node y)
{
if (x == null & y == null) return 0;
if (x == y) return 0;
if (x == null) return 1;
if (y == null) return -1;
return y.ChainSize - x.ChainSize;
}
}
public class NodeEqualityComparer : IEqualityComparer<Node>
{
public bool Equals(Node x, Node y)
{
if (x == null & y == null) return true;
if (x == y) return true;
if (x != y) return false;
return x.Equals(y);
}
public int GetHashCode(Node obj)
{
return obj.GetHashCode();
}
}
public class Node : IEquatable<Node>
{
public IItem Item { get; }
private readonly IEqualityComparer<IItem> _comparer;
public int ChainSize { get; set; }
public IList<Node> Childs { get; private set; }
public Node(IItem item, IEqualityComparer<IItem> comparer)
{
Item = item;
_comparer = comparer;
Childs = new List<Node>();
}
public override string ToString()
{
return Item.ItemName;
}
public bool Equals(Node other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return _comparer.Equals(Item, other.Item);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Node)obj);
}
public override int GetHashCode()
{
return (Item != null ? Item.GetHashCode() : 0);
}
public static bool operator ==(Node left, Node right)
{
return Equals(left, right);
}
public static bool operator !=(Node left, Node right)
{
return !Equals(left, right);
}
}
I am looking for a ways to traverse the tree and find two hierarchical connected items.
I want to randomly generate trees (not BST) for unit testing of my code. I have tried it in a number of ways but somehow after generation of 3 -4 trees there is an exception or code goes into infinite loop. I am using random numbers for edges and node values.
I have also tried queue approach where I fill up the queue with random numbers and then dequeue nodes and randomly select the old node from the existing items in the queue and then connect this new node.
Does anybody know how to do this in C# in more better and succinct way?
EDIT
public class Tree
{
public Node Root { get; private set; }
public readonly Dictionary<long, Node> Nodes = new Dictionary<long, Node>();
public readonly Dictionary<string, long> SumDictionary = new Dictionary<string, long>();
public readonly Dictionary<long, long> FDictionary = new Dictionary<long, long>
{
{0, 1},
{1, 1}
};
public long Query(long n)
{
long s = 0;
Dfs();
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++)
{
var lvalue = GetLValue(i, j);
if (i != j)
{
lvalue *= 2;
}
s += lvalue;
if (s >= Mod)
{
s %= Mod;
}
}
}
return s;
}
private long GetLValue(int a, int b)
{
var key = string.Format("{0}-{1}", a, b);
if (SumDictionary.ContainsKey(key))
{
return Fvalue(SumDictionary[key]);
}
var aKey = string.Format("{0}-{1}", 1, a);
var bKey = string.Format("{0}-{1}", 1, b);
var sumA = SumDictionary[aKey];
var sumB = SumDictionary[bKey];
var lca = Lca(a, b);
if (lca != a && lca != b)
{
return Fvalue(sumA + sumB - SumDictionary[string.Format("{0}-{1}", lca, lca)]);
}
long bigSum, smallSum;
if (sumA > sumB)
{
bigSum = sumA;
smallSum = sumB;
}
else
{
bigSum = sumB;
smallSum = sumA;
}
var sumAtoB = bigSum - (smallSum - Nodes[smallSum].Value);
return Fvalue(sumAtoB);
}
public void AddNode(long a, long b)
{
Node nodea, nodeb;
if (Nodes.ContainsKey(a))
{
nodea = Nodes[a];
}
else
{
nodea = new Node { Value = a };
Nodes.Add(a, nodea);
}
if (Nodes.ContainsKey(b))
{
nodeb = Nodes[b];
}
else
{
nodeb = new Node { Value = b };
Nodes.Add(b, nodeb);
}
nodea.ReachableNodes.Add(b, nodeb);
nodeb.ReachableNodes.Add(a, nodea);
if (Root == null)
{
Root = nodea;
}
}
public long? Lca(int a, int b)
{
bool found = false;
return TraverseForLca(Root, null, a, b, ref found);
}
private long? TraverseForLca(Node node, Node prev, long a, long b, ref bool found)
{
if (node == null)
{
return null;
}
if (node.Value == a)
{
return a;
}
if (node.Value == b)
{
return b;
}
long? f = null;
foreach (KeyValuePair<long, Node> reachableNode in node.ReachableNodes)
{
var n = reachableNode.Value;
if (prev != null && n.Value == prev.Value)
{
continue;
}
long? lca = TraverseForLca(n, node, a, b, ref found);
if (found)
{
return lca;
}
if (lca != null && f == null)
{
f = lca;
}
else if (lca != null)
{
found = true;
return node.Value;
}
}
return f;
}
public void Dfs()
{
TravelForDfs(Root, null, 0);
}
private void TravelForDfs(Node node, Node prev, long recSum)
{
if (node == null)
{
return;
}
var key = string.Format("{0}-{1}", prev != null ? prev.Value : node.Value, node.Value);
var iKey = string.Format("{0}-{1}", node.Value, node.Value);
var weight = node.Weight;
if (weight >= Mod)
{
weight %= Mod;
}
if (!SumDictionary.ContainsKey(iKey))
{
SumDictionary.Add(iKey, weight);
}
weight = recSum + node.Weight;
if (weight >= Mod)
{
weight %= Mod;
}
foreach (KeyValuePair<long, Node> reachableNode in node.ReachableNodes)
{
var n = reachableNode.Value;
if (prev != null && n.Value == prev.Value)
{
if (!SumDictionary.ContainsKey(key))
{
SumDictionary.Add(key, weight);
}
continue;
}
if (!SumDictionary.ContainsKey(key))
{
SumDictionary.Add(key, weight);
}
TravelForDfs(n, node, weight);
}
}
public long Fvalue(long n)
{
if (n == 1 || n == 0)
{
return 1;
}
long a, b;
if (FDictionary.ContainsKey(n - 1))
{
a = FDictionary[n - 1];
}
else
{
a = Fvalue(n - 1);
if (!FDictionary.ContainsKey(n - 1))
{
FDictionary.Add(n - 1, a);
}
}
if (FDictionary.ContainsKey(n - 2))
{
b = FDictionary[n - 2];
}
else
{
b = Fvalue(n - 2);
if (!FDictionary.ContainsKey(n - 2))
{
FDictionary.Add(n - 2, b);
}
}
if (!FDictionary.ContainsKey(n))
{
FDictionary.Add(n, a + b);
}
var s = a + b;
if (s >= Mod)
{
s %= Mod;
}
return s;
}
}
It should just generate a tree
Does this tree meet your requirements?
public class TreeNode<T>
{
public T Value { get; set; }
public List<TreeNode<T>> Childs { get; }
public TreeNode()
{
Childs = new List<TreeNode<T>>();
}
}
public class TreeGenerator
{
private readonly int maxChilds;
private readonly Random rnd = new Random();
public TreeGenerator(int maxChilds)
{
this.maxChilds = maxChilds;
}
public TreeNode<T> CreateTree<T>(int maxDepth, Func<T> valueGenerator)
{
var node = new TreeNode<T>();
node.Value = valueGenerator();
if (maxDepth > 0)
{
var childsCount = rnd.Next(maxChilds);
for (var i = 0; i < childsCount; ++i)
node.Childs.Add(CreateTree(maxDepth - 1, valueGenerator));
}
return node;
}
public static void Demo()
{
var rnd = new Random();
var generator = new TreeGenerator(3 /* max childs count*/);
var tree = generator.CreateTree(4 /*max depth*/, () => rnd.Next() /*node value*/);
}
}
I am storing Linked Lists in an Array List. Each linked list contains different items. I would like to retrieve a particular linkedlist from the array list such as at index position 0 of the and perform certain operations e.g. traversing from the front. However I am having problems getting the array items to be recognised as linked lists. What would be the best way of doing that?
E.g if I have
static ArrayList ar = new ArrayList();
static DLinkedList b = new DLinkedList();
And would like to do the following.
b.TraverseFront(ar[0]);
I have given an example below which I implemented in C#
class Program
{
static ArrayList ar = new ArrayList();
static DLinkedList b = new DLinkedList();
static void Main(string[] args)
{
store("huggo boss");
b.TraverseFront(ar[0]); // THIS IS WHAT I'D LIKE TO DO BUT I DON'T KNOW HOW TO DO IT
}
private static void store(string s)
{
DLinkedList linkedListNode = new DLinkedList();
string output = null;
string norm = null;
int token = 3;
for (int i = 0; i < s.Length; i++)
{
if (!String.IsNullOrWhiteSpace(char.ToString(s[i])))
{
output = output + s[i];
}
}
for (int j = 0; j < output.Length - token + 1 ; j++)
{
norm = norm + output[j] + output[j + 1] + output[j + 2]
linkedListNode.InsertNext(norm);
norm = null;
}
}
}
}
class DLinkedList
{
private Object data;
private DLinkedList next;
private DLinkedList prev;
/*
static void Main(string[] args)
{
DLinkedList node1 = new DLinkedList(1);
DLinkedList node3 = node1.InsertNext(3);
DLinkedList node2 = node3.InsertPrev(2);
DLinkedList node5 = node3.InsertNext(5);
DLinkedList node4 = node5.InsertPrev(4);
node1.TraverseFront();
node5.TraverseBack();
Console.Read();
}
*/
public DLinkedList()
{
data = null;
next = null;
prev = null;
}
public DLinkedList(Object value)
{
data = value;
next = null;
prev = null;
}
public DLinkedList InsertNext(Object value)
{
DLinkedList node = new DLinkedList(value);
if (this.next == null)
{
// Easy to handle
node.prev = this;
node.next = null; // already set in constructor
this.next = node;
}
else
{
// Insert in the middle
DLinkedList temp = this.next;
node.prev = this;
node.next = temp;
this.next = node;
temp.prev = node;
// temp.next does not have to be changed
}
return node;
}
public DLinkedList InsertPrev(Object value)
{
DLinkedList node = new DLinkedList(value);
if (this.prev == null)
{
node.prev = null; // already set on constructor
node.next = this;
this.prev = node;
}
else
{
// Insert in the middle
DLinkedList temp = this.prev;
node.prev = temp;
node.next = this;
this.prev = node;
temp.next = node;
// temp.prev does not have to be changed
}
return node;
}
public void TraverseFront()
{
TraverseFront(this);
}
public void TraverseFront(DLinkedList node)
{
if (node == null)
node = this;
System.Console.WriteLine("\n\nTraversing in Forward
Direction\n\n");
while (node != null)
{
System.Console.WriteLine(node.data);
node = node.next;
}
}
public void TraverseBack()
{
TraverseBack(this);
}
public void TraverseBack(DLinkedList node)
{
if (node == null)
node = this;
while (node != null)
{
System.Console.WriteLine(node.data);
node = node.prev;
}
}
internal void TraverseFront(object p)
{
throw new NotImplementedException();
}
}
}