search algorithm in multi level list - c#

i have a c# class
public class treeItem
{
public string parentName { get; set; }
public int index { get; set; }
public List<treeItem> children { get; set; }
public treeItem()
{
children = new List<treeItem>();
}
}
i can fill it and sort it by index but i have a problem in search of index in 3rd or n level
function to add index
void AddIndexToTree(List<treeItem> children)
{
for(int i = 0; i < children.Count; i++)
{
count++;
children[i].index = count;
if (children[i].children.Count > 0)
{
AddIndexToTree(children[i].children);
}
}
}
i try to create a search function but have a problem in n level that i remove item from list so i send a copy of list to function but in n level it delete from the original list
treeItem getParentNode(int index, List<treeItem> searchList)
{
if (searchList.Count == 1)
{
if (searchList[0].index == index)
{
return searchList[0];
}
else if (searchList[0].children.Count > 0)
{
for (int i = 0; i < searchList[0].children.Count; i++ )
{
if (searchList[0].children[i].index == index)
return searchList[0].children[i];
}
List<treeItem> tempList = searchList[0].children;
return getParentNode(index, tempList);
}
}
else
{
int length = searchList.Count;
int mid;
if( length % 2 == 0)
{
mid = length / 2;
if (length != 2)
mid--;
}
else
{
mid = length / 2;
}
if (searchList[mid].index == index)
return searchList[mid];
if(searchList[mid].index > index)
{
searchList.RemoveRange(mid, searchList.Count - mid );
return getParentNode(index, searchList);
}
else
{
if (searchList.Count > 2 && searchList[mid + 1].index < index )
searchList.RemoveRange(0, mid + 1);
else
searchList.RemoveRange(0, mid);
return getParentNode(index, searchList);
}
}
return null;
}
any help in my code or another algorithm please ?

Here is an example of a simple recursive search for a specific index in a tree made up from your class: (of course, this should be a method in your class)
public treeItem Find(int index)
{
if(this.Index == index)
return this;
foreach(var child in this.children)
return child.Find(index);
return null; // Index was not found in the current treeItem or any of it's children.
}
Please note that if the treeItems in your children property are ordered by index, you can use a binary search (which is what I think you tried to do).

Related

How to modify my CustLinkedList to implement insert more efficiently

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 to print all the elements that are stored in class Vector?

public class Vector < T>
{
private const int DEFAULT_CAPACITY = 10;
private T[] data;
public int Count { get; private set; } = 0;
public int Capacity
{
get { return data.Length; }
}
public Vector(int capacity)
{
data = new T[capacity];
}
public Vector() : this(DEFAULT_CAPACITY) { }
public T this[int index]
{
get
{
if (index >= Count || index < 0) throw new IndexOutOfRangeException();
return data[index];
}
set
{
if (index >= Count || index < 0) throw new IndexOutOfRangeException();
data[index] = value;
}
}
private void ExtendData(int extraCapacity)
{
T[] newData = new T[Capacity + extraCapacity];
for (int i = 0; i < Count; i++) newData[i] = data[i];
data = newData;
}
public void Add(T element)
{
if (Count == Capacity) ExtendData(DEFAULT_CAPACITY);
data[Count++] = element;
}
public int IndexOf(T element)
{
for (var i = 0; i < Count; i++)
{
if (data[i].Equals(element)) return i;
}
return -1;
}
public void Insert(int index, T element)
{
if (Count == Capacity)
{
ExtendData(DEFAULT_CAPACITY);
}
if (index >= Count || index < 0)
throw new IndexOutOfRangeException();
int tmp = Count;
while (tmp != index)
{
//shuffle
data[tmp] = data[tmp - 1];
tmp--;
}
data[tmp] = element;
Count++;
}
I am working with arrays and vectors. Just wondering how could we create a function which displays all elements in a vector. I am confused because of the data scope. I can write a function for a simple array but how do you do that when you have whole class?
How do i create a function that prints all the elements stored in this vector?

Insert, display, min and max in array list in C#

I'm new in C#. I have this program and I need to add the function for insert, function min, function max, and function display.
namespace unSortedArrayAssignment
{
class unSortedArray
{
public int size;
public int[] array;
//Constructor for an empty unsorted array
public unSortedArray(int MAX_SIZE)
{
array = new int[MAX_SIZE]; //Create a C# array of size MAX_SIZE
size = 0; // Set size of unSortedArray to 0
}
//Append assuming array is not full
public void Append(int value)
{
array[size] = value;
size++;
}
//Remove the last item
public void Remove()
{
if (size != 0)
size--;
}
//Search for an item
public int Search(int value)
{
for (int counter = 0; counter < size; counter++)
{
if (array[counter] == value)
return counter;
}
return -1;
}
//Delete an item
public void Delete(int value)
{
int index = Search(value);
if (index != 0)
{
for (int counter = index; counter < size; counter++)
array[counter] = array[counter + 1];
size--;
}
}
}
}
class unSortedArray
{
public int size;
public int[] array;
public unSortedArray()
{
array = new int[int size here];
}
public int Min()
{
return array.Min();
}
public int Max()
{
return array.Max();
}
public void Insert(int value)
{
Array.Resize<int>(ref array, array.Count() + 1);
array[array.Count() - 1] = value;
}
}

LINQ Query Fails to identify duplicates

I have two custom classes.
The first class contains basic data:
public class Request
{
public Request(int lineID, string partNo, int qty, int reasonID, int typeID)
{
LineID = lineID;
PartNo = partNo;
Qty = qty;
ReasonID = reasonID;
TypeID = typeID;
}
public int LineID { get; private set; }
public string PartNo { get; private set; }
public int Qty { get; internal set; }
public int ReasonID { get; private set; }
public int TypeID { get; private set; }
}
The second class contains a List of these Request objects, with a signature as follows:
public class Requests : IEnumerable<Request>
{
private List<Request> list;
public Requests()
{
list = new List<Request>();
}
public int Add(Request item)
{
if (item != null)
{
foreach (var x in list.Where(r =>
(r.LineID == item.LineID) &&
(r.PartNo == item.PartNo) &&
(r.ReasonID == item.ReasonID) &&
(r.TypeID == item.TypeID)))
{
x.Qty += item.Qty;
return list.IndexOf(x);
}
list.Add(item);
return list.Count - 1;
}
return -1;
}
// other code
}
I am testing my code and adding items is putting new items into the list, but the LINQ query to find duplicates is not working.
If 2 identical items are added to the list, I want my code to be smart enough to simply update the quantity, but it does not seem to be working.
Could someone tell me what is wrong with the LINQ query?
Could someone tell me what is wrong with the LINQ query?
Theoretically it looks OK. I think we need to know more information about your data to be able to find out why it isn't working as you expect. Does the combination of LineID, PartNo, ReasonID, and TypeID uniquely distinguish an item? Since PartNo is a string, are the values case-insensitive (your comparison is case-sensitive)?
If 2 identical items are added to the list, I want my code to be smart enough to simply update the quantity, but it does not seem to be working.
For this I would suggest a different approach. Consider overriding Equals() on your Request type. Then your Add method can just check if the list already contains the item, incrementing the quantity if so and adding it if not:
var idx = list.IndexOf(item);
if(idx != -1)
{
list[idx].Qty += item.Qty;
}
else
{
list.Add(item);
}
Make Request implement IEquatable<Request>, because this is what IndexOf uses:
public bool Equals(Request other) {
return other != null && (this.LineID == other.LineID) && (this.PartNo == other.PartNo) && (this.ReasonID == other.ReasonID) && (this.TypeID == other.TypeID);
}
Then:
public int Add(Request item) {
if (item != null)
{
int ind = list.IndexOf(item);
if (ind == -1)
{
list.Add(item);
return list.Count - 1;
}
else
{
list[ind].Qty += item.Qty;
return ind;
}
}
return -1;
}
You can modify the method by materializing LINQ query. For example:
public int Add(Request item) {
if (item != null) {
foreach (var x in list.Where(r =>
(r.LineID == item.LineID) &&
(r.PartNo == item.PartNo) &&
(r.ReasonID == item.ReasonID) &&
(r.TypeID == item.TypeID)
).ToList()) {
x.Qty += item.Qty;
return list.IndexOf(x);
}
list.Add(item);
return list.Count - 1;
}
return -1;
}
But, because your Requests must be unique, you can use this
public int Add(Request item)
{
if (item != null)
{
var req = list.SingleOrDefault(r =>
(r.LineID == item.LineID) &&
(r.PartNo == item.PartNo) &&
(r.ReasonID == item.ReasonID) &&
(r.TypeID == item.TypeID)
);
if(req!=null)
{
req.Qty += item.Qty;
return list.IndexOf(req);
}
list.Add(item);
return list.Count - 1;
}
return -1;
}

Performance issues with repeatable loops as control part

In my application, i need to show made calls to the user. The user can arrange some filters, according to what they want to see. The problem is that i find it quite hard to filter the calls without losing performance. This is what i am using now :
private void ProcessFilterChoice()
{
_filteredCalls = ServiceConnector.ServiceConnector.SingletonServiceConnector.Proxy.GetAllCalls().ToList();
if (cboOutgoingIncoming.SelectedIndex > -1)
GetFilterPartOutgoingIncoming();
if (cboInternExtern.SelectedIndex > -1)
GetFilterPartInternExtern();
if (cboDateFilter.SelectedIndex > -1)
GetFilteredCallsByDate();
wbPdf.Source = null;
btnPrint.Content = "Pdf preview";
}
private void GetFilterPartOutgoingIncoming()
{
if (cboOutgoingIncoming.SelectedItem.ToString().Equals("Outgoing"))
for (int i = _filteredCalls.Count - 1; i > -1; i--)
{
if (_filteredCalls[i].Caller.E164.Length > 4 || _filteredCalls[i].Caller.E164.Equals("0"))
_filteredCalls.RemoveAt(i);
}
else if (cboOutgoingIncoming.SelectedItem.ToString().Equals("Incoming"))
for (int i = _filteredCalls.Count - 1; i > -1; i--)
{
if (_filteredCalls[i].Called.E164.Length > 4 || _filteredCalls[i].Called.E164.Equals("0"))
_filteredCalls.RemoveAt(i);
}
}
private void GetFilterPartInternExtern()
{
if (cboInternExtern.SelectedItem.ToString().Equals("Intern"))
for (int i = _filteredCalls.Count - 1; i > -1; i--)
{
if (_filteredCalls[i].Called.E164.Length > 4 || _filteredCalls[i].Caller.E164.Length > 4 || _filteredCalls[i].Caller.E164.Equals("0"))
_filteredCalls.RemoveAt(i);
}
else if (cboInternExtern.SelectedItem.ToString().Equals("Extern"))
for (int i = _filteredCalls.Count - 1; i > -1; i--)
{
if ((_filteredCalls[i].Called.E164.Length < 5 && _filteredCalls[i].Caller.E164.Length < 5) || _filteredCalls[i].Called.E164.Equals("0"))
_filteredCalls.RemoveAt(i);
}
}
private void GetFilteredCallsByDate()
{
DateTime period = DateTime.Now;
switch (cboDateFilter.SelectedItem.ToString())
{
case "Today":
period = DateTime.Today;
break;
case "Last week":
period = DateTime.Today.Subtract(new TimeSpan(7, 0, 0, 0));
break;
case "Last month":
period = DateTime.Today.AddMonths(-1);
break;
case "Last year":
period = DateTime.Today.AddYears(-1);
break;
default:
return;
}
for (int i = _filteredCalls.Count - 1; i > -1; i--)
{
if (_filteredCalls[i].Start < period)
_filteredCalls.RemoveAt(i);
}
}
_filtered calls is a list of "calls". Calls is a class that looks like this :
[DataContract]
public class Call
{
private User caller, called;
private DateTime start, end;
private string conferenceId;
private int id;
private bool isNew = false;
[DataMember]
public bool IsNew
{
get { return isNew; }
set { isNew = value; }
}
[DataMember]
public int Id
{
get { return id; }
set { id = value; }
}
[DataMember]
public string ConferenceId
{
get { return conferenceId; }
set { conferenceId = value; }
}
[DataMember]
public DateTime End
{
get { return end; }
set { end = value; }
}
[DataMember]
public DateTime Start
{
get { return start; }
set { start = value; }
}
[DataMember]
public User Called
{
get { return called; }
set { called = value; }
}
[DataMember]
public User Caller
{
get { return caller; }
set { caller = value; }
}
Can anyone direct me to a better solution or make some suggestions.
Try using a foreach loop instead of an explicit for loop with an iterator variable. If _filteredCalls is a List, then _filteredCalls[i] will take O(n) time. Using a foreach will use the built in iterator of the list and will likely get you a speed increase.
Edit: I see you are actually looping backward through _filteredCalls, and also modifying the list.
So something like this would be better:
_filteredCalls = _filteredCalls.Where(c => c.Caller.E164.Length > 4 || c.Caller.E164.Equals("0"))

Categories