Linked List - Problems displaying list and deleting something that isn't there - singly-linked-list

so I have an assignment that creates an alphabetically ordered linked list. I'm having trouble with the following:
Displaying the full list after every insertion and deletion. It only seems to print apple in every step.
Deleting tangerine, something that doesn't exist in the list anymore. I'm not very familiar with try and catch exceptions and I feel like I'm doing it wrong.
Thanks in advance, here is my code:
Node class:
class Node
{
String item; // data item
Node next; // next Node in list
public Node(String i)
{
item = i;
}
public void displayLink() // displays this link
{
System.out.println (item + " ");
}
}
SortedList Class:
class SortedList
{
Node start; // reference to the first item in the list
public SortedList()
{
start = null;
}
public boolean isEmpty() // true if no links
{
return (start == null);
}
public void insert(String key)
{
Node newNode = new Node(key); // creates new Node
Node previous = null; // start at the beginning
Node current = start;
// until end of list,
while (current != null && (current.item.compareTo(newNode.item)<0))
{ // while current isn't null and current.item is equal to newNode.item
previous = current;
current = current.next; // go to the next item
}
if (previous == null) // at beginning of list
start = newNode; // start --> newNode
else // not at the beginning
previous.next = current; // old previous --> newNode
newNode.next = current; // newNode --> old current
}
public Node remove(String key) // return and delete first Node
{
Node temp = start; // saves start
start = start.next; // deletes start
return temp; // returns String
}
public void displayList()
{
System.out.println("List (first to last): ");
Node current = start; // starts at the beginning of the list
while (current != null) // until end of the list
{
current.displayLink(); // prints data
current = current.next; // moves to next Node
}
System.out.println(" ");
}
}
And finally my demo class:
class SortedListDemo
{
public static void main (String [] args)
{
SortedList theSortedList = new SortedList(); // creates new list
theSortedList.insert("apple"); // inserts apple
theSortedList.displayList(); // displays list
theSortedList.insert("orange"); // inserts orange
theSortedList.displayList(); // displays list
theSortedList.insert("kiwi"); // inserts kiwi
theSortedList.displayList(); // displays list
theSortedList.insert("tangerine"); // inserts tangerine
theSortedList.displayList(); // displays list
theSortedList.insert("strawberry"); // inserts strawberry
theSortedList.displayList(); // displays list
theSortedList.remove("apple"); // deletes apple
theSortedList.displayList(); // displays list
theSortedList.remove("strawberry"); // deletes strawberry
theSortedList.displayList(); // displays list
theSortedList.remove("tangerine"); // deletes tangerine
theSortedList.displayList(); // displays list
theSortedList.insert("apple"); // inserts apple
theSortedList.displayList(); // displays list
try
{
theSortedList.remove("tangerine"); // deletes tangerine
theSortedList.displayList(); // displays list
}
catch (NullPointerException tangerine)
{
System.out.println ("Tangerine doesn't exist, so can't be deleted");
}
theSortedList.remove("apple"); // deletes apple
theSortedList.displayList(); // displays list
try
{
theSortedList.remove("tangerine"); // deletes tangerine
theSortedList.displayList(); // displays list
}
catch (NullPointerException e)
{
System.out.println ("Tangerine doesn't exist, so can't be deleted");
}
try
{
theSortedList.remove("apple"); // deletes tangerine
theSortedList.displayList(); // displays list
}
catch (NullPointerException e)
{
System.out.println ("Apple doesn't exist, so can't be deleted");
}
theSortedList.remove("kiwi"); // deletes kiwi
theSortedList.displayList(); // displays list
theSortedList.remove("orange"); // deletes orange
theSortedList.displayList(); // displays list
theSortedList.remove("strawberry"); // deletes apple
theSortedList.displayList(); // displays list
theSortedList.insert("job-well-done"); // inserts job-well-done
theSortedList.displayList(); // displays list
}
}
Here is the output I get:
List (first to last):
apple
List (first to last):
apple
List (first to last):
apple
List (first to last):
apple
List (first to last):
apple
List (first to last):
java.lang.NullPointerException
...
Thanks for all the help, much appreciated.

Well, I seem to have noticed two problems with your program, which can explain your troubles
You're not using the key given in the remove method when searching for the element to delete in the class. You're just deleting de first item (start).
Also, apart from when adding the first element in the list, your insert() method doesn't seem to add any new nodes to it. You can see in the program that you're referencing the "next" node of your newNode to an element in your list (the line "newNode.next = current;" ) but you're not referencing this newNode in any element in your list. That way it can never be iterated. Your list should have at least one element whose "next" node is referencing this newNode.
As a suggestion, you should use your isEmpty() method when displayng and removing items in your list, so you can avoid that exception when you ran your program, which was probalby caused for trying to reference a null node.
This link can help you with using and implementing data types with linked list: http://algs4.cs.princeton.edu/13stacks/
There is also a very interesting course on Coursera about Algorithms which help you further in this matter. It is called Algorithm Part I.
I hope I have managed to help you. Feel free to ask more question and I'll try to answer them.

Related

C++ editing delete function of a class

In my program, the function void UnsortedType::DeleteItem(ItemType item) deletes the user specified item, however it crashes if the user specified item doesn't exist.
void UnsortedType::DeleteItem(ItemType item)
// Pre: item's key has been initialized.
// An element in the list has a key that matches item's.
// Post: No element in the list has a key that matches item's.
{
int location = 0;
while (item.ComparedTo(info[location]) != EQUAL)
location++;
info[location] = info[length - 1];
length--;
}

Red-Black Tree rebalancing crashes on tree rotation

I am implementing a red-black tree. Currently stuck on tree rotations. When I rotate and assign the new left/right children, I crash and burn. The way I have learned to do left or right rotations on a binary tree is like so (in c++):
void right_rotation(node *&root)
{
auto *temp = root->left;
root->left = temp->right;
temp->right = root;
root = temp;
}
This works fine for an AVL tree.
Here is the RB-tree. I'll try to post the minimum it takes to reproduce this
#include <stdio.h>
struct foo
{
int key;
foo *parent;
foo *left;
foo *right;
int rb; // 0 black, 1 red
foo(int k, foo *p, foo *l, foo *r, int _rb) : key(k), parent(p), left(l), right(r), rb(_rb) {}
};
class rbtree
{
public:
foo *root{};
void insert(int key)
{
if (root != nullptr)
insert(root, root, key);
else
root = new foo(key, nullptr, nullptr, nullptr, 0);
}
void insert(foo *&node, foo *&parent, int key)
{
if (!node) {
node = new foo(key, parent, nullptr, nullptr, 1);
rebalance(node);
} else if (key <= node->key) {
insert(node->left, node, key);
} else {
insert(node->right, node, key);
}
}
void rebalance(foo *&node)
{
if (!node)
return;
if (root == node) {
root->rb = 0;
return;
}
if (node->rb == 1 && node->parent->rb == 1) {
auto *grand_p = node->parent->parent;
foo *aunt;
if (grand_p->left != node->parent)
aunt = grand_p->left;
else
aunt = grand_p->right;
if (!aunt || aunt->rb == 0)
rotate(node, grand_p);
else
color_flip(node);
}
// if there is no parent to the root
if (!node->parent)
root = node;
rebalance(node->parent);
}
void rotate(foo *&node, foo *&grand_parent)
{
if (grand_parent->right->left == node) {
right_left_rot(node);
} // else the rest is not critical
}
void right_rot(foo *&root)
{
auto *grand_p = root->parent;
auto *tmp = root->left;
if (!tmp->left)
printf("\nI am about to crash");
root->left = tmp->right; // segfault here
// the rest of the rotation logic
tmp->right = root;
root->parent = tmp;
if (root->left)
root->left->parent = root;
if (grand_p) {
if (root == grand_p->left)
grand_p->left = tmp;
else if (root == grand_p->right)
grand_p->right = tmp;
}
tmp->parent = grand_p;
}
void right_left_rot(foo *&node)
{
right_rot(node->parent);
// rest not important
}
void color_flip(foo *&node)
{
node->parent->parent->rb = 1;
node->parent->parent->left->rb = 0;
node->parent->parent->right->rb = 0;
if (root->rb != 0)
root->rb = 0;
}
};
int main()
{
rbtree rbt;
rbt.insert(3);
printf("\n%s%d", "Added successfully ", 3);
rbt.insert(1);
printf("\n%s%d", "Added successfully ", 1);
rbt.insert(5);
printf("\n%s%d", "Added successfully ", 5);
rbt.insert(7);
printf("\n%s%d", "Added successfully ", 7);
rbt.insert(6);
printf("\n%s%d", "Added successfully ", 6);
return 0;
}
From what I know, the tmp->left is a nullptr, thus when I am assigning it to the root->left it is normal to segfault. How do I overcome this and both execute this step and not terminate?
I have searched over SO and other internet corners and have seen that people use this approach and they do not complain of this segfault.
If I do a check if (tmp->right) root->left = tmp->right; then the code is not being executed and I am skipping over a critical algorithm step. With this if statement, I get a tree where some of the nodes point to themselves and it gets really messy.
Sample case
To get this situation, I insert 3(root)->1(go left of 3)->5(go right of 3)->7(go right of 5)->6(go left of 7). A balance must be made at 5->7->6. The logic is to do a Right-Left rotation. At the right rotation, this situation is happening
The only time rebalance should reiterate is the case where the aunt is red, and in that case the next node to be handled will be the grandparent, not the parent. If the aunt is black then after the single or double rotation you are done.
Remember, the insert logic is:
insert as normal for any BST
set new node's color to red
LOOP:
if node is root then set node's color black and done
if node's parent's color is black then done
if node's aunt's color is red then set node's parent's and node's aunt's color to black, set node's grandparent's color to red, set node to node's grandparent and go to LOOP
if node is left child of right child or right child of left child then rotate node's parent so it is child to node otherwise set node to node's parent
set node's color to black
set node's parent's color to red
rotate so that node's parent is child to node
done
You appear not to have the "if node is left child of right child or right child of left child then rotate node's parent so it is child to node otherwise set node to node's parent" step at all.
And even the final step you don't exchange the colors of the node and its parent (note at this stage 'node' is the parent of the red violation rather than the child as it started out before the optional rotation).
Also, you have:
if (!aunt || aunt->rb == 0)
but then immediately rotate, the case where the aunt is black is when you should color flip, not rotate.
Okay after a lot of testing I found an interesting case where the code above works. Most noticeable, the line auto *grand_p = root->parent; was causing the problem. If I create a method like
foo *rbtree::parent(foo *root)
{
return *&root->parent;
}
and then access the parent through this method call
auto *grand_p = parent(root);
then there would be no segfault and the whole rotation of the tree would be exactly as it should.
Due to my limited knowledge of compiler optimization and how references are handled underneath, I would assume that the following is happening.
In both cases I am getting a copy of the parent pointer to the grandparent variable, but when this is done through a function, the compiler does not do any optimization and dereferencing, which would cause the segfault.
Here is another question which has a similar topic

How to check if data in linked list exists C++

I'm working on creating a function that will remove an item from a linked list, however, I'm unsure how to check if the item passed to the function exists in the linked list. Because of this, my program crashes in the event that it gets an input it doesn't recognize.
Here is my function:
bool StringList::remove(string rmData){
StringNode *current = new StringNode;
StringNode *previous = new StringNode;
current = head;
while(current->data != rmData){
previous = current;
current = current->next;
}
previous->next = current->next;
}
How can I check if the data exists in the list?
You always need to check if current->next points to a null, if so break;

Why do I lose my QList items when accessing it in another function?

GraphWidget Timeline Image.
I have a list called node1List which stores a list of nodes that are to be displayed in a QGraphicsScene. GraphWidget.cpp is a timeline where the user can click to add nodes. EffectsWidget is another timeline which has the option to add three QLabels to the scene. When these labels are added, I need to add a node to the graphWidget timeline in the same respective place.
list declaration in graphWidget.h:
private:
QList<Node *> node1List;
In graphWidget.cpp, on Mouse Click I create a node and add it to the list:
void GraphWidget::mousePressEvent(QMouseEvent *event)
{
switch (event->button()) {
case Qt::MouseButton::RightButton: {
//... create node
addNode1(newNode, location);
//...
}
break;
}
}
Here is the addNode1 function which is declared in the same graphWidget.cpp:
void GraphWidget::addNode1(Node *newNode,int loc)
{
node1List.insert(loc, newNode);
}
This all works fine and I can access the list of nodes WITHIN the mouse press event.
However now I need to allow these nodes to be also added when a label is added to another class, effectsWidget.cpp.
void EffectsWidget::addEffectsItemStart(){
graphWidget = new GraphWidget();
graphWidget->addLabelsToListAt(sceneStartLabel, 1);
//...
}
and then
void GraphWidget::addLabelsToListAt(QLabel *label, int location)
{
labelListGraphWidget.insert(location, label);
generateNodes(label);
}
So finally, now when I call generateNodes(label), I output the size of the node1List only to find that it is empty?
void GraphWidget::generateNodes(QLabel* label)
{
//The following outputs zero
DBOUT("List size = " << node1List.size() << "\n");
//...create new node
addNode1(newNode, location);
}
If anyone could please explain to me how to retain all the items in a list it would be great thanks! First question here so my apologies if I've messed it up!

Append Item to Linked List

So I am completely and utterly confused on how to append a node to my linked list. Basically, I have an Inventory object (linked list), comprised of nodes containing an ItemStack object. This ItemStack object contains the name of an item and the quantity of that item. Within my Inventory.cpp file I have a function named addItems() that has an ItemStack parameter.
For some reason when I attempt to append an ItemStack node to the end of my list and output the results the only output is the first and last ItemStack. It skips over the ItemStack nodes in the middle. I am not sure if they are just being overwritten or what is going on. I know it has to do with either my Inventory.cpp file or my Inventory.h file, as I am not allowed to modify any other file.
The input for this program is read from two files. itemList-01.txt and inventoryList-01.txt. Furthermore, the number of occupied slots in an inventory are not being being updated. If anyone would care to shed some light on the issues I am having I would greatly appreciate it. I have been at it for days with no progress. I AM ATTACHING A LINK TO ALL OF MY CODE IF THE BELOW CODE IS NOT HELPFUL ENOUGH.(REMEMBER ONLY INVENTORY.CPP and INVENTORY.H CAN BE MODIFIED). Thanks in advance.
https://github.com/brussell757/CS330/tree/master/Assignment_1
START OF INVENTORY.H FILE
#ifndef INVENTORY_H_INCLUDED
#define INVENTORY_H_INCLUDED
#include <iostream>
#include "ItemStack.h"
/**
* An Inventory is composed of n slots. Each slot may store only
* one type of item--specified by *slots*.
* <p>
* Once all slots are filled, no additional Item types may be
* stored. Individual slots may contain any number of the same
* Item.
*/
class Inventory{
private:
/**
* Each Node represents one Inventory slot--i.e., space
*/
struct Node{
ItemStack data; ///< One ItemStack
Node *next; ///< Next ItemStack Node
/**
* Create an empty *Air* Node
*/
Node();
/**
* Create a Node that contains an ItemStack, *s*
*/
Node( ItemStack s );
};
Node *first; ///< First inventory slot
Node *last; ///< Last inventory slot
int slots; ///< Capacity
int occupied; ///< Number of occupied slots
/**
* Disassembles the list for Deconstructor
*/
void disassemble();
public:
/**
* Default to 10 slots
*/
Inventory();
/**
* Create an inventory with n slots
*
* #pre n > 0
*/
Inventory( int n );
/**
* Copy an already existing Inventory
*/
Inventory( const Inventory &src );
/**
* Destruct an Inventory
*/
~Inventory();
/**
* Add one or more items to the inventory list
*
* #return true if *stack* was added and false otherwise
*/
bool addItems( ItemStack stack );
/**
* Print a Summary of the Inventory and all Items contained within
*/
void display( std::ostream &outs ) const;
/**
*
*/
Inventory::Node* begin() const;
/**
*
*/
Inventory::Node* end() const;
/**
* Overloaded assignment operator for Inventory
*/
Inventory& operator=( const Inventory &rhs );
};
/**
* Print the Inventory through use of the display member function
*/
inline std::ostream& operator<<(std::ostream &outs, const Inventory &prt) {
prt.display( outs );
return outs;
}
#endif
START OF INVENTORY.CPP FILE
/**
* Used to add items to the Inventory
*/
bool Inventory::addItems ( ItemStack stack ){
Node* new_node = nullptr;
// Sets new_node equal to a new node containing the current ItemStack
new_node = new Node(stack);
// Insert ItemStack into empty Inventory
if(this->first == nullptr) {
// Sets the first node in the Inventory to the new Node
this->first = new_node;
// Sets the last node in the Inventory to the new Node
this->last = new_node;
// Increase the number of occupied slots by 1
occupied++;
return true;
} else {
// Statement that executes if the maximum number of slots in the Inventory have not been filled
if(occupied <= slots) {
// Sets current node to the head
Node *curr = this->first;
// Sets trail node to nullptr
Node *trail = nullptr;
// Traverse the list
while(curr != nullptr) {
// Sets the (first->next) node to the new_node (new ItemStack)
curr->next = new_node;
// Sets the trail node to the current node (first)
trail = curr;
// Sets the current node to the node after new_node (nullptr)
curr = new_node->next;
return true;
}
// Increase the number of occupied slots by 1
occupied++;
} else {
return false;
}
}
}
In your loop, you're supposed to traverse the list until you get to the end. Once you get to the end of the list, then you add the node.
Not tested, but this is what you more than likely should have done:
Node *curr = this->first;
Node *temp = curr;
while(curr != nullptr)
{
temp = curr;
curr = curr->next;
}
temp->next = new_node;
new_node->next = nullptr;
last = new_node;
This simply traverses the list until it gets to the end. A temporary keeps track of the last node. Then once this is done, you just point the last valid node to the new node.