How do I parse commands from a text file in C#? - c#

I am creating an application for my C# class in school that reads commands in from text file and displays the results in the console. Basically there will be commands in the file that should add a node and delete a node from a singly linked list. So if in the input file it reads I:1, I:7 it would output Node1:1 and Node2:7 to the console.
I know how to parse a file to display things like hello world, etc. But I am unsure as to how I would parse a file to look for a specific string and then output results based on that string (in this case appending and deleting nodes from a list). Is there any resources on how one would do that?
This is what I have for my program so far:
public class LinkedList {
Node head; //the head of list
public class Node {
public int data;
public Node next;
//constructor
public Node(int d) {
data = d;
next = null;
} //end of constructor
}
public void printList() { //traversing list and printing the contents starting from head(1)
Node n = head;
while (n != null) {
Console.Write(n.data + " ");
n = n.next;
}
}
public void push(int new_data) {
Node new_node = new Node(new_data); //allocate new node, put in data
new_node.next = head; //make next of new node as head
head = new_node; //move the head to point to new node
}
//main method to create a linked list with 3 nodes
public static void Main(String[] args) {
//starting with an empty list
LinkedList llist = new LinkedList();
llist.head = new Node(1);
Node second = new Node(2);
Node third = new Node(3);
//now 3 nodes have been allocated. head, second, and third
llist.head.next = second; //linking the head (1st) with the second node. these are both now linked.
second.next = third; //linking second with third. now linked. all 3 are linked now
llist.printList();
}
} //end of class program

Related

How to implement user inputted integers in a sorted linked list?

As stated in in the title, I would like to know how to allow the user to push the integers and print them. I have written another simple program where the user can press keys to do a few things, like push/pop/print, would it be possible to merge them even if the one is just an ordinary stack and another is a linked list?
This is is the first program that simply lets the user add a string, push/pop/print:
class Program
{
static void Main(string[] args)
{
Stack<string> mystack = new Stack <string>();
int number = -1;
while (number != 0)
{
Console.WriteLine("1- enter string");
Console.WriteLine("2 - delete string");
Console.WriteLine("3- print all strings");
Console.WriteLine("0- Exit");
number = Convert.ToInt32(Console.ReadLine());
{
switch (number)
{
case 1:
Console.Write("Enter string: ");
mystack.Push(Console.ReadLine());
break;
case 2:
mystack.Pop();
Console.WriteLine("first string deleted");
break;
case 3:
foreach (string i in mystack)
{
Console.WriteLine(i);
}
break;
}
}
}
Console.ReadKey();
}
}
}
This is the second which is a linked list sorted in ascending order but the integers are inputted by the coder.
{
class LinkedList
{
public class node
{
public int data;
public node next;
};
static node start;
static void sortList(node head)
{
int startVal = 1;
while (head != null)
{
head.data = startVal;
startVal++;
head = head.next;
}
}
static void push(node head_ref,
int new_data)
{
node new_node = new node();
new_node.data = new_data;
new_node.next = head_ref;
head_ref = new_node;
start = head_ref;
}
static void printList(node node)
{
while (node != null)
{
Console.Write(node.data + " ");
node = node.next;
}
}
public static void Main(String[] args)
{
start = null;
push(start, 2);
push(start, 1);
push(start, 6);
push(start, 4);
push(start, 5);
push(start, 3);
sortList(start);
printList(start);
Console.ReadKey();
}
You are trying to merge the functionality of two different data types that have different usage.
Stack and Linked List are two linear data structures. A programmer can implement them using any programming language. The main difference between Stack and Linked List is that a Stack works according to the FIFO mechanism while a Linked List works by storing the data and the addresses of other nodes to refer to each other.
In a stack, the topmost element can be read. On the other hand, in a linked list, if the programmer wants to access a specific element, it is necessary to traverse each element from the beginning.
Though you can use the combination of both in such a way to push the data to stack in a sorted manner.
Reference: https://pediaa.com/what-is-the-difference-between-stack-and-linked-list/#:~:text=A%20stack%20is%20an%20abstract,between%20stack%20and%20linked%20list.

Create a list referencing object in another list

using c# I have read an XML file into an XML document and I use XPath to get a list of XMLNodes in an XMLNodeList codelist. I am wanting to create a separate List BlankCodes that has reference to any XmlNodes in codelist that meet a criteria.
so my current code that creates a list of XmlNodes of interest looks like the below.
XmlDocument xDoc = new XmlDocument();
xDoc.Load("C:\\Test.XML");
List<int> blankCodes = new List<int>();
XmlNodeList codeList = xDoc.SelectNodes("codelist\\Code");
foreach( XmlNode aNode in codeList)
{
if(aNode.Value == "")
{
blankCodes.Add( (int)aNode.Attributes("Index")
}
}
I will then iterate through the integers in the blankCodes list and find the corresponding node in the codeList again and modify another value in the node.
is it possible to essentially create a list of Pointers to the appropriate XmlNodes in codeList? then rather than having to find XmlNodes in codeList by xPath or looping through I can reference the XmlNode directly?
I am more than happy to try and provide clarification if you can guide on what needs clarifying.
Many Thanks bommelding.
------Demo code of working answer below -----------------
using System;
using System.Collections.Generic;
namespace TestReferences
{
/// <summary>
/// Basic Class to with index and value
/// </summary>
class aVal
{
public int Index { get; set; }
public int Value { get; set; }
}
class Program
{
static void Main(string[] args)
{
//Create two lists of class to simulate XML node
List<aVal> originalList = new List<aVal>(); //Proper list as if read from XML
List<aVal> blankList = new List<aVal>(); //List of Blank Codes
//Loop to create 20 instances of class
for(int i = 1; i <= 20; i++)
{
//Create class
aVal temp = new aVal();
temp.Index = i; //Index
temp.Value = i * 2; //Easily Identifiable Value
originalList.Add(temp); //Add to original list
if( i == 4 || i==12 || i == 18) //Simulate Blank Codes
{
blankList.Add(originalList[originalList.IndexOf(temp)]); //Add the instance to blank list so we get a reference,
//I presume that I have to add the one in the list not the temporary instance used to populate the original list
}
}
//Write the original list to the console
//Expected output "Index 1 : Val 2"
Console.WriteLine("******* Original List ***************");
foreach( aVal te in originalList)
{
Console.WriteLine("Index {0} : Val {1}", te.Index, te.Value);
}
//Write the blank list to the console.
Console.WriteLine("******* Blank List ***************");
foreach (aVal te in blankList)
{
Console.WriteLine("Index {0} : Val {1}", te.Index, te.Value);
}
Console.WriteLine("*****************");
Console.WriteLine("Modifying Blanks");
Console.WriteLine("*****************");
//Set each instance.value to -99 referenced by the blanklist
foreach (aVal te in blankList)
{
te.Value = -99;
}
//Check the output, 4,12,18 should have value -99
Console.WriteLine("******* Original List after blanks modified ***************");
foreach (aVal te in originalList)
{
Console.WriteLine("Index {0} : Val {1}", te.Index, te.Value);
}
Console.ReadLine();
}
}
}
Yes, because XmlNodes are normal C# objects. You always work with (through) a reference.
Creating a copy of an instance is a lot more work, especially for the XmlDocument family.
List<XmlNode> blankCodes = new List<XmlNode>();
if(aNode.Value == "")
{
blankCodes.Add(aNode);
}

Finding all possible paths from one node to another?

I was trying to find all possible paths, but I am having hard time keeping track of the paths that I have visited. Here is the code so far:
public void FindAllPaths(Node startNode, Node endNode)
{
queue.Enqueue(startNode);
while (queue.Count > 0)
{
var currentNode = queue.Dequeue();
foreach (var edge in currentNode.Edges)
{
if (edge.Visisted)
continue;
edge.Visisted = true;
queue.Enqueue(edge.TargetNode);
}
}
}
You have to keep track of the paths visited for each route, not globally. For a breadth first approach each route needs a list of visited paths. For a depth first approach you can either keep a list of visited paths, or keep it global but unvisit the paths as you backtrack.
Getting the length of the path and the total weight will more or less do itself, once you keep track of the paths for each route.
With your current algorithm you would enqueue an item that has a node and a list of visited paths:
public void FindAllPaths(Node startNode, Node endNode) {
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0) {
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges) {
if (!currentItem.Visited.Contains(edge)) {
List<Edge> visited = new List<Edge>(currentItem.Visited);
visited.Add(edge);
if (edge.TargetNode == endNode) {
// visited.Count is the path length
// visited.Sum(e => e.Weight) is the total weight
} else {
queue.Enqueue(new QueueItem(edge.TargetNode, visited));
}
}
}
}
}
The QueueItem class is just:
public class QueueItem {
public Node Node { get; private set; }
public List<Edge> Visited { get; private set; }
public QueueItem(Node node, List<Edge> visited) {
Node = node;
Visited = visited;
}
}
I set up the paths this way:
Node a = new Node("A");
Node b = new Node("B");
Node c = new Node("C");
Node d = new Node("D");
Node e = new Node("E");
a.Edges.Add(new Edge(5, b));
a.Edges.Add(new Edge(7, e));
a.Edges.Add(new Edge(5, d));
b.Edges.Add(new Edge(4, c));
c.Edges.Add(new Edge(2, e));
c.Edges.Add(new Edge(8, d));
d.Edges.Add(new Edge(8, c));
d.Edges.Add(new Edge(6, e));
e.Edges.Add(new Edge(3, b));
If you go A-B-C-E then C will be marked as visited, but since C is also part of the path A-D-C-E you won't be able to find the later. Therefore a depth-first approach seems more appropriate, as it allows you to work on one path at a time. After you are finished with a path, you can clear the Visited-flags and continue with another path. I'm trying to scetch a solution in pseudo code:
declare path as list of node;
procedure FindPath(node)
for each edge in node.Edges
if not edge.Visited then
edge.Visited = true
path.Append(edge.TargetNode)
if edge.TargetNode = goal then
Print(path)
else
FindPath(edge.TargetNode)
end
path.Remove(edge.TargetNode)
edge.Visited = false
end
end
end
Where goal is node E in your example. You would call FindPath with the start node
FindPath(A);
As stated previously, maintaining a Visited property on each edge will not work because a given edge may be present in multiple distinct paths. For example, the D/E edge will be traversed for both the A->D->E path and the A->B->C->D->E path.
You need to maintain the current path for each node added to the queue:
IEnumerable<Path> FindAllPaths(Node from, Node to)
{
Queue<Tuple<Node, List<Node>>> nodes = new Queue<Tuple<Node, List<Node>>>();
nodes.Enqueue(new Tuple<Node, List<Node>>(from, new List<Node>()));
List<Path> paths = new List<Path>();
while(nodes.Any())
{
var current = nodes.Dequeue();
Node currentNode = current.Item1;
if (current.Item2.Contains(currentNode))
{
continue;
}
current.Item2.Add(currentNode);
if (currentNode == to)
{
paths.Add(new Path(current.Item2));
continue;
}
foreach(var edge in current.Item1.Edges)
{
nodes.Enqueue(new Tuple<Node, List<Node>>(edge.Target, new List<Node>(current.Item2)));
}
}
return paths;
}

How to get to next list in the List<List<Node>> when particular condition is satisfied

I have a List<Node> nodes and each node in nodes have a variable called Interest associated with it.
public static List<Node> nodes = new List<Node>();
for (int i = 0; i < Program.n; i++)
{
//int densityrandom = generateRandom();
Node n = new Node(Interest3);
Program.nodes.Add(n);
}
While class Node is as Follows:
public class Node
{
public int Density { get; set; }
public InterestProfile P1 { get; set; }
public List<Edge> adjnodes { get; set; }
public Node(InterestProfile a)
{
adjnodes = new List<Edge>();
P1 = a;
}
}
For some object Interest1 of type InterestProfile there is an array associated with it like
Interest1 = new InterestProfile(array1);
So, if you do something like nodes[0].P1.InterestArray[0], it will give me first element in the array1.
Now here is my actual question:
I am splitting up the list nodes according to user input into list of list of Node. Thus, if nodes have 100 elements in it, it will be split up into 10 lists and all those lists will stored in one list.
This is something I have in mind:
List<List<Node>> smallList = new List<List<Node>>();
for (int i = 0; i < nodes.Count; i++)
{
for(int k=0; k < smallList.Count; k++)
{
if (list[i].P1.InterestArray[0] > 5 && smallList[k].Count != 10)
{
smallList[0].Add(list[i]);
}
else smallList[k+1].Add(list[i]);
}
and so on by checking for all 5 elements in an array associated with particular node. However, when smallList[0] reaches limit of 10, I want to start adding elements from nodes in some other smallList[i]. When all the values of particular InterestArray[j] are checked for all nodes in nodes, then only it should move to checking InterestArray[j+1]. How can I program this in c#? Is my implementation correct and if yes can it be improved?
I know question is quite confusing. Please ask me if anything is difficult to understand. Any help will be highly appreciated.
Instead of creating the List<List<Node>> data structure why not simply query your existing List<Node> for the nodes you want when you need them?
e.g.
Old School:
var interestingNodes = new List<Node>();
foreach(Node node in nodes)
{
foreach(int i in note.InterestArray)
{
if(i > 5)
interestingNodes.Add(node);
}
}
Using List<T>.FindAll():
var interstingNodes = nodes.FindAll(node => node.P1.InterestArray.Contains(5));
Or in LINQ:
var interstingNodes = from node in nodes
where node.P1.InterestArray.Contains(5)
select node;

Printing a binary tree in order

I have a problem to convert a sorted array to a binary tree. I think that I have done it. Now I just want to print all items after conversion to double check it.
My question is that my printing part doesn't print all items. Something is wrong in the method 'inOrderTraversalHelper'.
class Program
{
// Given an array where elements are sorted in ascending order,
// convert it to a height balanced BST
static int[] arr = new int[8] {1,2,3,4,5,6,7,8};
static TreeNode node { get; set; }
static void Main(string[] args)
{
node = SortedArrayToBST(arr, 0, arr.Length-1);
inOrderTraversal();
}
static void inOrderTraversal()
{
inOrderTraversalHelper(node);
}
static void inOrderTraversalHelper(TreeNode r)
{
if (r != null)
{
**// UPDATED**
inOrderTraversalHelper(r.leftNode);
Console.Write("{0} ", r.data);
inOrderTraversalHelper(r.rightNode);
}
}
static TreeNode SortedArrayToBST(int[] a,int start,int end)
{
if (start > end) return null;
int mid = (start + end) / 2;
TreeNode node = new TreeNode(a[mid]);
node.leftNode= SortedArrayToBST(a, start, mid-1);
node.rightNode = SortedArrayToBST(a, mid + 1, end);
return node;
}
}
public class TreeNode
{
public int data;
public TreeNode leftNode;
public TreeNode rightNode;
public TreeNode(int data)
{
this.data = data;
}
}
It's because you are storing the value of the index mid not the value at the index of mid:
int mid = (start + end) / 2;
TreeNode node = new TreeNode(mid);
You are calculating the value of mid and then passing it in as the data. Instead mid should be the index of the value you want. For, example if you had a data set where the data was ordered but non sequential you'd get even stranger results:
{-1,22,33,44,55,66,77,100}
So your code should probably look up the value at index mid instead:
var mid = (int)((start + end) / 2.0);
var node = new TreeNode(arr[mid]);
In SortedArrayToBST, you work with the index mid, rather than with the element a[mid], change:
TreeNode node = new TreeNode(mid);
to:
TreeNode node = new TreeNode(a[mid]);
In the call to the SortedArrayToBST function, you need to pass array size - 1, since the end condition in inclusive, change:
node = SortedArrayToBST(arr, 0, arr.Length);
to:
node = SortedArrayToBST(arr, 0, arr.Length-1);
Also, your inOrderTraversalHelper function isn't actually in-order, but rather post-order.

Categories

Resources