Sorting using Linear Linked List in C++ - c++

So I'm trying to build a linear linked list that takes info from users and saves the info in two sorted lists by name (alphabetically) and by birthdate. So far I have
struct node{
char* name;
int birthDate;
node *nameNext;
node * dateNext;
};
where each node will have two pointers pointing to the appropriate list. The problem I'm having is how to direct the head pointer node *head. How do I set head when there are two different lists? I'm thinking something like head->nameNext and head->dateNext but that would point to the second node of the lists if it work. Please help! Thanks in advance.

if i got your question right, you're simply looking to sort your list
in two ways (alphabetically and birthdate)
note: i will use bubble sort to simplify the algorithm but you can use better one as you know
#include <iostream>
struct node{
const char* name;
int birthdate;
node*next;
};
struct sort_data{
private:
node *name_root = nullptr; // alphabetically head/root pointer
node *date_root = nullptr; // birthdate head/root pointer
public:
void push(const char*name,int birthdate); // push data;
void sort_by_birth(); // sort the birth linked list
void sort_by_alphabet(); // sort the alphabet linked list
void print_birth(); // print the data of the birth linked list
void print_alph(); // print of the data of the alphabet linked list
};
void sort_data::push(const char*name,int birthdata) {
node*Name = new node; // allocate a node for the alphabet list
node*Date = new node; // allocate a node for the date list
Name->name = Date->name = name;
Name->birthdate = Date->birthdate = birthdata;
Name->next = name_root;
Date->next = date_root;
name_root = Name;
date_root = Date;
}
void sort_data::sort_by_birth() {
node*i = date_root;
node*j;
if(!i) // if i == nullptr
return;
while(i){ // while(i!=nullptr)
j = i->next;
while(j){
if(i->birthdate > j->birthdate){
std::swap(i->birthdate,j->birthdate);
std::swap(i->name,j->name);
}
j = j->next;
}
i = i->next;
}
}
void sort_data::sort_by_alphabet() {
node*i = name_root;
node*j;
if(!i)
return;
while(i){
j = i->next;
while(j){
if(i->name[0] > j->name[0]){
std::swap(i->birthdate,j->birthdate);
std::swap(i->name,j->name);
}
j = j->next;
}
i = i->next;
}
}
void sort_data:: print_birth(){
node*temp = date_root;
while(temp){
std::cout << temp->name << " " << temp->birthdate << std::endl;
temp = temp->next;
}
}
void sort_data::print_alph() {
node*temp = name_root;
while(temp){
std::cout << temp->name << " " << temp->birthdate << std::endl;
temp = temp->next;
}
}
int main(){
sort_data obj;
obj.push("jack",1997);
obj.push("daniel",1981);
obj.push("maria",1995);
obj.push("john",2008);
obj.sort_by_alphabet();
obj.sort_by_birth();
std::cout << "alphabetically : \n" ;
obj.print_alph();
std::cout << "by birthdate : \n";
obj.print_birth();
}
note: because you're using C++ don't use char* to store string literals
use std::string or const char *. as the chars in string literals are const char so you don't want to point on const char with char
if you're using a C++ compiler that support C++11 your compiler should generate a warning about such thing

Related

Inserting a basic singly linked list node seems to break my c++ code?

Singly Linked List and Node classes and the start of the main function, where I wrote a brief outline of the code functionality. The issue is toward the end of the main function. I wrote '...' in place of what I believe to be irrelevant code because it simply parses strings and assigns them to the string temp_hold[3] array.
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
string value;
string attr;
string tagname;
Node *next;
Node(string c_tagname, string c_attr, string c_value) {
this->attr = c_attr;
this->value = c_value;
this->tagname = c_tagname;
this->next = nullptr;
}
};
class SinglyLinkedList {
public:
Node *head;
Node *tail;
SinglyLinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
void insert_node(string c_tagname, string c_attr,string c_value) {
Node *node = new Node(c_tagname,c_attr, c_value);
if (!this->head) {
this->head = node;
} else {
this->tail->next = node;
}
this->tail = node;
}
};
int main(int argc, char **argv) {
/* storage is a vector holding pointers to the linked lists
linked lists are created and the linked list iterator sll_itr is incremented when
previous line begins with '</' and the currentline begins with '<'
linked lists have nodes, which have strings corresponding to tagname, value, and attribute
*/
SinglyLinkedList *llist = new SinglyLinkedList();
vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
string temp_hold[3];
// to determine new sll creation
bool prev = false;
bool now = false;
//input
int num1, num2;
cin >> num1; cin >> num2;
//read input in
for (int i = 0; i <= num1; ++i) {
string line1, test1;
getline(cin, line1);
test1 = line1.substr(line1.find("<") + 1);
//determine to create a new linked list or wait
if (test1[0] == '/') {
prev = now;
now = true;
} else {
//make a node for the data and add to current linked list
if (i > 0) {
prev = now;
now = false;
//if last statement starts with '</' and current statment starts with '<'
// then start a new sll and increment pointer to vector<SinglyLinkedList*>
if (prev && !now) {
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp);
sll_itr++;
}
}
//parse strings from line
int j = 0;
vector<string> datastr;
vector<char> data;
char test = test1[j];
while (test) {
if (isspace(test) || test == '>') {
string temp_for_vect(data.begin(),data.end());
if (!temp_for_vect.empty()) {
datastr.push_back(temp_for_vect);
}
data.clear();
} else
if (!isalnum(test)) {
} else {
data.push_back(test);
}
j++;
test = test1[j];
}
//each node has 3 strings to fill
int count = 0;
for (auto itrs = datastr.begin(); itrs!=datastr.end(); ++itrs) {
switch (count) {
case 0:
temp_hold[count]=(*itrs);
break;
case 1:
temp_hold[count]=(*itrs);
break;
case 2:
temp_hold[count]=(*itrs);
break;
default:
break;
}
count++;
}
}
cout << "before storing node" << endl;
(*sll_itr)->insert_node(temp_hold[0], temp_hold[1], temp_hold[2]);
cout << "after" << endl;
}
cout << "AFTER ELSE" << endl;
return 0;
}
And here is the line that breaks the code. The auto sll_itr is dereferenced which means *sll_itr is now a SinglyLinkedList* and we can call the insert_node(string, string, string) to add a node to the current linked list. However when I keep the line, anything after the else statement brace does not run, which means the cout<<"AFTER ELSE"<< endl; does not fire. If I remove the insert_node line, then the program runs the cout<<"AFTER ELSE"<< endl; I am unsure what the issue is.
(*sll_itr)->insert_node(temp_hold[0],temp_hold[1],temp_hold[2]);
cout << "after" << endl;
} //NOT HANGING. This closes an else statement.
cout << "AFTER ELSE" << endl;
return 0;
}
Compiled as g++ -o myll mylinkedlist.cpp and then myll.exe < input.txt And input.txt contains
8 3
<tag1 value = "HelloWorld">
<tag2 name = "Name2">
</tag2>
</tag1>
<tag5 name = "Name5">
</tag5>
<tag6 name = "Name6">
</tag6>
Your linked list isn't the problem, at least not the problem here.
A recipe for disaster in the making: retaining, referencing, and potentially manipulating, an iterator on a dynamic collection that potentially invalidates iterators on container-modification. Your code does just that. tossing out all the cruft between:
vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
....
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp); // HERE: INVALIDATES sll_iter on internal resize
sll_itr++; // HERE: NO LONGER GUARANTEED VALID; operator++ CAN INVOKE UB
To address this, you have two choices:
Use a container that doesn't invalidate iterators on push_back. There are really only two sequence containers that fit that description: std::forward_list and std::list.
Alter your algorithm to reference by index`, not by iterator. I.e. man your loop to iterate until the indexed element reaches end-of-container, then break.
An excellent discussion about containers that do/do-not invalidate pointers and iterators can be found here. It's worth a read.

Store the address of an object inside a node

I'm trying to create an object of a class called Cell and store it in a linked list. I'm sure I could do this with an array, but part of my assignment is that I use a linked list and I didn't think I'd get this many problems. This is currently my node. Right now, I have all these variables stored in the node, but I'd rather create an object(Called "Cell") to store them. Info should be a pointer to an object of type T. Right now, that T should be of type Cell.
template<class T>
struct Node {
T *info;
Node<T> *nodeP;
Node<T> *linkP;
int nodeNumber = 0;
bool purchased = false;
std::string color = " ";
int index = 0;
int max_num = 0;
std::string name = " ";
int price;
};
In here I am creating the node and adding it to a linked list. At the moment I'm just filling in values of the node, but I'm trying to create an object of type Cell and assign it's address to the pointer info. I've tried a couple different ways but keep coming back with errors. I commented them out so you can see what I've tried.
template<class T>
void Board<T>::setCellValue() {
//open file
ifstream inFile;
string line;
inFile.open("CellValues.txt");
//Check for Error
if (inFile.fail()) {
cerr << "File does not exist!";
exit(1);
}
int index = 0, max_num = 0, count = 0, price = 0;
string color, name;
istringstream inStream;
while (getline(inFile, line)) {
inStream.clear();
inStream.str(line);
inStream >> color >> index >> max_num >> name >> price;
//creates node
Node<T> *newNodeP = new Node<T>;
//create pointer, assign pointer to pointer in Node
//Cell<T> *cellPtr = new Cell<T>(count, name, color, index, max_num, price);
//newNode->info= cellPtr;
//creating anonymous object and assigning to the node? I think
newNodeP->info = new Cell<T>(color, index, max_num, name, price);
//weird way I was just experimenting with
newNodeP->info->Cell<T>(count, name, color, index, max_num, price);
//fills node values(this is what I want to handle in the object
newNodeP->color = color;
newNodeP->index = index;
newNodeP->max_num = max_num;
newNodeP->name = name;
newNodeP->nodeNumber += count;
newNodeP->price = price;
newNodeP->linkP = NULL;
if (firstP != NULL)
lastP->linkP = newNodeP;
else
firstP = newNodeP;
lastP = newNodeP;
count++;
}
}
Currently, I have two ways of returning the node landed on. One returns a Node* and sort of works. It returns the pointer to the node, and I can access the values inside that node, but I can't figure out how to store the pointer to that node.
//Find Cell
template<class T>
Node<T>* Board<T>::findCell(int id) {
for (Node<T> *traverseP = firstP; traverseP != NULL; traverseP = traverseP->linkP) {
if (traverseP->nodeNumber == id) {
return traverseP;
}
}
return nullptr;
}
//how I call it in main. it returns an address to that node, but I'm getting errors trying to store that address in a pointer.
cout << "You landed on cell " << gameBoard.findCell(player.getCellNum()) << endl << endl;
Node<T> *ptr = gameboard.findCell(player.getCellNum())->info;
This second way, I think returns the reference to the object in the node, but my earlier problem is stopping me from figuring that out.
//Return Cell
template <class T>
T Board<T>::returnCell(int id) {
for (Node<T> *traverseP = firstP; traverseP != NULL; traverseP = traverseP->linkP) {
if (traverseP->nodeNumber == id) {
return traverseP->info;
}
}
return nullptr;
}
//How i'm calling it in main. I don't really know what it's returning though because it only prints "You landed on " and then nothing else.
cout << "You landed on " << gameBoard.returnCell(player.getCellNum()) << endl;

Hash table implementation in C++

I am trying the following code for Hash table implementation in C++. The program compiles and accepts input and then a popup appears saying " the project has stopped working and windows is checking for a solution to the problem. I feel the program is going in the infinite loop somewhere. Can anyone spot the mistake?? Please help!
#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
/* Definitions as shown */
typedef struct CellType* Position;
typedef int ElementType;
struct CellType{
ElementType value;
Position next;
};
/* *** Implements a List ADT with necessary functions.
You may make use of these functions (need not use all) to implement your HashTable ADT */
class List{
private:
Position listHead;
int count;
public:
//Initializes the number of nodes in the list
void setCount(int num){
count = num;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
//Inserts an element after Position p
int insertList(ElementType data, Position p){
Position temp;
temp = p->next;
p->next = new CellType;
p->next->next = temp;
p->next->value = data;
return ++count;
}
//Returns pointer to the last node
Position end(){
Position p;
p = listHead;
while (p->next != NULL){
p = p->next;
}
return p;
}
//Returns number of elements in the list
int getCount(){
return count;
}
};
class HashTable{
private:
List bucket[10];
int bucketIndex;
int numElemBucket;
Position posInsert;
string collision;
bool reportCol; //Helps to print a NO for no collisions
public:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
}
collision = "";
reportCol = false;
}
int insert(int data){
bucketIndex=data%10;
int col;
if(posInsert->next==NULL)
bucket[bucketIndex].insertList(data,posInsert);
else { while(posInsert->next != NULL){
posInsert=posInsert->next;
}
bucket[bucketIndex].insertList(data,posInsert);
reportCol=true;}
if (reportCol==true) col=1;
else col=0;
numElemBucket++;
return col ;
/*code to insert data into
hash table and report collision*/
}
void listCollision(int pos){
cout<< "("<< pos<< "," << bucketIndex << "," << numElemBucket << ")"; /*codeto generate a properly formatted
string to report multiple collisions*/
}
void printCollision();
};
int main(){
HashTable ht;
int i, data;
for (i=0;i<10;i++){
cin>>data;
int abc= ht.insert(data);
if(abc==1){
ht.listCollision(i);/* code to call insert function of HashTable ADT and if there is a collision, use listCollision to generate the list of collisions*/
}
//Prints the concatenated collision list
ht.printCollision();
}}
void HashTable::printCollision(){
if (reportCol == false)
cout <<"NO";
else
cout<<collision;
}
The output of the program is the point where there is a collision in the hash table, thecorresponding bucket number and the number of elements in that bucket.
After trying dubbuging, I come to know that, while calling a constructor you are not emptying the bucket[bucketIndex].
So your Hash Table constructor should be as follow:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
bucket[i].makeEmptyList(); //here we clear for first use
}
collision = "";
reportCol = false;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
what you can do is you can get posInsert using
bucket[bucketIndex].end()
so that posInsert-> is defined
and there is no need to
while(posInsert->next != NULL){
posInsert=posInsert->next;
because end() function is doing just that so use end() function

Accessibility for Vectors of Singly Linked Lists (or possibly a Linked List of Linked Lists)

Been wracking my mind all day trying to hammer out the underlying data structures for a challenge assignment in one of my programming classes.
The problem is as follows:
Given an assortment of objects (each of which includes an identifier and a weight) and a supply of containers (which have a fixed weight capacity), pack all the items using as few containers as possible without overloading any of them.
I have the logic aspects hammered out using a hodgepodge of arrays, but the dynamic nature of this assignment has me wanting to optimize things by using vectors and/or linked lists.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <math.h>
#include <time.h>
#include <conio.h>
#include <vector>
#include <algorithm>
using namespace std;
struct Item
{
int number;
double weight;
bool operator < (const Item& str) const
{
return (weight < str.weight);
}
};
class Node
{
int number;
double weight;
Node* next;
public:
Node()
{};
void SetID(int iNum)
{
number = iNum;
};
void SetWeight(double iWeight)
{
weight = iWeight;
};
void SetNext(Node* iNext)
{
next = iNext;
}
int GetID()
{
return number;
};
double GetWeight()
{
return weight;
};
Node* Next()
{
return next;
};
};
class List
{
Node* head;
double weight;
public:
List()
{
head = NULL;
weight = 0;
};
int Size()
{
Node* tmp;
int count = 0;
for (tmp = head; tmp != NULL; tmp = tmp->Next())
{
count++;
}
return count;
};
double Weight()
{
return weight;
};
void Print()
{
Node *tmp = head;
if ( tmp == NULL )
{
cout << " E M P T Y" << endl;
return;
}
do
{
cout << setw(8) << tmp->GetID() << " | " << setw(8) << tmp->GetWeight() << endl;
tmp = tmp->Next();
} while ( tmp != NULL );
};
void Append(int iNum, double iWeight)
{
Node* newNode = new Node();
newNode->SetID(iNum);
newNode->SetWeight(iWeight);
newNode->SetNext(NULL);
Node *tmp = head;
if ( tmp != NULL )
{
while ( tmp->Next() != NULL )
{
tmp = tmp->Next();
}
tmp->SetNext(newNode);
}
else
{
head = newNode;
}
weight += iWeight;
};
};
double ItemWeights(vector<Item> iVect)
{
double total = 0;
for(int i = 0; i < iVect.size(); i++)
{
total += iVect[i].weight;
}
return total;
}
int main()
{
const double MAX_WEIGHT = 20;
vector< Item > source;
//
// Segment of code which propagates the vector data
// works fine, but is excluded for the sake of brevity
//
double totalWeight = ItemWeights(source);
// Duplicate vector of items
vector< Item > items(source);
for(int i = 0; i < items.size(); i++)
{
cout << setw(8) << items[i].number << setw(8) << items[i].weight << endl;
}
cout << "\n Total weight = " << totalWeight << endl;
cout << "\n\n Press any key to continue... ";
getch();
// Solution A-Original
// vector< vector< Item > > boxesAO( vector< Item >);
// boxesAO[0].push_back({items[items.size()].number, items[items.size()].weight});
vector< List > boxesAO;
// boxesAO[0].Append(items[items.size()].number, items[items.size()].weight);
return 0;
}
I've left some of the methods I've tried in the code (commented out) - none of which worked. As I mentioned above, I've got it working with arrays of linked lists and with 2D arrays, but the vast range of potential input makes these problematic at best. Either a bunch of empty lists taking up space or, worse, not having enough.
I'm thinking that vector< List > is my best option, but I can't figure out how I'm supposed to access any of the List functionality.
If someone would be so helpful as to offer a suggestion for how to create a "dynamic 2D array" as well as a code example of how to access it, I would be most greatly appreciative. My deepest thanks in advance.
EDIT:
#jaredad7 ~ That's what I've been trying, but it keeps causing the program to crash.
List box;
box.Append(items[items.size()].number, items[items.size()].weight);
This works just fine - no problems whatsoever.
The earlier code propagates a 1D vector of Item structs, which also works properly.
vector< List > boxes;
boxes[0].Append(items[items.size()].number, items[items.size()].weight);
This compiles fine but crashes during execution, no matter what index is used. (I'm also using couts for debugging, and the issue most definitely lies with trying to access the List functions.)
I'm suspecting that .push_back or somesuch may be needed, but I haven't been able to find much information concerning vectors of List objects.
If you can, my first suggestion would be to go with the vector (if that is allowed). As for accessing functions/attributes of a member of a vector, it's done the same way as an array, that is:
vectorname[i].functionname(a,b,c);
The best way to do this without vectors would be to use your nodes as the item container (a struct), and handle node-creation, deletion, etc. in your list class. Then, you would only really need one container for as many objects of one type as you need. You can make the type dynamic (although it appears you only need doubles for this project) by adding a class template (use google if you are unfamiliar with templates in C++). This will allow your user to make a container for each type of data (much like a vector).

Segfault in recursive function

I'm getting a segfault when I run this code and I'm not sure why. Commenting out a particular line (marked below) removes the segfault, which led me to believe that the recursive use of the iterator "i" may have been causing trouble, but even after changing it to a pointer I get a segfault.
void executeCommands(string inputstream, linklist<linklist<transform> > trsMetastack)
{
int * i=new int;
(*i) = 0;
while((*i)<inputstream.length())
{
string command = getCommand((*i),inputstream);
string cmd = getArguments(command,0);
//cout << getArguments(command,0) << " " << endl;
if (cmd=="translate")
{
transform trs;
trs.type=1;
trs.arguments[0]=getValue(getArguments(command,2));
trs.arguments[1]=getValue(getArguments(command,3));
((trsMetastack.top)->value).push(trs);
executeCommands(getArguments(command,1),trsMetastack);
}
if (cmd=="group")
{
//make a NEW TRANSFORMS STACK, set CURRENT stack to that one
linklist<transform> transformStack;
trsMetastack.push(transformStack);
//cout << "|" << getAllArguments(command) << "|" << endl;
executeCommands(getAllArguments(command),trsMetastack); // COMMENTING THIS LINE OUT removes the segfault
}
if (cmd=="line")
{ //POP transforms off of the whole stack/metastack conglomeration and apply them.
while ((trsMetastack.isEmpty())==0)
{
while ((((trsMetastack.top)->value).isEmpty())==0) //this pops a single _stack_ in the metastack
{ transform tBA = ((trsMetastack.top)->value).pop();
cout << tBA.type << tBA.arguments[0] << tBA.arguments[1];
}
trsMetastack.pop();
}
}
"Metastack" is a linked list of linked lists that I have to send to the function during recursion, declared as such:
linklist<transform> transformStack;
linklist<linklist<transform> > trsMetastack;
trsMetastack.push(transformStack);
executeCommands(stdinstring,trsMetastack);
The "Getallarguments" function is just meant to extract a majority of a string given it, like so:
string getAllArguments(string expr) // Gets the whole string of arguments
{
expr = expr.replace(0,1," ");
int space = expr.find_first_of(" ",1);
return expr.substr(space+1,expr.length()-space-1);
}
And here is the linked list class definition.
template <class dataclass>
struct linkm {
dataclass value; //transform object, point object, string... you name it
linkm *next;
};
template <class dataclass>
class linklist
{
public:
linklist()
{top = NULL;}
~linklist()
{}
void push(dataclass num)
{
cout << "pushed";
linkm<dataclass> *temp = new linkm<dataclass>;
temp->value = num;
temp->next = top;
top = temp;
}
dataclass pop()
{
cout << "pop"<< endl;
//if (top == NULL) {return dataclass obj;}
linkm<dataclass> * temp;
temp = top;
dataclass value;
value = temp->value;
top = temp->next;
delete temp;
return value;
}
bool isEmpty()
{
if (top == NULL)
return 1;
return 0;
}
// private:
linkm<dataclass> *top;
};
Thanks for taking the time to read this. I know the problem is vague but I just spent the last hour trying to debug this with gdb, I honestly dunno what it could be.
It could be anything, but my wild guess is, ironically: stack overflow.
You might want to try passing your data structures around as references, e.g.:
void executeCommands(string &inputstream, linklist<linklist<transform> > &trsMetastack)
But as Vlad has pointed out, you might want to get familiar with gdb.