Can someone help me find/make/point me in the right direction of a disjoint set implementation using Doubly Linked Lists? I have some supplemental code and I've already started editing it, I was wondering if someone could help me fill the rest in or at least give me some pointers on how to do so.
DisjointSet.h
#pragma once
#include "TemplateDoublyLinkedList.h"
#include <cstddef>
#include <iostream>
#include <vector>
using namespace std;
// Disjoint Set
template <typename T>
class DisjointSet {
private:
vector<DListNode<T>*> nodeLocator;
public:
~DisjointSet();
DisjointSet(int n) { nodeLocator.resize(n); }
vector<DListNode<T>*> getNodeLocator() const { return nodeLocator; }
DListNode<T>* MakeSet(int key, T node);
DListNode<T>* Union(DListNode<T> nodeI, DListNode<T> nodeJ);
DListNode<T>* FindSet(DListNode<T> node);
DListNode<T>* FindSet(int nodeKey);
};
template <typename T>
DListNode<T>* DisjointSet<T>::MakeSet(int key, T node)
{
DListNode<T> *temp = new DListNode(key, node);
nodeLocator.insert(nodeLocator.begin() + key - 1, temp);
return temp;
}
template <typename T>
DListNode<T>* DisjointSet<T>::Union(DListNode<T> nodeI, DListNode<T> nodeJ){
if (nodeI.getListSize() >= nodeJ.getListSize())
{
nodeI.getTrailer()->setNext(nodeJ.getRepresentative());
nodeJ.getRepresentative()->setPrevious(nodeI.getTrailer());
nodeI.getRepresentative()->setTrailer(nodeJ.getTrailer());
nodeJ.getRepresentative()->setTrailer(NULL);
nodeJ.getRepresentative()->setRepresentative(nodeI.getRepresentative());
nodeI.setListSize(nodeI.getListSize()+nodeJ.getListSize());
return nodeI.getRepresentative();
}
else if (nodeI.getListSize() < nodeJ.getListSize())
{
nodeJ.getTrailer()->setNext(nodeI.getRepresentative());
nodeI.getRepresentative()->setPrevious(nodeJ.getTrailer());
nodeJ.getRepresentative()->setTrailer(nodeI.getTrailer());
nodeI.getRepresentative()->setTrailer(NULL);
nodeI.getRepresentative()->setRepresentative(nodeJ.getRepresentative());
nodeJ.setListSize(nodeI.getListSize() + nodeJ.getListSize());
return nodeJ.getRepresentative();
}
return NULL;
}
template <typename T>
DListNode<T>* DisjointSet<T>::FindSet(DListNode<T> node){
}
template <typename T>
DListNode<T>* DisjointSet<T>::FindSet(int nodeKey){
if (nodeLocator[nodeKey-1]) != NULL)
return nodeLocator[nodeKey-1];
else
return nullptr;
}
template <typename T>
ostream& DisjointSet<T>::operator<<(ostream& out, const DisjointSet<T>& ds){
}
TemplateDoublyLinkedList.h
#pragma once
#include <string>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
using namespace std;
// list node
template <typename T>
class DListNode {
private:
friend class DisjointSet;
int key, listSize;
T obj;
DListNode *prev, *next, *representative;
DListNode *trailer; //just the representative node has this pointer assigned
public:
DListNode(int k, T e, DListNode *p = NULL, DListNode *n = NULL)
: key(k), obj(e), prev(p), next(n) { listSize = 1; }
T getElem() const { return obj; }
T& getElemt() { return obj; }
DListNode<T> * getNext() const { return next; }
DListNode<T> * getPrev() const { return prev; }
void setNext(DListNode* n) { this->next = n; }
void setPrevious(DListNode* p) { this->prev = p; }
DListNode<T>* insert_before(T d); // insert the int before this node
// return a pointer to the inserted node
DListNode<T>* insert_after(T d); // insert the int after this node
// return a pointer to the inserted node
void delete_before(); // delete the node before this node
void delete_after(); // delete the node after this node
int getKey() { return key; }
DListNode<T>* getRepresentative() const { return representative; }
DListNode<T>* getTrailer() const { return trailer; }
void setRepresentative(DListNode* rep);
void setTrailer(DListNode* trail);
int getListSize() { return this->getRepresentative()->listSize; }
void setListSize(int lSize)
{ this->listSize = lSize; if(this->next != NULL) this->next->setListSize(lSize); }
};
template <typename T>
void DListNode<T>::setRepresentative(DListNode* rep) {
this->representative = rep;
if (this->next != NULL)
{
this->next->setRepresentative(rep);
}
}
template <typename T>
void DListNode<T>::setTrailer(DListNode* trail) {
this->representative = trail;
}
template <typename T>
DListNode<T>* DListNode<T>::insert_before(T d) {
DListNode<T>* temp = new DListNode(d); //temp pointer // 1 OPERATION
if(prev!= NULL){ //if previous is not null // 2 OPERATION
temp -> next = this; //initialize next // 2 OPERATION
temp -> prev = prev; //initialize previous // 2 OPERATION
prev -> next = temp; // insert in the list // 2 OPERATION
prev = temp; // 1 OPERATION
}
else{ //if null than do a simple insert
temp -> next = this; // 2 OPERATION
prev = temp; // 1 OPERATION
}
return temp; // 1 OPERATION
}
template <typename T>
DListNode<T>* DListNode<T>::insert_after(T d) {
DListNode<T>* temp = new DListNode(d); // 2 OPERATION
if(next != NULL){ //if next is not null do this // 2 OPERATION
temp -> next = next; //initialize next and previous // 2 OPERATION
temp -> prev = this; // 2 OPERATION
next -> prev = temp; //make the connection to insert // 2 OPERATION
next = temp; // 1 OPERATION
}
else{ //if null than do a simple insert
temp -> prev = this; // 2 OPERATION
next = temp; // 1 OPERATION
}
return temp; // 1 OPERATION
}
template <typename T>
void DListNode<T>::delete_before() {
if(prev!= NULL){ //check if something is there // 2 OPERATION
DListNode<T>* temp = prev; // 1 OPERATION
temp -> prev-> next = temp-> next; //change the interconnections // 4 OPERATION
temp -> next -> prev = temp -> prev; // 4 OPERATION
delete temp; //delete the element // 1 OPERATION
}
else{
cout << ">Error: Nothing is there :(" << endl;
}
}
template <typename T>
void DListNode<T>::delete_after() {
if(next != NULL){ //check if something is there
DListNode<T>* temp = next; // 1 OPERATION
next -> prev = this; //change the interconnections // 2 OPERATION
next = next -> next; // 2 OPERATION
delete temp; //delete the element // 1 OPERATION
}
else{
cout << ">Error: Nothing is there :(" << endl;
}
}
Related
I'm currently working through AVL trees and am curious why the output (pre order traversal) is only showing two levels of indentation, as if one of the second order nodes is pointing to three separate 3rd level node. I'm note sure if this is an issue with my print function, or the actual code.
#include <iostream>
#include <list>
#include <vector>
#include <iomanip>
using namespace std;
template <class T>
class BST;
template <class T>
class BSTNode{
T data;
BSTNode<T>* parent;
BSTNode<T>* left;
BSTNode<T>* right;
int height;
public:
BSTNode(T data = T(), BSTNode<T>* parent = nullptr, BSTNode<T>* left = nullptr,
BSTNode<T>* right = nullptr, int height = 0) : data(data), parent(parent), left(left), right(right), height(height){}
friend class BST<T>;
int getSize() const;
};
template <class T>
class BST{
public:
BSTNode<T>* root = nullptr;
BST() {}
~BST();
BST(const BST& rhs) {*this = rhs;};
BST& operator=(const BST& rhs);
void printPreOrder(BSTNode<T>* p, int indent);
void insert(T item, BSTNode<T> * & node);
void remove(BSTNode<T>*& temp); //pass pointer by reference because we will be changing the pointer
void clear(BSTNode<T>*& root); //clears the entire tree;
BST<T>* clone(BSTNode<T>* start);
void rotateRight(BSTNode<T> * & node); //rotate the left child (the left child becomes the parent and parent becomes the right child)
void rotateLeft(BSTNode<T> * & node); //rotate the right child (the right child becomes the parent and the parent becomes the left child)
void doubleRotateRight(BSTNode<T> *& node); //same result as rotate right
void doubleRotateLeft(BSTNode<T> *& node); //same result as rotate left
int height(BSTNode<T> * node); //return height
void balance(BSTNode<T> * &node);
};
template <class T>
int BSTNode<T>::getSize() const {
int count = 1;
if(left != nullptr){
count += left->getSize();
};
if(right != nullptr){
count += right->getSize();
};
return count;
}
template <class T>
void BST<T>::printPreOrder(BSTNode<T>* p, int indent){
if(p) {
if (indent) {
std::cout << std::setw(indent) << '\t';
}
cout<< p->data << "\n ";
if(p->left) printPreOrder(p->left, indent+2);
if(p->right) printPreOrder(p->right, indent+2);
}
}
template <class T>
void BST<T>::insert(T item, BSTNode<T> * & node){
if(!node){
node = new BSTNode<T>(item);
}
else if(item < node->data){
insert(item, node->left);
}
else{
insert(item, node->right);
}
balance(node);
}
template <class T>
void BST<T>::remove(BSTNode<T>*& temp){
if(temp->left == nullptr && temp->right == nullptr){
if(temp->parent == nullptr){
root = nullptr;
}
else if(temp->parent->left == temp){
temp->parent->left = nullptr;
}
else{
temp->parent->right = nullptr;
}
delete temp;
}
else if(temp->left == nullptr){ //promote right
BSTNode<T>* toDelete = temp->right;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else if(temp->right == nullptr){ //promote left
BSTNode<T>* toDelete = temp->left;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else{
BSTNode<T>* maxOfLeft = temp->left;
while(maxOfLeft){
maxOfLeft = maxOfLeft->right;
}
temp->data = maxOfLeft->data;
remove(maxOfLeft);
}
balance(temp);
}
template <class T>
void BST<T>::clear(BSTNode<T>*& root) {
if (root) {
if (root->left) {
clear(root->left);
}
if (root->right) {
clear(root->right);
}
delete root;
}
root = nullptr;
};
template <class T>
BST<T>::~BST(){
clear(root);
}
template <class T>
BST<T>* BST<T>::clone(BSTNode<T>* start){
if(!start){
return nullptr;
}
else{
return new BSTNode<T>(start->data, clone(start->left), clone(start->right));
}
}
template <class T>
BST<T>& BST<T>::operator=(const BST<T>& rhs){
if(this == &rhs){
return *this;
}
clear(root);
root = clone(rhs.root);
return *this;
}
template <class T>
void BST<T>::rotateRight(BSTNode<T> * & node){
BSTNode<T> * newParent = node->left;
node->left = newParent->right;
newParent->right = node;
node->height = max(height(node->right),height(node->left)) + 1;
newParent->height = max(height(newParent->left), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
void BST<T>::rotateLeft(BSTNode<T> * & node){
BSTNode<T> * newParent = node->right;
node->right = newParent->left;
newParent->left = node;
node->height = max(height(node->right), height(node->left)) + 1;
newParent->height = max(height(newParent->right), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
int BST<T>::height(BSTNode<T> *node){
if(node){
return node->height;
};
return -1;
}
template <class T>
void BST<T>::doubleRotateRight(BSTNode<T> * &node){
rotateLeft(node->left);
rotateRight(node);
}
template<class T>
void BST<T>::doubleRotateLeft(BSTNode<T> * &node){
rotateRight(node->right);
rotateLeft(node);
}
template<class T>
void BST<T>::balance(BSTNode<T> * &node){
if(!node){
return;
}
if(height(node->left) > height(node->right) + 1){
if(height(node->left->left) >= height(node->left->right)){
rotateRight(node);
}
else{
doubleRotateRight(node);
};
};
if(height(node->right) > height(node->left) + 1){
if(height(node->right->right) >= height(node->right->left)){
rotateLeft(node);
}
else{
doubleRotateLeft(node);
}
}
node->height = max(height(node->right), height(node->left)) + 1;
}
int main() {
vector<int>data = {5, 3, 4, 2, 1, 2, 6, 7};
BST<int> test;
for(int r : data){
test.insert(r, test.root);
}
test.printPreOrder(test.root,0);
cout << endl;
return 0;
}
Here is the output I am getting:
3
2
1
2
5
4
6
7
From my understanding, I should be getting the following output:
3
2
1
2
5
4
6
7
Don't use tabs.
Consider this example:
#include <iostream>
#include <iomanip>
int main() {
for (int indent=0;indent<5;++indent) {
if (indent) {
std::cout << std::setw(indent) << "\t" << "tabs" << "\n";
std::cout << std::setw(indent) << " " << "spaces" << "\n";
}
}
}
Possible output is:
tabs
spaces
tabs
spaces
tabs
spaces
tabs
spaces
I have written a linked list(which is aimed for the data type int) implementation.
Seems to be working fine except when I try to sort the list in such a way that all the odd
elements should come after all the even elements with the original order of the even and odd numbers preserved.
Upon debugging in MS Visual Studio, I found out that in the oddevenSort() function, the for loop seems to be going on infinitely...as if somehow the tail->next was not being updated to nullptr.
I can't seem to grasp where the error lies in my logic.
#include<iostream>
template<class T>
class SLL_Node
{
public:
T info;
SLL_Node* next;
SLL_Node();
SLL_Node(T el, SLL_Node<T>* n = nullptr);
};
template<class T>
class SLL
{
private:
SLL_Node<T>* head, * tail;
size_t size;
public:
SLL();
~SLL();
bool isEmpty() const;
size_t get_size() const;
void add_to_head(T el);
void add_to_tail(T el);
void delete_at(size_t); //delete at a certain index. Index starting from 1. Throws an error //message if index out of bounds or list empty.
void display()const; //the logic is for mostly primitive data types and not user defined data //types (including classes)
void oddevenSort();
};
template<class T>
bool SLL<T>::isEmpty() const
{
if (tail == nullptr)
return true;
else
return false;
}
template<class T>
SLL_Node<T>::SLL_Node() : next{ nullptr }
{}
template<class T>
SLL_Node<T>::SLL_Node(T el, SLL_Node<T>* n) : info{ el }, next{ n }
{}
template<class T>
SLL<T>::SLL()
{
size = 0;
head = tail = nullptr;
}
template<class T>
void SLL<T>::add_to_tail(T el)
{
++size;
if (!isEmpty())
{
tail->next = new SLL_Node<T>(el);
tail = tail->next;
}
else
head = tail = new SLL_Node<T>(el);
}
template<class T>
void SLL<T>::add_to_head(T el)
{
head = new SLL_Node<T>(el, head);
if (tail == nullptr) //if empty
{
tail = head;
}
++size;
}
template<class T>
void SLL<T>::display()const
{
std::cout << '\n';
for (SLL_Node<T>* tmp{ head }; tmp != nullptr; tmp = tmp->next)
{
std::cout << tmp->info << "->";
}
std::cout << "NULL\n";
}
template<class T>
void SLL<T>::delete_at(size_t index)
{
if (index >= 1 && index <= size) //bound checking
{
if (!isEmpty()) //we dont need is empty since size takes care of that but still adding it for clarity
{
if (head == tail && index == 1) //if list only has one node and we delete head node
{
delete head;
head = tail = nullptr;
}
//otherwise if list more than one node
else if (index == 1) //if deleting head node
{
SLL_Node<T>* tmp{ head };
head = head->next;
delete tmp;
tmp = nullptr;
}
else //deleting other nodes
{
SLL_Node<T>* tmp{ head->next }, * pred{ head };
for (size_t i{ 2 }; i < index; ++i)
{
tmp = tmp->next;
pred = pred->next;
}
pred->next = tmp->next;
if (tmp == tail)
{
tail = pred;
}
delete tmp;
tmp = nullptr;
}
}
}
else
{
std::cout<<"\nError! Either the list is empty or the index entered is out of bounds!\n";
}
}
template<class T>
void SLL<T>::oddevenSort()
{
SLL_Node<T>* t=head;
size_t count{1};
for (; t != nullptr; t = t->next)
{
if (((t->info) % 2) != 0)
{
add_to_tail(t->info);
delete_at(count);
}
++count;
}
}
main:
int main()
{
SLL<int> a;
a.add_to_head(1);
a.add_to_head(2);
a.add_to_tail(3);
a.add_to_tail(4);
a.add_to_head(6);
a.add_to_tail(7);
a.add_to_head(5);
a.display();
//a.oddevenSort();
a.display();
return 0;
}
Consider an example input for oddevenSort a(1)->b(2) ->c(3)->null
on 1st iteration t is pointing to a(1) new node is created with
data 1 which is appended at the end of list like
b(2)->c(3)->d(1)->null.
On 2nd iteration t will point to node b(2) and no changes done
on list.
On 3rd iteration t will point to node c(3) new node is created
with data 3 which is appended at the end of list like
b(2)->d(1)->e(3)->null.
on 4th iteration t will point to d(1) which creates new node at the end of list. Iteration goes on and on recursively without breaking the loop.
Every time you need not to delete and create the new node. You can segregate even and odd nodes and make final list.
Here is the updated snippet
template<class T>
void SLL<T>::oddevenSort()
{
SLL_Node <T>tempOddHeader;
SLL_Node <T> *tempOddPtr = &tempOddHeader;
SLL_Node <T> tempEvenHeader;
SLL_Node <T> *tempEvenPtr = &tempEvenHeader;
SLL_Node<T>* t = head;
tempOddHeader.next = nullptr;
tempEvenHeader.next = nullptr;
while(t)
{
if (((t->info) % 2) != 0) {
//append to the odd list
tempOddPtr->next = t;
tempOddPtr = tempOddPtr->next;
t = t->next;
tempOddPtr->next = nullptr;
}
else {
//append to the even list
tempEvenPtr->next = t;
tempEvenPtr = tempEvenPtr->next;
t = t->next;
tempEvenPtr->next = nullptr;
}
}
tempEvenPtr->next = tempOddHeader.next;
head = tempEvenHeader.next;
tail = tempOddPtr;
}
so I have an assignment where I need to create a doubly linked list and then create a stack and queue class and inherit from the linkedlist class in order to create an RPN calculator. So far I have created my doubly linkedlist class and the other to classes. However, I am having trouble understanding how I will inherit and use the linked list class with the stack and queue. I will provide what I have so far.
I have gone to tutoring and have not had much help so I thought I would look for some extra help, do not want homework done for me but to just be pointed in the right direction.
Stack.h
using std::iterator;
using std::vector;
using std::string;
template<class T>
class Stack : public vector<T>
{
private:
T getElement(bool erase);
typename std::vector<T> ::iterator pEnd;
T top;
public:
Stack();
T pop();
T peek();
void push(T elem);
};
template<class T>
Stack<T>::Stack()
{
}
template<class T>
void Stack<T>::push(T elem)
{
this->push_back(elem);
}
template<class T>
T Stack<T>::peek()
{
return this->getElement(false);
}
template<class T>
T Stack<T>::pop()
{
return this->getElement(true);
}
template<class T>
T Stack<T>::getElement(bool erase)
{
this->pEnd = this->end() - 1;
T tmp;
if (this->size() > 0)
{
tmp = *this->pEnd;
if (erase) {
this->erase(pEnd);
}
}
return tmp;
}
Queue.h
using namespace std;
class Queue
{
private:
int items[MAXQUEUE];
int head;
int tail;
public:
Queue();
bool isEmpty();
bool isFull();
bool enqueue(int item);
int dequeue();
int peek();
};
Queue::Queue()
:head(QEMPTY), tail(QEMPTY)
{
}
bool Queue::isEmpty()
{
return this->head == this->tail;
}
bool Queue::isFull()
{
return this->tail == MAXQUEUE;
}
bool Queue::enqueue(int item)
{
if (this->isFull())
return false;
this->items[this->tail] = item;
tail = (tail + 1) % MAXQUEUE;
return true;
}
int Queue::dequeue()
{
if (this->isEmpty())
return EMPTY;
int item = this->items[head];
this->head = (this->head + 1) % MAXQUEUE;
return item;
}
int Queue::peek() {
return this->tail;
}
doublylinkedlist.h
using std::iterator;
using std::vector;
using std::string;
/*START OF NODE CLASS*/
/*---------------------------------------------*/
template<class T>
struct Node
{
T Data;
T Search;
T value;
Node<T>*Next;
Node<T>*Prev;
};
template<class T>
class LinkedList
{
private:
Node<T> *Head;
public:
LinkedList();
void addNode(T Data);
void deleteNode(T Search);
void insert(T Search, T value);
void printListBackwards();
void printListForwards();
};
template<class T>
LinkedList<T>::LinkedList()
{
this->Head = NULL;
}
template<class T>
void LinkedList<T>::addNode(T data)
{
if (Head == NULL)
{
Head = new Node<T>;
Head->Data = data;
Head->Next = NULL;
Head->Prev = NULL;
}
else
{
Node<T>*p = this->Head;
while (p->Next != NULL)
p = p->Next;
Node<T>*n = new Node<T>;
n->Data = data;
n->Next = NULL;
p->Next = n;
n->Prev = p;
}
}
template<class T>
void LinkedList<T>::insert(T Search, T value)
{
Node *p = Head;
while (p->Data != Search)
{
p = p->Next;
}
Node *n = new Node;
n->Data = value;
n->Next = p->Next;
p->Next = n;
}
template<class T>
void LinkedList<T>::deleteNode(T Search)
{
Node *p = Head;
while (p->Next->Data != Search)
{
p = p->Next;
}
Node *delPtr = p->Next;
p->Next = p->Next->Next;
delete delPtr;
}
template<class T>
void LinkedList<T>::printListBackwards()
{
Node<T> *p = Head;
while (p->Next != NULL)
{
p = p->Next;
}
while (p != NULL)
{
cout << p->Data<< endl;
p = p->Prev;
}
}
template<class T>
void LinkedList<T>::printListForwards()
{
Node<T> *p = Head;
while (p != NULL)
{
cout << p->Data << endl;
p = p->Next;
}
}
A doubly linked list can be added to at the head or the tail, and removed at the tail.
A stack pushes at one end (the head?) and pops at the same end (the head).
A queue pushes at one end (the tail) and pops at the other end (the head).
I've gone through a bunch of threads trying to understand what is going on exactly with linked lists and bubblesort, and I think I get the bulk of it.
Right now my program is simply crashing when I get to the sort function and I am not sure why. Hopefully another set of eyes will see what I do not.
Any help is greatly appreciated.
DoublyList.h:
#include "listNode.h"
#ifndef DOUBLYLIST_H
#define DOUBLYLIST_H
template <typename T>
class DoublyList
{
public:
DoublyList();
~DoublyList();
void addFront(T d);
void addBack(T d);
T removeFront();
T removeBack();
T peak();
bool isEmpty();
int getSize();
void printList();
void sortList();
private:
ListNode<T> *front;
ListNode<T> *back;
int numOfElements;
};
template <typename T>
DoublyList<T>::DoublyList(){
front = NULL;
back = NULL;
numOfElements = 0;
}
template <typename T>
DoublyList<T>::~DoublyList(){
if(numOfElements!=0){
ListNode<T> *current;
current = front;
while (current != back)
{
ListNode<T> *temp = current;
current = current->next;
temp->next = NULL;
temp->prev = NULL;
delete temp;
numOfElements--;
}
//at this point current = back, now delete it
current->next = NULL;
current->prev = NULL;
delete current;
numOfElements--;
}
//this is a safeguard if you create a LL and then delete it without doing anything to it
else{
cout<<"deleted empty LL"<<endl;
delete front;
delete back;
}
}
template <typename T>
void DoublyList<T>::addFront(T d)
{
ListNode<T> *node = new ListNode<T>();
node->data = d;
if (isEmpty()){
back = node;
}
else{
front->prev = node;
}
node->next = front;
front = node;
++numOfElements;
}
template <typename T>
T DoublyList<T>::removeFront()
{
if (isEmpty()){
return T();
}
else
{
ListNode<T>* temp = front;
if (front->next == 0){
back = 0;
}
else
{
front->next->prev = 0;
}
front = front->next;
temp->next = 0;
T theData = temp->data;
delete temp;
--numOfElements;
return theData;
}
}
template <typename T>
void DoublyList<T>::addBack(T d)
{
ListNode<T> *node = new ListNode<T>();
node->data = d;
if (isEmpty()){
front = node;
}
else{
back->next = node;
}
node->prev = back;
back = node;
++numOfElements;
}
template <typename T>
T DoublyList<T>::removeBack()
{
if (isEmpty()) {
return T();
}
else
{
ListNode<T>* temp;
temp = back;
if (back->prev == 0){
front = 0;
}
else{
back->prev->next = 0;
}
back = back->prev;
temp->prev = 0;
T theData = temp->data;
delete temp;
--numOfElements;
return theData;
}
}
template <typename T>
T DoublyList<T>::peak()
{
if (isEmpty()) {
return T();
}
return front->data;
}
template <typename T>
int DoublyList<T>::getSize(){
return numOfElements;
}
template <typename T>
bool DoublyList<T>::isEmpty(){
if(numOfElements == 0){
return true;
}
else{
return false;
}
}
template <typename T>
void DoublyList<T>::printList(){
if(numOfElements!=0){
ListNode<T> *current = front;
while(current!=back)
{
cout<<current->data<<endl;
current = current->next;
}
cout<<back->data<<endl;
}
else{
cout<<"list is empty"<<endl;
}
}
template <typename T>
void DoublyList<T>::sortList(){
int size = getSize();
ListNode<T> *current;
ListNode<T> *dummy;
ListNode<T> *next;
if(current == NULL) return;
if(current -> next == NULL) return;
int swapped = 1;
while(swapped){
swapped = 0; //last pass unless there is a swap
while(current -> next != NULL){
if(current-> data < current -> next -> data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
dummy -> data = current -> data;
current -> data = current -> next -> data;
current -> next -> data = dummy -> data;
}
current = current -> next;
}
}
}
#endif
listNode.h:
#include <iostream>
#ifndef LISTNODE_H
#define LISTNODE_H
using namespace std;
template <typename T>
class ListNode
{
public:
T data;//the data that we will store
ListNode();
ListNode(int d);
~ListNode();
ListNode *next;//int and ptr and the member variables
ListNode *prev;
};
template <typename T>
ListNode<T>::ListNode(int d){
data = d;
next = NULL;
prev = NULL;
}
template <typename T>
ListNode<T>::ListNode(){}
template <typename T>
ListNode<T>::~ListNode(){
delete next;
delete prev;
cout<<"deleted Node"<<endl;
}
#endif
testList.cpp
#include <iostream>
#include "doublyList.h"
#include "genericQueue.h"
int main(){
DoublyList<int> testQueue;
testQueue.addBack(3);
testQueue.addBack(5);
testQueue.addBack(2);
testQueue.addBack(10);
testQueue.addBack(1);
cout << "Before Sort: " << endl;
testQueue.printList();
cout << "After Sort: " << endl;
testQueue.sortList();
testQueue.printList();
}
The erors I could find so far are:
Your default ListNode() constructor doesn't null the next and prev pointers.
In void DoublyList<T>::sortList() you don't initialize dummy, so it just points into nowhere. Actually there is no reason to use a node list at all, you can just directly use a variable of type T.
You don't initialize current in the same function and you actually should reset current to e.g. front at the beginning of each outer loop.
You don't use next at all (and don't need to), so just remove it.
To sum it up, this is what void DoublyList<T>::sortList() could look like:
template <typename T>
void DoublyList<T>::sortList(){
int size = getSize();
ListNode<T> *current=front;
T dummy;
if (current == NULL) return;
if (current->next == NULL) return;
int swapped = 1;
while (swapped){
current = front;
swapped = 0; //last pass unless there is a swap
while (current->next != NULL){
if (current->data < current->next->data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
dummy = current->data;
current->data = current->next->data;
current->next->data = dummy;
}
current = current->next;
}
}
}
and this is my suggestion for the ListNode constructor.
template <typename T>
ListNode<T>::ListNode() :
next(nullptr),
prev(nullptr),
data{}
{}
Besides that, I also agree with DaveB that swapping pointers is the approach you should actually use.
To start with you need to initialize current in your sort function,
current = first;
template <typename T>
void DoublyList<T>::sortList(){
ListNode<T> *current;
ListNode<T> *next;
T tmp;
current = front;
if(current == NULL) return;
if(current -> next == NULL) return;
int swapped = 1;
while(swapped){
swapped = 0; //last pass unless there is a swap
while(current->next != nullptr){
if(current->data < current->next->data){
swapped = 1; //swap, will need to re-enter while loop
//actual number swap
tmp = current->data;
current->data = current->next->data;
current->next->data = tmp;
}
current = current -> next;
}
if (swapped) // go back to start of list for next pass
current = front;
}
}
Hi I am trying to make a doubly linked list to store individual numbers as nodes of a doubly linked list and then add them together and print them out for a homework assignment. I am having a lot of trouble getting this to work and have traced my problem to my add node functions as they don't update the pointers correctly. For example on the AddToFront() function I can't understand how I can get the prev pointer to work and point to the node behind it.
I can't use the STL and have to implement the LL myself in case anyone is wondering. Thanks!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
/////// PART A
template <class T>
class List {
private:
struct Node {
T data;
Node *next;
Node *prev;
};
Node *front, *current, *rear;
public:
List();
~List();
void AddtoFront (T newthing);
void AddtoRear (T newthing);
bool FirstItem (T & item);
bool LastItem (T & item);
bool NextItem (T & item);
bool PrevItem (T & item);
};
template <class T>
List<T>::List() {
front = NULL; current = NULL; rear = NULL;
}
template <class T>
List<T>::~List() {
}
template <class T>
void List<T>::AddtoFront (T newthing) {
if (front == NULL) {
Node *temp;
temp = new Node;
temp->data = newthing;
temp->next = front;
temp->prev = NULL;
front = temp;
} else {
Node *temp;
temp = new Node;
front->prev = temp;
temp->data = newthing;
temp->next = front;
temp->prev = NULL;
front = temp;
}
}
template <class T>
void List<T>::AddtoRear (T newthing) {
if (rear == NULL) {
Node *temp;
temp = new Node;
temp->data = newthing;
temp->prev = rear;
temp->next = NULL;
rear = temp;
} else {
Node *temp;
temp = new Node;
rear->next = temp;
temp->data = newthing;
temp->prev = rear;
temp->next = NULL;
rear = temp;
}
}
template <class T>
bool List<T>::FirstItem (T & item) {
if (front == NULL) { return false; }
current = front;
item = front->data;
return true;
}
template <class T>
bool List<T>::LastItem (T & item) {
if (rear == NULL) { return false; }
current = rear;
item = rear->data;
return true;
}
template <class T>
bool List<T>::NextItem (T & item) {
if (current != NULL) current = current->next;
if (current == NULL) { return false; }
item = current->data;
return true;
}
template <class T>
bool List<T>::PrevItem (T & item) {
if (current == NULL) { return false; }
if (current->prev != NULL) current = current->prev;
item = current->data;
return true;
}
/////// PART B
class BigNumber {
private:
//complete here...
//include here a List of integers, or shorts etc
List<int>L;
public:
//complete here...
//what methods do you need?
//e.g., ReadFromString, PrintBigNumber, AddBigNumbers
BigNumber();
~BigNumber();
void ReadFromString(char * decstring);
void PrintBigNumber();
void AddBigNumbers(BigNumber B1, BigNumber B2);
};
BigNumber::BigNumber(){
// anything here?
}
BigNumber::~BigNumber(){
//you can keep that empty
}
void BigNumber::ReadFromString (char * decstring ) {
//read a string, adding a new node per digit of the decimal string
// To translate 'digits' to integers: myinteger=decstring[index]-48
//You need to use the AddtoFront()
int temp;
for (unsigned i=0; i < strlen(decstring); ++i) {
//cin >> decstring[i];
temp = decstring[i]-48;
//L.AddtoFront(temp);
L.AddtoRear(temp);
//cout <<"Number added!" <<endl;
}
}
void BigNumber::PrintBigNumber () {
//complete here, print the list (i.e., use FirstItem() and NextItem() )
int val;
if (L.FirstItem(val)) {
cout << val;
} else {
cout << "print failed";
}
//if (L.FirstItem(val)) { cout << "true-first";} else { cout <<"false-first";};
//if (L.LastItem(val)) { cout << "true";} else { cout <<"false";};
//L.FirstItem(val);
//cout << val;
/*while (L.PrevItem(val)){
cout << val;
//cout <<"Print error!Value not here.";
}*/
}
void BigNumber::AddBigNumbers(BigNumber B1,BigNumber B2){
//complete here.
//use FirstItem(), NextItem() and AddNode()
//to add two big numbers, what do you have to do? Be careful about the carry
//Remember to add the last carry, the resulting number can have one more digit than B1 or B2
}
/////// PART C
BigNumber B1, B2, RES;
int main (int argc, char ** argv) {
//use command line arguments
if(argc!=3){printf("usage: executable number1 number2\n");exit(0);}
B1.ReadFromString(argv[1]);
B2.ReadFromString(argv[2]);
//print
cout << endl<< "Add the following numbers " << endl;
B1.PrintBigNumber();
cout << " + ";
B2.PrintBigNumber();
cout << " = " << endl;
//compute the addition
RES.AddBigNumbers(B1,B2);
//print the result
RES.PrintBigNumber();
cout << endl;
return 0;
}
EDIT: I added in a line each in AddToFront() and AddToRear(). Is this on the right track?
AddtoFront needs to also update the prev pointer for front. That is, you're currently doing
temp -> front <-> rest_of_list
where it needs to be
temp <-> front <-> rest_of_list.
Also, you might notice that the two branches of your if statement in AddtoFront are identical... :)