I need to overload the ostream operator with new functionality for a doubly linked Skip List class.
When I cout the instance of my class, I want it to iterate through my the levels of my skip list, and wherever the head pointer is pointed to a nullptr I want it to print the level name and a status of empty.
Would look something like:
After adding 7
Level: 4 -- empty
Level: 3 -- empty
Level: 2 -- empty
Level: 1 -- empty
Level: 0 -- 7
I need the number of levels to be dynamically entered. I try to assign int level = SkipList::maxLevels_; but I get the error invalid use of non-static data member
I've made the ostream a friend. How can I instruct it access the maxLevels_ data member?
SkipList.h
#include <stdio.h>
#include <iostream>
#ifndef SKIP_LIST_
#define SKIP_LIST_
using namespace std;
class SkipList
{
private:
struct SkipListNode {
// Convenience constructor to create node, set its data, and set all pointers to nullptr
explicit SkipListNode(int data){
data_ = data;
next_ = NULL;
prev_ = NULL;
upLevel_ = NULL;
downLevel_ = NULL;
}
// data for SNode
int data_;
// link to next at same level
SkipListNode* next_;
// link to previous at same level
SkipListNode* prev_;
// link up one level
SkipListNode* upLevel_;
// link down one level
SkipListNode* downLevel_;
};
// maximum # of levels of SkipList, levels are 0 to maxLevels-1
int maxLevels_;
// array of maxLevels_ SkipListNode pointers as head pointers. For example,
// if maxLevels_ == 2, we'd have Heads[0] and Heads[1]. Dynamically allocated
// by constructor.
SkipListNode** heads_;
// array of maxLevels_ SkipListNode pointers as tail pointers.
SkipListNode** tails_;
// given a pointer to a SkipListNode, place it before the given nextNode
void addBefore(SkipListNode* newNode, SkipListNode* nextNode, int level);
// return true 50% of time,
// each node has a 50% chance of being at higher level
bool alsoHigher() const;
public:
//Constructor
SkipList(){maxLevels_ = 1;}
SkipList(int maxLevels);
//Destructor
// virtual ~SkipList();
// return true if successfully added, no duplicates
bool insert(int item);
// item deletion; return true if successfully removed
bool erase(int item);
// return true if found in SkipList
bool contains(int item) const;
friend ostream& operator<<(ostream& os, const SkipList& list){
int level = SkipList::maxLevels_;
while (level >= 0) {
SkipListNode* temp = list.heads_[level];
if (temp == nullptr) {
os << "Level: " << level << "-- empty";
}
else {
while (temp) {
os << temp->data_ << " ";
temp = temp->next_;
}
}
os << endl;
level--;
}
}
};
#endif
SkipList::maxLevels_; refers to the static maxLevels_ member of the SkipList class.
So, if you need maxLevels_ to be the maximum level of all the instances of SkipList you have to declare it as static.
Otherwise in your overloaded friend function you have to use the private member of the list instance.
friend ostream& operator<<(ostream& os, const SkipList& list){
int level = list.maxLevels_;
...
Related
I'm working on my final project for C++ and my professor specified that we had to have three class files for a linked list.
The first named LinkedList holds the head and the tail, as well as two overloaded operators in which we have to use the list as an array, and add an element to the end of the array.
The second named Node holds the two generic values Seat and Row.
The third and final named RNode holds the values of the next, previous spots in the list, as well as reservation status.
My problem is when using my LinkedList.cpp, defining all of the functions, I cannot figure out how to set node equal to the head, because the types are different. I can set the next node in the list with tempNode.setNext(Head);. But when I try to do tempNode = tempNode.getNext() it says the types are not the same. What is an easy way for me to make this work?
Here is my code.
This is supposed to use the Linked List as an array and return the pointer to the Node correlating with the integer passed in.
int& LinkedList::operator[] (const int &middle) {
RNode *tempNode;
tempNode->setNext(Head);
tempNode = tempNode->getNext(); // Error here
for (int i = 0; i < middle; i++) {
}
}
Here are the three class files I have currently made.
Linked List Class
#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED
#include "Node.h"
class LinkedList {
private:
Node* Head; // Head of linked list
Node* Tail; // Tail of linked list
public:
// Constructors
LinkedList(); // Set default values
LinkedList(Node*, Node*); // Set values passed in to head and tail
int& operator [] (const int &); // Overloaded [] operator PAGE 854 HOW TO USE THIS
// Treat list like an array.
// First node will be [0]
// Return pointer to node indicated inside of brackets
Node& operator += (const Node &); // Overloaded += operator
// Adds a node to the end of the linked list
// Head
void setHead(Node*); // Sets head of list
Node* getHead(); // Returns the head of list
// Tail
void setTail(Node*); // Sets tail of list
Node* getTail(); // Returns tail of list
};
#endif // LINKEDLIST_H_INCLUDED
Reservation Node Class
#ifndef RNODE_H_INCLUDED
#define RNODE_H_INCLUDED
#include "Node.h"
using namespace std;
class RNode : public Node {
private:
Node* Next; // Next node pointer
Node* Prev; // Previous node pointer
bool reservationStatus(); // Reservation status
public:
// Constructors
RNode(); // Sets default values
RNode(Node*, Node*, bool); // Takes values passed in and sets them
// Overloaded operators
friend ostream &operator << (ostream &, Node*); // Prints out correct symbol based on reservation status
friend istream &operator >> (istream &, Node*); // Prints correct symbol based on reservation status .
// Next
void setNext(Node*); // Sets next node in list
Node* getNext(); // Returns next node in list
// Prev
void setPrev(Node*); // Sets previous node in list
Node* getPrev(); // Returns previous node in list
// Reservation Status
void setReservationStatus(bool); // Sets reservation status of a current node
bool getReservationStatus(); // Returns reservation status
};
#endif // RNODE_H_INCLUDED
Node Class
#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED
class Node {
protected:
int row;
int seat;
public:
// Constructors
Node(); // Sets default values
Node(int, int); // Sets row and seat to values passed in
// Row
void setRow(int); // Sets row for current node
int getRow(); // Gets row for current node
// Seats
void setSeat(int); // Sets seat for current node
int getSeat(); // Gets seat for current node
};
#endif // NODE_H_INCLUDED
In summary, how can I match the types so that I can set RNode tempNode equal to a Node? This is very confusing and I can't really find a good explanation on how to solve this.
Keep in mind, according to my instructions I have to have the classes created this way. If it were up to me, I would have combined the RNode and Node class.
I am writing a binary tree search program but I'm not sure how to add nodes and search through them. The nodes come from a .txt file that is being read with a different file so just assume that already works.
The text file looks like:
Name Location
Old Building 31.2222
New Building 21.2111
Like I said, the program already reads in the file so that's not an issue. However, I have to insert the name and location into the nodes of the binary tree. Then I have to search everything within a range which is where the plus minus comes from.
Side note: my copy constructor may be incorrect as well though it complies properly.
Thanks for the help!
#ifndef BINTREE_HPP
#define BINTREE_HPP
#include <utility>
#include <string>
#include <vector>
class bintree {
// A binary search tree for locations in Lineland.
// Notes:
// - Assume a flat, one-dimensional world with locations from -180 to 180.
// - All locations and distances are measured in the same units (degrees).
public:
// Default constructor
bintree() {
this->root = NULL;
}
// Copy constructor
bintree(const bintree &t) {
this -> root = NULL;
*this = t;
}
// Destructor
~bintree() {
}
// Copy assignment is implemented using the copy-swap idiom
friend void swap(bintree &t1, bintree &t2) {
using std::swap;
// Swap all data members here, e.g.,
// swap(t1.foo, t2.foo);
// Pointers should be swapped -- but not the things they point to.
}
bintree &operator= (bintree other) {
// You don't need to modify this function.
swap(*this, other);
return *this;
}
void insert(const std::string& name, double p) {
// insert node with name and location (p)
}
void within_radius(double p, double r, std::vector<std::string> &result) const {
// Search for elements within the range `p` plus or minus `r`.
// Clears `result` and puts the elements in `result`.
// Postcondition: `result` contains all (and only) elements of the
// tree, in any order, that lie within the range `p` plus or minus
// `r`.
}
private:
struct node
{
node *left;
node *right;
};
node* root;
};
#endif
First, your nodes need to hold the data:
struct node
{
node *left;
node *right;
std::string name; // This is the key for your reasearch
double p; // followed by other data
};
Then you can think to browsing through your tree to insert a new node.
In this example, I assume that you can insert several nodes with the same name.
void insert(const std::string& name, double p) {
node *n = new node; // create a new node
n->name=name; n->p=p; // intialise the data payload
n->left=n->right=nullptr; // and make it a leaf.
if (root==nullptr) // if tree is empty,
root = n; // add the new node.
else { // else find where to insert it
node* t=root;
while (true) {
if (t->name > n->name) { // go to left
if (t->left==nullptr) {
t->left = n;
break;
}
else t=t->left;
}
else if (t->name == n->name) { // insert between current and next
n->right = t->right;
t->right = n;
break;
}
else { // go to right
if (t->right==nullptr) {
t->right = n;
break;
}
else t=t->right;
}
}
}
}
Here a live demo.
Note that I have only answered your insertion question, you still have to do a lot on your own (operator= and copy constructor need review, a destructor needs to be created, etc...)
I'm getting a segfault when executing this code. Specifically after g_lru_stack.add_node(&lru_node) is called.
Running under GDB shows that the dummy node doesn't look like it has been initialised. Is this to do with how extern globals are initialised? If so any help would be greatly appreciated here.
I have included snippets from both the header and cpp file.
Specifically, my question is this:
How can I get LRU_Stack g_lru_stack , declared at the top of object.cc, to call the LRU_Node ctor that takes no arguments.
It seems this ctor never gets called, hence why my dummy node isn't initialised.
Object.h
class obj_payload;
extern cas_mutex g_lru_stack_mutex;
class LRU_Node {
private:
obj_payload* payload;
LRU_Node* up;
LRU_Node* down;
size_t predicted_bytes_in_cache;
public:
LRU_Node() : payload(nullptr), up(this), down(this), predicted_bytes_in_cache(1337) {} // Dummy ctor
LRU_Node(obj_payload* p) : payload(p), up(nullptr), down(nullptr), predicted_bytes_in_cache(88) {} // Normal Creation of node
//Adds a node to the top of the stack
//Has dummy context
void add_to_stack(LRU_Node* newNode);
//Sets how many bytes of the object are predicted to be in the cache
//Has dummy context
void is_node_in_cache(LRU_Node* node);
//Moves a node to the top of the stack
//Has dummy context
void move_node_to_top(LRU_Node* node);
//Has context of caller
size_t get_predicted_bytes_in_cache();
};
class LRU_Stack {
LRU_Node dummy;
public:
void add_node(LRU_Node* node);
void move_node_to_top(LRU_Node* node);
};
extern LRU_Stack g_lru_stack;
class obj_payload {
typedef uint32_t ctr_t;
private:
ctr_t refcnt;
const uint32_t sz; // size of the data space in bytes
LRU_Node lru_node; // Jordan -- This arg objects node for the LRU_Stack
obj_payload( typeinfo tinfo_,
uint32_t size_,
int refcnt_init=1 )
: refcnt( refcnt_init ),
sz( size_ ),
tinfo( tinfo_ ), lru_node(this) {
g_lru_stack.add_node(&lru_node);
}
Object.cc
#include "object.h"
namespace obj {
//Jordan -- Global LRU_Node Stack
cas_mutex g_lru_stack_mutex;
LRU_Stack g_lru_stack;
//Adds a node to the top of the stack
//Has dummy context
void LRU_Node::add_to_stack(LRU_Node* newNode) {
newNode->down = down; // Set the new nodes previous -> dummys previous
newNode->up = this; // Set new nodes next -> dummy
down->up = newNode; // Dummy next -> new node (i.e. Previous top of stack node up -> newNode)
down = newNode; // Dummy previous -> new node (i.e. Dummy down pointer now links back round to the new node at the top)
}
//Sets how many bytes of the object are predicted to be in the cache
//Has dummy context
void LRU_Node::is_node_in_cache(LRU_Node* node) {
size_t total = 0;
LRU_Node* orignal = node;
while (node != this) {
total += node->payload->get_size(); // Add current size to total
node = node->up; // Go to next node
}
node = orignal; //Reset node to the passed in node, then set how many bytes it has contained within cache
if (total <= cache_size) {
node->predicted_bytes_in_cache = node->payload->get_size();
}
else {
node->predicted_bytes_in_cache = (node->payload->get_size()) - (total - cache_size) < node->payload->get_size() ? (node->payload->get_size()) - (total - cache_size) : 0;
}
}
//Moves a node to the top of the stack
//Has dummy context
void LRU_Node::move_node_to_top(LRU_Node* node) {
if (down != node) { // Check that the node to move is not already top of stack
node->down->up = node->up;
node->up->down = node->down;
if (down == node->up) { // If the node is seccond top of stack
node->up->up = node;
}
node->down = down;
node->up = this;
down->up = node;
down = node;
}
}
//Has context of caller
size_t LRU_Node::get_predicted_bytes_in_cache() {
return predicted_bytes_in_cache;
}
//Has dummy context
bool LRU_Node::is_empty() {
return (up == this);
}
void LRU_Stack::add_node(LRU_Node* node) {
g_lru_stack_mutex.lock();
dummy.add_to_stack(node);
g_lru_stack_mutex.unlock();
}
void LRU_Stack::move_node_to_top(LRU_Node* node) {
g_lru_stack_mutex.lock();
dummy.is_node_in_cache(node);
dummy.move_node_to_top(node);
g_lru_stack_mutex.unlock();
}
"extern globals" are not objects (unless they include an initializer): They are forward-declarations.
Global objects are initialized in two phases:
All those with compile-time constant initializers are done, the rest is zeroed.
The run-time initializers are run in order of object definition. (No ordering guarantees for objects in different compilation units!).
Seems like UB got you there.
To solve the error, do one of these:
Put the definition of the object before its first use in the same compilation unit (The most efficient method).
Put the object as a static in an accessor function. Init will be on first use (thread-safe!).
Type& getTypeSingleton() {
static Type x/*optional initializer*/;
return x;
}
(Implementation dependent) The compilation unit first mentioned on the command-line will be initialized first in all current implementations (As effifient as the first, but fragile).
i am working on an assignment where i am asked to implement a linked list in c++. so far everything is working great except for when i am creating a new list. in my method create_list(). after i assign content and an id number to my Field and try to call GetNext() i get an error saying: Request for member 'GetNext()' in 'Node' which is a non-class type '*Field'. I'm still new to the C++ syntax and object oriented programming. What am I doing wrong? I thought by using the line Field *Node = new Field(SIZE, EMPTY); that my variable Node would be of class type Field...?
#include <iostream>
#include <ctype.h>
using namespace std;
typedef enum { EMPTY, OCCUPIED } FIELDTYPE;
// Gameboard Size
int SIZE;
class Field {
private:
int _SquareNum;
FIELDTYPE _Content;
Field* _Next;
public:
// Constructor
Field() { }
// Overload Constructor
Field(int SquareNum, FIELDTYPE Entry) { _SquareNum = SquareNum; _Content = Entry; }
// Get the next node in the linked list
Field* GetNext() { return _Next; }
// Set the next node in the linked list
void SetNext(Field *Next) { _Next = Next; }
// Get the content within the linked list
FIELDTYPE GetContent() { return _Content; }
// Set the content in the linked list
void SetContent(FIELDTYPE Content) { _Content = Content; }
// Get square / location
int GetLocation() { return _SquareNum; }
// Print the content
void Print() {
switch (_Content) {
case OCCUPIED:
cout << "Field " << _SquareNum << ":\tOccupied\n";
break;
default:
cout << "Field " << _SquareNum << ":\tEmpty\n";
break;
}
}
}*Gameboard;
here is my create_list() method:
void create_list()
{
int Element;
cout << "Enter the size of the board: ";
cin >> SIZE;
for(Element = SIZE; Element > 0; Element--){
Field *Node = new Field(SIZE, EMPTY);
Node.GetNext() = Gameboard; // line where the error is
Gameboard = Node;
}
}
. is used for addressing members in objects and references to objects. Node, however, is a pointer to an object. So you need to turn it into a reference before you can use it with .. This means doing (*Node).GetNext(). Or you can use the shorthand: Node->GetNext() - these two are exactly equivalent.
A good mnemonic to use is that you use the pointy operator with pointers :)
No in the declaration
Field *Node = new Field(SIZE, EMPTY);
Node is of type pointer to Field.
The fix is simple if you have a pointer to a class and you want to access a member of that class use ->.
Node->GetNext() = Gameboard;
I think your code has other errors, and I don't think that even with this 'fix' it's going to work. Probably what you really want is
Node->SetNext(Gameboard);
You're calling Node.GetNext(), but Node is a pointer. You need to use the -> operator instead of the . operator, as in Node->GetNext().
The function must returns a reference value if you want to set as a l-value.
You code need some changes:
// Get the next node in the linked list
Field& GetNext() { return *_Next; }
then you can use the function as a l-value
Node->GetNext() = *Gameboard;
I'm having problems with the following situation. I have three classes that are involved in this mixup. List, ListNode, City. I have a List<City *>, where the list will be made up of a set of ListNode<City *> (standard wrapper around the list nodes).
City is an abstract class, so there are several classes that inherit from it that could be placed in this list and accessed polymorphically. The List class has a getHead() method which returns a pointer to a ListNode that is the head.
Any city has a population, so to access the populations, I'd expect the following to work. It's not, thus my question. I broke it down into pieces to make it simpler along the way:
ListNode<City *> *head= country->city_list->getHead();
City *headnode = *head->getNode();
cout << "Test: " << headnode->getPopulation() << endl;
getPopulation() returns an integer. country is defined as List<City*> *city; Any help on how I could figure out my problem would be greatly appreciated.
edit adding more code for better idea of what I'm working with. First, ListNode:
template <class T>
class ListNode
{
public:
ListNode() {next = 0;node = 0;};
ListNode(T *t) {node = t; next = 0;};
ListNode(const ListNode &l)
{
//long copy constructor. snip.
};
T *getNode() const { return node; }
ListNode *getNext() const { return next; };
private:
T *node;
ListNode *next;
};
Now, here is what might relevant in the List class..
template <class T>
class List
{
public:
List()
{
head = 0;
size = 0;
};
List(ListNode<T> *t)
{
head = t;
size = 1;
};
List(T *t)
{
head = new ListNode<T>(t);
size = 1;
};
List(const List<T> &t)
{
// long copy constructor. snip.
};
//bunch of irrelevent methods.
ListNode<T> *getHead() const {return head;};
List &operator+=(T &t)
{
this->insert(&t);
size++;
return (*this);
};
private:
List &insert(T *t)
{
ListNode<T> *current = head;
if (current == 0)
{
head = new ListNode<T>(t);
}
else
{
while (current->getNext() != 0)
{
current = current->getNext();
}
current->setNext(new ListNode<T>(t));
}
return (*this);
};
ListNode<T> *head;
int size;
};
I have a hunch that the process of inserting might be the problem. I insert with the List class's += operator, shown in the List implementation above. It calls the private insert method shown above, as well. It looks like this:
City *somecity = new City(x,y,z); //some parameters. integers.
*city_list += somecity; // where city_list is a List.
I think you've got a variable scoping problem.
Your ListNode class contains a pointer to the node value. Your ListNode constructor takes in a pointer to the node value and saves it.
The problem is if that pointer is to a local variable that then goes out of scope. Your ListNode's node pointer is now pointing to an object that doesn't exist. e.g. in this example
addToList(List<int>& myList)
{
int x = 3;
myList += x; // pointer to x is in the list
}
// Out of scope; x no longer exists, but myList has a pointer to it.
// Accessing this node will result in an error.
There are a couple possible remedies:
Have your ListNode contain values rather than pointers. The drawback here is that you will be making copies of the values
Implement ListNode using a reference counted smart pointer which will manager the lifetime of the object.
Well, what you could do is:
ListNode<City *>* head = new ListNode<City*>(country->city_list->getHead());
City* headnode = head->getNode();
cout << "Test: " << headnode->getPopulation() << endl;
It will take the existing City (on the memory) and put it at the head of the List node, and so on.
and if you want to copy them, maybe you could just make this:
ListNode<City *>* head = new ListNode<City*>*(new City(country->city_list->getHead()));
City* headnode = new City(head->getNode());
cout << "Test: " << headnode->getPopulation() << endl;
Hope it will help you.