Right now my loop is
for (TreeNode n = e.Node.FirstNode; n != null; n = n.NextNode)
and my data is something like
a
a1
a2
b
b1
I want to enum breadth only (a, b etc, not a1, a2 etc). How do i do this?
Breadth first enumeration is typically done by using a queue of some sort as an ancillary data structure.
First push the root onto the queue.
Then, while there is something in the queue:
Pop the first item from the front of
the queue.
Push its children onto the end of the queue.
Process the item you popped.
Try
foreach (TreeNode n in e.Node.Parent.Nodes)
you might have to check for a null parent and use
TreeNodeCollection nodes;
if(e.Node.Parent != null)
{
nodes = e.Node.Parent.Nodes;
}
else
{
nodes = e.Node.TreeView.Nodes;
}
This should cover the breadth first algorithm (sorry I haven't tested it)
Queue<TreeNode> currentLevel = new Queue<TreeNode>( nodes );
Queue<TreeNode> nextLevel = new Queue<TreeNode>();
while( currentLevel.Count > 0 )
{
while( currentLevel.Count > 0 )
{
TreeNode n = currentLevel.Dequeue();
// Add child items to next level
foreach( TreeNode child in n.Nodes )
{
nextLevel.Enqueue( child );
}
}
// Switch to next level
currentLevel = nextLevel;
nextLevel = new Queue<TreeNode>();
}
Modify code provided by bstoney
1. push root node to currentLevel queue
2. mark nextLevel = new Queue();
Queue<TreeNode> currentLevel = new Queue<TreeNode>();
Queue<TreeNode> nextLevel = new Queue<TreeNode>();
// 1. push root to the queue
currentLevel.Enqueue(treeView1.Nodes[0]);
// pop the first item from the front of the queue
while (currentLevel.Count > 0)
{
while (currentLevel.Count > 0)
{
TreeNode n = currentLevel.Dequeue();
Console.WriteLine(n.Text);
// Add child items to next level
foreach (TreeNode child in n.Nodes)
{
nextLevel.Enqueue(child);
}
}
// Switch to next level
currentLevel = nextLevel;
// 2. mark this line
//nextLevel = new Queue<TreeNode>();
}
Related
I'm implementing A* in Unity so my NPCs can navigate through the world.
The nodes are Vector3s in the game, and they have a class called WaypointController on them.
Each waypoint has a list of adjacent nodes in the graph.
All my A* function needs to do is start at the closest node to the NPC that is within their line of sight, then do A* to the node within line of sight of where they're headed and closest.
I am pretty sure my A* finds the node with the lowest f score in the open set.
Then takes it out of open and puts it into the closed set.
Then breaks if current node is the destination.
Then looks at all nodes adjacent to the current node, and updates their f score and h score, and sets current node as the adjacent node's node before it.
Something is definitely wrong because it crashes unity when I call it.
...
public List GetPath(WaypointController start, WaypointController end)
{
List path = new List();
//Don't interrupt other GetPath calls
if (findingPath == false)
{
findingPath = true;
//nodes to evaluate
List<WaypointController> openNodes = new List<WaypointController>();
//evaluated nodes
List<WaypointController> closedNodes = new List<WaypointController>();
//Setup start & end
start.pathLengthToA = 0;
start.distanceToZ = Vector3.Distance(start.transform.position, end.transform.position);
end.distanceToZ = 0;
//node being evaluated
WaypointController currentNode = start;
//Add start node to open
openNodes.Add(currentNode);
//Evaluate nodes in the open set until currentNode = end
do {
//currentNode = lowest F cost node in openNodes
foreach(WaypointController openWPC in openNodes)
{
if(openWPC.pathLengthToA + openWPC.distanceToZ < currentNode.pathLengthToA + currentNode.distanceToZ)
{
Debug.Log("A* using: " + openWPC);
currentNode = openWPC;
}
}
//Move currentNode from openNodes to closedNodes
openNodes.Remove(currentNode);
closedNodes.Add(currentNode);
//Break if path complete
if(currentNode == end)
break;
//For each adjacent node to currentNode
float tempEdgeLength;
foreach(WaypointController adjWPC in currentNode.adjacentNodes)
{
//Skip closed nodes
if(closedNodes.Contains(adjWPC))
continue;
//If new path to adjacent node is shorter, or adjacent node is not in open (set it up)
graph.TryGetEdge(currentNode, adjWPC, out tempEdgeLength);
if(currentNode.pathLengthToA + tempEdgeLength < adjWPC.pathLengthToA || openNodes.Contains(adjWPC) == false)
{
Debug.Log("A* is evaluating node: " + adjWPC.name);
//set f cost of neighbor
adjWPC.pathLengthToA = currentNode.pathLengthToA + tempEdgeLength;
adjWPC.distanceToZ = Vector3.Distance(adjWPC.transform.position, end.transform.position);
//set nodeBeforeThisInPath in neighbor to currentNode
adjWPC.nodeBeforeThisInPath = currentNode;
//add neighbor to openNodes
if(openNodes.Contains(adjWPC) == false)
openNodes.Add(adjWPC);
}
}
} while (currentNode != end);
//Output it
path.Add(start.transform.position);
while (currentNode.nodeBeforeThisInPath != start)
{
path.Add(currentNode.nodeBeforeThisInPath.transform.position);
}
path.Add(end.transform.position);
//free up the function
findingPath = false;
}
else
{
path.Add(Vector3.zero);
}
//Return the path or an empty path if findingPath was already true (& handle retry in the other script
return path;
}
...
Thanks for joining me on this puzzle.
I will post any updates as I discover them.
I'm taking lines (I:3, I:6, D:5, etc) from a text file and splitting them on the colon. Then, taking the number after the colon and pushing it to a node in a linked list. Depending on the line, it will insert(I) or delete(D) the node. However, I'm having trouble deleting a node. I created a method called deleteNode()
I reference this method in my if statement to check whether or not the command in the file starts with I or D to be told whether it gets inserted or deleted or not. I'm having trouble on how to reference the node to be deleted in llist.deletenode();
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;
int count = 0;
while (n != null)
{
count++;
Console.Write("Node" + count + ":" + " " + n.data + " ");
n = n.next;
}
}
public void push(int new_data)
{
// ads node to list
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; //moving head to point to the new node
}
public static void deleteNode(Node node, Node n)
{
// deletes node from list
// find the previous node
Node prev = node;
while (prev.next != null && prev.next != n)
{
prev = prev.next;
}
// Check if node really exists in Linked List
if (prev.next == null)
{
Console.WriteLine("Given node is not" +
"present in Linked List");
return;
}
// Remove node from Linked List
prev.next = prev.next.next;
// Free memory
GC.Collect();
return;
}
}
// 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();
string[] lines = File.ReadAllLines(#"C:\\Users\project\text.txt");
foreach (string line in lines)
{
// splitting the lines on the colon
string[] bits = line.Split(':');
// taking the bit after the colon and parsing
// into an integer - the i is already parsed
int x = int.Parse(bits[1]); //the value after colon
if (bits[0] == "i")
{
llist.push(x);
}
else if (bits[0] == "d")
{
deleteNode(llist, existingNode); //error here
}
}
llist.printList();
}
I think the logic should probably match that of the push method (not sure why push isn't called Add or Insert instead, though...), in that it should look for the first node whose data matches the data we want to delete.
If we start at the head, we first want to determine if the head should be deleted. If so, then we reset the head to head.next and we're done!
Otherwise, we examine head.Next to see if it's the one to delete. If it is, then we set head.Next equal to head.Next.Next, effectively removing head.Next from our list (no node is pointing to it anymore).
If head.Next is not the node to delete, then we move to the next node and continue the process.
Here's an example:
public void DeleteNode(int nodeData)
{
// First check if the head is the node to delete
if (head != null && head.data == nodeData)
{
// If it is, set the head to the next node (effectively removing it from the list)
head = head.next;
return;
}
// Start at the head node
var current = head;
while (current != null)
{
// Get the next node
var next = current.next;
// See if the next node is the one to delte
if (next != null && next.data == nodeData)
{
// It is, so set the current node's Next pointer to the *next* node's
// Next pointer (effectively removing the Next node from the list)
current.next = next.next;
return;
}
// Update our current node to the next one and keep looking
current = next;
}
}
There are a lot of issues with your code ranging from aesthetic (name casing), to syntax errors, to design errors (static functions instead of methods).
I am offering some cleanup and an example below. The result is
Print List:
Node1: 0 Node2: 1 Node3: 2 Node4: 3 Node5: 4 Node6: 5
Deleting 4
Print List:
Node1: 0 Node2: 1 Node3: 2 Node4: 3 Node5: 5
and the sample code. The main addition is a separate function that finds the previous node FindPrevious() and use the existing Head of the list in DeleteNode().
Also changed fields into properties and PascalCasing as recommended per C# design rules.
namespace ConsoleApp1
{
public class Node
{
public int Data { get; set; }
public Node Next { get; set; }
// constructor
public Node(int data)
: this(null, data)
{ }
// always add a full constructor
public Node(Node next, int data)
{
this.Data = data;
this.Next = next;
}
}
public class LinkedList
{
public Node Head { get; set; }
public string PrintList()
{
// traversing list and printing the contents starting from head(1)
Node n = Head;
int count = 0;
StringBuilder sb = new StringBuilder();
while (n != null)
{
count++;
sb.Append("Node" + count + ":" + " " + n.Data + " ");
n = n.Next;
}
return sb.ToString();
}
// adds node to list
public void Push(int data)
{
//allocate new node, put in data
//and make next of new node as head
//moving head to point to the new node
Head = new Node(Head, data);
}
public Node FindPrevious(Node node)
{
Node n = Head;
while (n!=null)
{
if (n.Next == node)
{
return n;
}
n = n.Next;
}
return null;
}
public void DeleteNode(Node node)
{
if (node==null)
{
return;
}
Node prev = FindPrevious(node);
if (prev!=null)
{
// skip over node
prev.Next = node.Next;
}
}
}
static class Program
{
static void Main(string[] args)
{
LinkedList llist = new LinkedList();
llist.Push(5);
llist.Push(4);
llist.Push(3);
llist.Push(2);
llist.Push(1);
llist.Push(0);
Console.WriteLine($"Print List:");
Console.WriteLine(llist.PrintList());
Console.WriteLine();
var existingNode = llist.Head.Next.Next.Next.Next;
Console.WriteLine($"Deleting {existingNode.Data}");
llist.DeleteNode(existingNode);
Console.WriteLine($"Print List:");
Console.WriteLine(llist.PrintList());
}
}
}
DeleteNode method takes in two arguments. You are using deleteNode as an extension method but it's a simple method with two inputs.
deleteNode(llist, nodeYouWantToDelete);
Also, your loop that checks for D isn't right
if (bits[0] == "i") { //loop that checks if command starts with i (for inserting)
llist.push(x);
} else if(bits[0] == "d") { // CHECK bits[0] not [1]
// Get the node that matches value
// check here if the node already exists then delete
deleteNode(llist, existingNode);
}
update
public void push(int new_data) { //ads node to list
Node new_node = new Node(new_data); //allocate new node, put in data
new_node.next = null; //next should always be null.
// start from head and find the node whose next = null, point that to new_node
}
public void deleteNode(Node nodeToDelete) { //deletes node from list
// start from head and keep going next until node.next = nodeToDelete
// set node.next = node.next.next;
}
Working Solution for you
public class LinkedList
{
Node head;
Node last;
public class Node
{
public int data;
public Node next;
public Node(int d)
{
data = d;
next = null;
} // end of constructor
}
public void print()
{
// traversing list and printing the contents starting from head(1)
Node n = head;
int count = 0;
while (n != null)
{
Console.Write("Node" + count++ + ":" + " " + n.data + " ");
n = n.next;
}
}
public void push(int new_data)
{
Node thisNode = new Node(new_data);
if (head == null)
{
head = thisNode;
last = head;
return;
}
last.next = thisNode;
last = last.next;
}
public void delete(Node node)
{
if (head.data == node.data)
head = head.next;
else
{
Node iterate = head;
bool deleted = false;
while (iterate.next != null)
{
if (iterate.next.data == node.data && !deleted)
{
iterate.next = iterate.next.next;
deleted = true;
continue;
}
iterate.next = iterate.next.next;
}
last = iterate;
if (!deleted)
{
Console.WriteLine("Given node is not " +
"present in Linked List");
}
// Free memory
GC.Collect();
return;
}
}
}
//and use it in the main like,
public static void Main(string[] args)
{
LinkedList llist = new LinkedList();
string[] lines = new[] { "i:1", "i:3", "d:3", "i:2", "i:1", "d:3" };
foreach(string line in lines)
{
string[] split = line.Split(':');
if (split[0] == "i") // INSERTS At the end of the list.
llist.push(int.Parse(split[1]));
else if (split[0] == "d") // Deletes the "FIRST" occurence of said number
llist.delete(new LinkedList.Node(int.Parse(split[1])));
}
Console.Read();
}
I try to remove an element after a specified node, code doesn't give me an error but doesn't to its job .
public List<int> list;
public class Node
{
public object Cont;
public Node Next;
}
public Node head;
linkedlist()
{
head = null;
}
public linkedlist(object value)
{
head = new Node();
head.Cont = value;
}
public void removeAfter(int nume1)
{
Node currentnode = head;
int current = 0;
while (current <= nume1 && currentnode.Next != null)
{
currentnode = currentnode.Next;
current++;
}
currentnode = currentnode.Next;
}
I try to remove the element on the "nume1"th position from the LinkedList.
I know c# has a built-in LinkedList but I need to work on this one. The file has more code but I think this is enough to get a proper answer
In order to remove an item after another item in a singly-linked list, we simply need to set Item.Next = Item.Next.Next. This effectively removes the Node at Item.Next from the list because:
If we have a node "first" at index 0, then it's Next will point to "second" at index 1, and second.Next will point to "third" at index 2
So first.Next.Next points to "third" at index 2
And setting first.Next = first.Next.Next changes the next item for "first" to "third".
For example:
class Node
{
public string Data { get; set; }
public Node Next { get; set; }
}
class LinkedList
{
public Node Head { get; private set; }
public void Add(string data)
{
var node = new Node {Data = data};
if (Head == null)
{
Head = node;
}
else
{
var current = Head;
while (current.Next != null) current = current.Next;
current.Next = node;
}
}
public void RemoveAfterIndex(int index)
{
if (index < -1) return;
if (index == -1)
{
Head = Head.Next;
return;
}
var current = Head;
var count = 0;
while (count < index && current.Next != null)
{
current = current.Next;
count++;
}
current.Next = current.Next?.Next;
}
public void WriteNodes()
{
var current = Head;
var index = 0;
while (current != null)
{
Console.WriteLine(current.Data.PadRight(10) + $" (index {index++})");
current = current.Next;
}
}
}
If we wanted to create a list with 10 nodes, and then remove the node after the node at index 3, it might look something like:
private static void Main()
{
var linkedList = new LinkedList();
for (int i = 0; i < 10; i++)
{
linkedList.Add($"Item #{i + 1}");
}
linkedList.WriteNodes();
var dash = new string('-', 25);
Console.WriteLine($"{dash}\nCalling: RemoveAfterIndex(3)\n{dash}");
linkedList.RemoveAfterIndex(3);
linkedList.WriteNodes();
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
In a single-linked list you remove element n by setting Next on element n-1 to element n+1. Since each element has a reference to the following element you need to iterate through the list until you locate element n, retaining the previous element as you go. Then it's just a simple assignment to cut the element from the list.
In code this looks something like:
public void RemoveAt(int position)
{
// reference to current position in list
Node current = head;
// check for empty list
if (current == null)
return;
// special case if we're removing the first item in the list
if (position == 0)
{
root = current.Next;
return;
}
// reference to previous position in list
Node previous = null;
// scan through the array to locate the item to remove
for (int i = 0; i < position && current != null; i++)
{
// update previous reference
previous = current;
// step to next element in list
current = current.Next;
}
if (previous != null && current != null)
{
previous.Next = current.Next;
}
}
Where you say this:
currentnode = currentnode.Next;
You should consider saying this:
currentnode.Next = currentnode.Next?.Next;
If you think about it, to remove the 5th node in a list, you want to make the .Next property of the 4th node, point to node 6. If you're looking at the 4th node, you want its .Next (pointing to 5) to be the .Next.Next (pointing to 5.pointing to 6) instead.
The ? after the first .Next helps us out if we are at the end of the list. If we are looking at the last item in a list, then .Next is null, so calling .Next.Next would result in a NullReferenceException. The ?prevents this by realising the first .Next is null and not trying to evaluate the second .Next on something that is null, but instead stopping evaluation early and returning a null at that point
It is conceptually equivalent to
currentnode.Next = (currentnode.Next == null ? null : currentNode.Next.Next);
It can be done any number of times:
a = b.C?.D?.E?.F;
If any of C, D, E is null, a will end up null without causing an exception. You don't need it after F because if only the last thing is null no exception occurs - we aren't accessing any method or property of the null F
Couple of other points:
Microsoft's own LinkedList has a method of removing nodes based on position, called RemoveAt. It's more useful than RemoveAfter because if can remove the first node in the list, whereas RemoveAfter cannot, unless you take the slightly counterintuitive approach that supplying any index less than the start index will remove the first node (e.g RemoveAfter(-1)). You could create a RemoveBefore or RemoveFirst, but it does add a bit of unnecessary complexity. Generally if taking the academic exercise of re-implementing a class that already exists somewhere in the framework, it's a sensible notion to model your methods on the existing one then it's a good overall fit for "the Microsoft way" in which the rest of the framework is written; fellow developers used to "the Microsoft way" will appreciate it if you're writing a library for them to use
Your naming convention (lowercase first letter for method) is java form, and I did wonder if you were using java but tagged c# for some reason. I'm not sure if null promoting ? exists in java- if it doesn't the inline-if form given last will also work fine.
So I have implemented an Binary search tree using a parameterized List i.e.
List<Node> tree = new List<>();
The tree works fine. The node itself doesn't know anything about its parent or children. This is because I calculate the locations based on the index e.g.
If i is the index of some None N then:
N's left child is in tree[i*2]
N's right child is in tree[(i*2)+1]
This binary tree works fine. But now I want to put AVL tree features to it. Im am stuck at this point because I do not know how to make the rotations on a List. On rotation, how do i move the children of the new root? Fact is they have to shift indexes don't they? Also doing this on an List gives me the problem that displaying the tree will require looping through the List everytime i add a node. THis wont happen in O(logn) anymore destroying the whole point of an AVL tree.
I am doing this in C#. I just want to know how to make this AVL tree efficiently using a List or any array based data structure thats indexable and not a Linked list. This is important.Some code to illustrate would be greatly appreciated.
Representing a tree in an array/list the way you are doing is common for the heap data structure, but it does not work for virtually any other kind of tree. In particular, you cannot do this (efficiently) for AVL trees because each rotation would require too much copying.
I had a need for this for an embedded application where we did not have malloc available. Having not any done any kind of data structure algorithm implementation before I was trying if it could be done. While writing code I realized I would have to move a lot of things around. I searched for a remedy and got to this post.
Thanks to Chris's reply, I am not going to spend any more time on it. I will find some other way to implement what I need.
I believe I found an answer, the Trick is to move subtrees up and down the list so that you don't overwrite valid nodes while rotating.
void shiftUp(int indx, int towards) {
if (indx >= size || nodes[indx].key == NULL) {
return;
}
nodes[towards] = nodes[indx];
nodes[indx].key = NULL;
shiftUp(lChild(indx), lChild(towards));
shiftUp(rChild(indx), rChild(towards));
}
void shiftDown(int indx, int towards) {
if (indx >= size || nodes[indx].key == NULL) {
return;
}
// increase size so we can finish shifting down
while (towards >= size) { // while in the case we don't make it big enough
enlarge();
}
shiftDown(lChild(indx), lChild(towards));
shiftDown(rChild(indx), rChild(towards));
nodes[towards] = nodes[indx];
nodes[indx].key = NULL;
}
As you can see this is done by exploring recursively each subtree until the NULL (defined in this as -1) nodes then copying each element one by one up or down.
with this we can define the 4 types of rotations named according this Wikipedia Tree_Rebalancing.gif
void rotateRight(int rootIndx) {
int pivotIndx = lChild(rootIndx);
// shift the roots right subtree down to the right
shiftDown(rChild(rootIndx), rChild(rChild(rootIndx)));
nodes[rChild(rootIndx)] = nodes[rootIndx]; // move root too
// move the pivots right child to the roots right child's left child
shiftDown(rChild(pivotIndx), lChild(rChild(rootIndx)));
// move the pivot up to the root
shiftUp(pivotIndx, rootIndx);
// adjust balances of nodes in their new positions
nodes[rootIndx].balance--; // old pivot
nodes[rChild(rootIndx)].balance = (short)(-nodes[rootIndx].balance); // old root
}
void rotateLeft(int rootIndx) {
int pivotIndx = rChild(rootIndx);
// Shift the roots left subtree down to the left
shiftDown(lChild(rootIndx), lChild(lChild(rootIndx)));
nodes[lChild(rootIndx)] = nodes[rootIndx]; // move root too
// move the pivots left child to the roots left child's right child
shiftDown(lChild(pivotIndx), rChild(lChild(rootIndx)));
// move the pivot up to the root
shiftUp(pivotIndx, rootIndx);
// adjust balances of nodes in their new positions
nodes[rootIndx].balance++; // old pivot
nodes[lChild(rootIndx)].balance = (short)(-nodes[rootIndx].balance); // old root
}
// Where rootIndx is the highest point in the rotating tree
// not the root of the first Left rotation
void rotateLeftRight(int rootIndx) {
int newRootIndx = rChild(lChild(rootIndx));
// shift the root's right subtree down to the right
shiftDown(rChild(rootIndx), rChild(rChild(rootIndx)));
nodes[rChild(rootIndx)] = nodes[rootIndx];
// move the new roots right child to the roots right child's left child
shiftUp(rChild(newRootIndx), lChild(rChild(rootIndx)));
// move the new root node into the root node
nodes[rootIndx] = nodes[newRootIndx];
nodes[newRootIndx].key = NULL;
// shift up to where the new root was, it's left child
shiftUp(lChild(newRootIndx), newRootIndx);
// adjust balances of nodes in their new positions
if (nodes[rootIndx].balance == -1) { // new root
nodes[rChild(rootIndx)].balance = 0; // old root
nodes[lChild(rootIndx)].balance = 1; // left from old root
} else if (nodes[rootIndx].balance == 0) {
nodes[rChild(rootIndx)].balance = 0;
nodes[lChild(rootIndx)].balance = 0;
} else {
nodes[rChild(rootIndx)].balance = -1;
nodes[lChild(rootIndx)].balance = 0;
}
nodes[rootIndx].balance = 0;
}
// Where rootIndx is the highest point in the rotating tree
// not the root of the first Left rotation
void rotateRightLeft(int rootIndx) {
int newRootIndx = lChild(rChild(rootIndx));
// shift the root's left subtree down to the left
shiftDown(lChild(rootIndx), lChild(lChild(rootIndx)));
nodes[lChild(rootIndx)] = nodes[rootIndx];
// move the new roots left child to the roots left child's right child
shiftUp(lChild(newRootIndx), rChild(lChild(rootIndx)));
// move the new root node into the root node
nodes[rootIndx] = nodes[newRootIndx];
nodes[newRootIndx].key = NULL;
// shift up to where the new root was it's right child
shiftUp(rChild(newRootIndx), newRootIndx);
// adjust balances of nodes in their new positions
if (nodes[rootIndx].balance == 1) { // new root
nodes[lChild(rootIndx)].balance = 0; // old root
nodes[rChild(rootIndx)].balance = -1; // right from old root
} else if (nodes[rootIndx].balance == 0) {
nodes[lChild(rootIndx)].balance = 0;
nodes[rChild(rootIndx)].balance = 0;
} else {
nodes[lChild(rootIndx)].balance = 1;
nodes[rChild(rootIndx)].balance = 0;
}
nodes[rootIndx].balance = 0;
}
Note that in cases where shifting would overwrite nodes we just copy the single node
As for efficiency storing the balance in each node would be a must as getting the differences of heights at each node would be quite costly
int getHeight(int indx) {
if (indx >= size || nodes[indx].key == NULL) {
return 0;
} else {
return max(getHeight(lChild(indx)) + 1, getHeight(rChild(indx)) + 1);
}
}
Though doing this requires us to update the balance at affected nodes when modifying the list, though this can be somewhat efficiently by only updating strictly necessary cases.
for deletion this adjustment is
// requires non null node index and a balance factor baised off whitch child of it's parent it is or 0
private void deleteNode(int i, short balance) {
int lChildIndx = lChild(i);
int rChildIndx = rChild(i);
count--;
if (nodes[lChildIndx].key == NULL) {
if (nodes[rChildIndx].key == NULL) {
// root or leaf
nodes[i].key = NULL;
if (i != 0) {
deleteBalance(parent(i), balance);
}
} else {
shiftUp(rChildIndx, i);
deleteBalance(i, 0);
}
} else if (nodes[rChildIndx].key == NULL) {
shiftUp(lChildIndx, i);
deleteBalance(i, 0);
} else {
int successorIndx = rChildIndx;
// replace node with smallest child in the right subtree
if (nodes[lChild(successorIndx)].key == NULL) {
nodes[successorIndx].balance = nodes[i].balance;
shiftUp(successorIndx, i);
deleteBalance(successorIndx, 1);
} else {
int tempLeft;
while ((tempLeft = lChild(successorIndx)) != NULL) {
successorIndx = tempLeft;
}
nodes[successorIndx].balance = nodes[i].balance;
nodes[i] = nodes[successorIndx];
shiftUp(rChild(successorIndx), successorIndx);
deleteBalance(parent(successorIndx), -1);
}
}
}
similarly for insertion this is
void insertBalance(int pviotIndx, short balance) {
while (pviotIndx != NULL) {
balance = (nodes[pviotIndx].balance += balance);
if (balance == 0) {
return;
} else if (balance == 2) {
if (nodes[lChild(pviotIndx)].balance == 1) {
rotateRight(pviotIndx);
} else {
rotateLeftRight(pviotIndx);
}
return;
} else if (balance == -2) {
if (nodes[rChild(pviotIndx)].balance == -1) {
rotateLeft(pviotIndx);
} else {
rotateRightLeft(pviotIndx);
}
return;
}
int p = parent(pviotIndx);
if (p != NULL) {
balance = lChild(p) == pviotIndx ? (short)1 : (short)-1;
}
pviotIndx = p;
}
}
As you can see this just uses plain arrays of "node"s as i translated it from c code given gitHub array-avl-tree and optimizations and balancing from (a link i'll post in a comment) but would work quite similar in a List
Finally I have minimal knowledge of AVL trees, or optimal implementations so i don't claim that this is bug free or the most efficient but have passed my preliminary tests at least for my purposes
I'm trying to move items in my list but when I compare against the last option I exit out before I move the items in my move linked list. Is there a way to do that before the node gets put at the end and can't loop through to move the items?
LinkedList<BD> list = new LinkedList<BD>(b[arg].Values);
LinkedListNode<BD> node, terminator, next = null;
List<LinkedListNode<BD>> move = new List<LinkedListNode<BD>>();
terminator = list.First;
node = next = list.Last;
while (next != null && next != terminator)
{
node = next;
next = next.Previous;
if (IDs.Contains(node.Value.Id))
{
move.Add(node);
list.Remove(node);
}
else
{
foreach (var item in move)
{
list.AddBefore(node, item);
node = node.Previous;
}
move.Clear();
}
}
Here is what worked for me. I tried different thing and thinks for the help but here is what worked for me more than just moving to the front but also just moving through the list:
while (next != null)
{
node = next;
next = next.Previous;
if (IDs.Contains(Id))
{
move.Add(node);
list.Remove(node);
}
else
{
foreach (var item in move)
{
list.AddBefore(node, item);
node = node.Previous;
}
move.Clear();
}
if (next == null)
{
foreach (var item in move)
{
list.AddFirst(item);
}
move.Clear();
}
}
Your code is interleaving the two lists -- this doesn't look right to me.
I think that instead of the repeated block
foreach (var item in move)
{
list.AddBefore(node, item);
node = node.Previous;
}
move.Clear();
you probably want something like
var before = node.Previous;
var LinkedListNode<BD> current = null;
foreach (var item in move)
{
list.AddBefore(node, item);
current = node = item;
}
current.Previous = before; // assumes move was not empty
move.Clear();
to keep track of where you're inserting.
Something like this? (I tried to base it on your code):
LinkedList<BD> list = new LinkedList<BD>(b[arg].Values);
LinkedListNode<BD> node = list.Last;
LinkedListNode<BD> terminator = null;
while (node != null && node != terminator) {
if (IDs.Contains(node.Value.DocumentVersionId)) {
LinkedListNode<BD> tempNode = node;
node = node.Previous;
list.Remove(tempNode);
list.AddFirst(tempNode);
if (terminator == null) terminator = tempNode;
} else {
node = node.Previous;
}
}
This piece of code should move your "DocumentVersionId-matched" nodes to the front of the linked list.
Below is an example with simple integers to demonstrate how it works:
List<int> specials = new List<int> { 1, 4, 5, 7 };
List<int> source = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
LinkedList<int> list = new LinkedList<int>(source);
LinkedListNode<int> node = list.Last;
LinkedListNode<int> terminator = null;
while (node != null && node != terminator) {
if (specials.Contains(node.Value)) {
LinkedListNode<int> tempNode = node;
node = node.Previous;
list.Remove(tempNode);
list.AddFirst(tempNode);
if (terminator == null) terminator = tempNode;
} else {
node = node.Previous;
}
}
The result linked list will contain:
1, 4, 5, 7 (the specials at the beginning of the linked list), 2, 3, 6, 8
An endless loop should be impossible.
Answer edits:
- node = list.First to node = list.Last
- added an example with integers