Deleting a node in a doubly linked list - c++

Im trying to delete a node from a doubly linked list with data that's been read in from a file and rewrite it to the file with the non-deleted nodes. But i'm doing this incorrectly.
Either it deletes only a part of the node or it doesn't delete anything (the starting node).
Here's my header
hw07.h
#ifndef HW07_H_
#define HW07_H_
#include <iostream>
#include <fstream>
using namespace std;
typedef struct slist slist;
struct stud
{
string term;
string title;
string description;
string tktNum;
string location;
string lecDay;
string instructor;
string labLoc;
string labDay;
string labInstruct;
string units;
string preReqs;
string grade;
};
struct sentry
{
slist *list;
sentry *next;
sentry *prev;
stud *data;
};
struct slist
{
int length;
sentry *first;
sentry *last;
};
void readFile(slist *&header);
void deleteDataTN(slist *&header);
#endif
my main
hw07.cpp
#include "hw07.h"
int main()
{
slist *header = NULL;
readFile(header);
deleteDataTN(header);
return 0;
}
my readFile function
readFile.cpp
#include "hw07.h"
void readFile(slist *&header)
{
ifstream fin;
sentry *node, *temp;
fin.open("sbclassdb.txt");
while(!fin.eof())
{
if(header == NULL)
{
header = new slist;
header-> length = 0;
header-> first = NULL;
header-> last = NULL;
node = new sentry;
header-> first = node;
header-> last = node;
node-> prev = NULL;
node-> next = NULL;
}else
{
node = new sentry;
node-> prev = header-> last;
node-> next = NULL;
temp = header -> last;
temp-> next = node;
header-> last = node;
}
node->data = new stud;
getline(fin, node->data->term);
getline(fin, node->data->title);
getline(fin, node->data->description);
getline(fin, node->data->tktNum);
getline(fin, node->data->location);
getline(fin, node->data->lecDay);
getline(fin, node->data->instructor);
getline(fin, node->data->labLoc);
getline(fin, node->data->labDay);
getline(fin, node->data->labInstruct);
getline(fin, node->data->units);
getline(fin, node->data->preReqs);
getline(fin, node->data->grade);
header->length++;
string blankLine;
if(!getline(fin, blankLine))
break;
}
fin.close();
}
my deleteData function
deleteDataTN.cpp
#include "hw07.h"
void deleteDataTN(slist *&header)
{
sentry *node, *temp;
string ticketNum;
ofstream fout;
int index;
bool found;
found = false;
index = 0;
cout << "Ticket Number: ";
getline(cin, ticketNum);
node = header->first;
while(index < header->length && !found)
{
if(node->data->tktNum == ticketNum)
{
found = true;
free(node->data);
}
else
{
++index;
temp = node;
node = temp->next;
}
fout.open("sbclassdb.txt");
node = header->first;
for(int i=0; i<header->length; ++i)
{
fout << node->data->term << endl;
fout << node->data->title << endl;
fout << node->data->description << endl;
fout << node->data->tktNum << endl;
fout << node->data->location << endl;
fout << node->data->lecDay << endl;
fout << node->data->instructor << endl;
fout << node->data->labLoc << endl;
fout << node->data->labDay << endl;
fout << node->data->labInstruct << endl;
fout << node->data->units << endl;
fout << node->data->preReqs << endl;
fout << node->data->grade << endl;
temp = node;
node = temp->next;
fout << "\n";
}
}
my text file used to read in file
sbclassdb.txt
Fall 2017
CS1A
Intro to Computer Science 1
11111
SM101
TTH 100PM
John Doe
SM102
TTH 300PM
John Doe
5
NA
A
Spring 2018
CS1B
Intro to Computer Science 2
22222
SM101
TTH 200PM
Jane Doe
SM102
TTH 300PM
Jane Doe
5
CS1A
NA
Spring 2018
CS4A
Into to Java for Computer Science
12345
BGS101
MWF 200PM
Bob Smith
BGS102
Bob Smith
4
CS1B
NA

new should be cleaned up with delete (not free which is for malloc)
struct sentry{stud *data;...} can be changed to struct sentry{stud data;...}. And there is no need for sentry::list member:
struct sentry
{
sentry *next;
sentry *prev;
stud data;
};
There is no gain in declaring sentry::data as a pointer. If you simply declare the data as stud data; then you don't have to allocate/free with new/delete. (you still need new/delete for the nodes)
void deleteDataTN(slist *&header) can be declared as void deleteDataTN(slist &header), the you simply call deleteDataTN(myheader);
Don't use while(!fin.eof()){...}. There are many SO topics on this issue. See for example how-does-ifstreams-eof-work. I wrote a code earlier which I believe was wrong, here is the corrected version:
while(fin.good())
{
sentry *node = new sentry;
if(header.first == nullptr)
{
node->prev = nullptr;
node->next = nullptr;
header.first = node;
header.last = node;
}
else
{
header.last->next = node;
node->prev = header.last;
node->next = nullptr;
header.last = node;
}
...
}
To remove a node, you can add a function to slist:
struct slist
{
...
void remove(sentry *node);
};
void slist::remove(sentry *node)
{
if(!node) return;
if(!first) return;//empty list, do nothing
if(first->next == nullptr)//deleting the only node
{
first = last = nullptr;
}
else if(node == last)//deleting the last node
{
last = node->prev;
node->prev->next = nullptr;
}
else if(node == first)//deleting the first node
{
first = node->next;
first->prev = nullptr;
}
else//deleting a node in the mid
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
length--;
delete node;
}
Now you can remove any node
node = header.first;
while(node)
{
if(node->data.tktNum == "xyz")
{
header.remove(node);
break;
}
node = node->next;
}

Related

How to remove a certain node from a linked list by the data its holding?

We are suppose to enter a string, and then find where the string is in the linked list and remove that node
when i insert to the front of the list, so i enter data values a, b, c , d, when i print it it comes up as d,c,b,a. Now i insert to the rear of it, entering f and g, and the list now looks, d,c,b,a,f,g. I want to remove f but it just use the remove function it does not and still output the same list
using namespace std;
struct node {
string data;
node* next;
};
node* addFront(node* s);
node* addRear(node* s);
void remove(node* head, string abc);
void print(node* head);
int main() {
node* head = NULL;
cout << "Enter 5 data strings\n";
cout << "This will be inserted from the back\n";
for (int i = 0; i < 5; i++) {
head = addFront(head);
}
print(head);
cout << "Enter 3 strings and this will be inserted from the back of the orignal string\n";
for (int i = 0; i < 3; i++) {
head = addRear(head);
}
print(head);
cout << "Removing the head node\n";
string n;
cout << "Enter a string to remove\n";
cin >> n;
remove(head, n);
print(head);
}
node* addFront(node* s)
{
node* person = new node;
cin >> person->data;
person->next = s;
s = person;
return s;
}
node *addRear(node*s ) {
node* person = new node;
cin >> person->data;
person->next = NULL;
if (s == NULL) {
return person;
}
else {
node* last = s;
while (last->next != NULL) {
last = last->next;
}
last->next = person;
}
return s;
}
void remove(node* head, string a) {
node* previous = NULL;
node* current = head;
if (current == NULL) {
cout << "Value cannot be found\n";
return;
}
else {
while (previous != NULL) {
if (current->data == a) {
previous->next = current->next;
delete current;
break;
}
current = current->next;
}
}
}
void print(node * head)
{
node* temp = head;
while (temp != NULL) // don't access ->next
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
In remove function, previous is most certainly NULL when you hit that while loop.
Perhaps consider a do-while loop instead (with better handling of previous).
You may be better off handling the first node in a different manner since the holder of its previous is essentially the root pointer.

Reading a text file to a doubly linked list and outputting it - C++

I'm trying to read in a file and use a doubly linked list to store the data and output the stored data. But whenever I run my program, it outputs nothing and terminates. I have no errors compiling the code.
Header file with the pre-processor directives and the structs
#include <iostream>
#include <fstream>
using namespace std;
typedef struct sentry sentry;
struct stud
{
string term;
string title;
string description;
string tktNum;
string location;
string lecDay;
string instructor;
string labLoc;
string labDay;
string labInstruct;
string units;
string preReqs;
string grade;
};
struct slist
{
int length;
sentry *first;
sentry *last;
};
struct sentry
{
slist *list;
sentry *next;
sentry *prev;
stud *data;
};
void readFile(slist *&header);
My main.cpp
It calls the read file function and outputs it
#include "header.h"
int main()
{
slist *header = NULL;
sentry *temp, *node;
temp = header->first;
readFile(header);
for(int i=0; i<header->length; ++i)
{
cout << node->data->term << endl;
cout << node->data->title << endl;
cout << node->data->description << endl;
cout << node->data->tktNum << endl;
cout << node->data->location << endl;
cout << node->data->lecDay << endl;
cout << node->data->instructor << endl;
cout << node->data->labLoc << endl;
cout << node->data->labInstruct << endl;
cout << node->data->units << endl;
cout << node->data->preReqs << endl;
cout << node->data->grade << endl;
node-> prev = header-> last;
node-> next = NULL;
temp = header -> last;
temp-> next = node;
header-> last = node;
node = temp->prev;
}
return 0;
}
My readFile function - it reads in from a text file and stores the data into the linked list
#include "header.h"
void readFile(slist *&header)
{
ifstream fin;
sentry *node, *temp;
fin.open("data.txt");
while(!fin.eof())
{
if(header == NULL)
{
header = new slist;
header-> length = 0;
header-> first = NULL;
header-> last = NULL;
node = new sentry;
header-> first = node;
header-> last = node;
node-> prev = NULL;
node-> next = NULL;
}else
{
node = new sentry;
node-> prev = header-> last;
node-> next = NULL;
temp = header -> last;
temp-> next = node;
header-> last = node;
}
node->data = new stud;
getline(fin, node->data->term);
getline(fin, node->data->title);
getline(fin, node->data->description);
getline(fin, node->data->tktNum);
getline(fin, node->data->location);
getline(fin, node->data->lecDay);
getline(fin, node->data->instructor);
getline(fin, node->data->labLoc);
getline(fin, node->data->labDay);
getline(fin, node->data->labInstruct);
getline(fin, node->data->units);
getline(fin, node->data->preReqs);
getline(fin, node->data->grade);
header->length++;
}
}
My data.txt file (the text file that is used to read data from)
Fall 2222
CS101
Computer Science Intro
12345
SCI546
MWF 1230PM
John Doe
SCI547
MWF 230PM
John Doe
4
N/A
B
Spring 111
English 101
Intro to English
6789
LI123
TTH 130PM
Jane Doe
N/A
N/A
N/A
N/A
3
N/A
A
slist *header = NULL;
You never allocate anything for header. header is always NULL. Also it's better to call it list, not header. You need instead:
slist list;
You have other uninitialized pointer, example sentry *node; You cannot use this unless it is pointing to something.
You are using C-style declaration in some parts, sort of. C-type structures can be as follows:
typedef struct sentry_t sentry; //in C
In C++ you can simply write struct sentry;
But you don't actually need this. You need the following structures instead:
struct stud
{
... as before
};
struct snode
{
stud data;
snode *next;
snode *prev;
};
struct slist
{
int length;
snode *head;
snode *tail;
};
slist is doubly linked list and snode are its nodes.
Note that I changed the structures, now stud is contained within snode, so you don't need to make a separate allocation with new (in a practical application you have to free all the memory, you want to avoid unnecessary allocations)
Now you can declare and initialize your list:
int main()
{
//declare and initialize the list
slist list;
list.head = NULL;
list.tail = NULL;
list.length = 0;
readFile(list);
snode *node = list.head;
for(int i = 0; i < list.length; i++)
{
cout << node->data.term << endl;
cout << node->data.title << endl;
cout << node->data.description << endl;
...
node = node->next;
cout << "\n";
}
return 0;
}
The read function should be as follows:
void readFile(slist &list)
{
ifstream fin("file");
while(fin.good())
{
snode *node = new snode;
if(list.head == NULL)
{
node->prev = NULL;
node->next = NULL;
list.head = node;
list.tail = node;
}
else
{
list.tail->next = node;
node->prev = list.head;
node->next = NULL;
list.tail = node;
}
getline(fin, node->data.term);
getline(fin, node->data.title);
getline(fin, node->data.description);
...
getline(fin, node->data.grade);
list.length++;
string blankline;
if(!getline(fin, blankline))
break;
}
}
Use fin.good() instead of !fin.eof(). Note that you have a blank line in your file. You want to skip that or break the loop when it reaches the last line.

part of linked list not printing

So I'm working on a linked list code and I have two functions: one to build the list forward and one to build the list backward.
My code runs but the problem I am having is that it is only printing out the function to buildlistForward() but not buildlistBackward()
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin;
//ofstream fout;
struct nodeType
{
int num;
nodeType *next;
};
void buildlistForward();
void buildlistBackward();
//void deleteHead(nodeType);
int main()
{
fin.open("testscores_input.txt");
buildlistForward();
buildlistBackward();
return 0;
}
void buildlistForward()
{
nodeType *head = NULL, *trail = NULL, *current = NULL;
int digit;
cout << "The list built forward is: " << endl;
while (fin >> digit)
{
if (head == NULL)
{
head = new nodeType;
head->num = digit;
head->next = NULL;
trail = head;
}
else
{
current = new nodeType;
current->num = digit;
current->next = NULL;
trail->next = current;
trail = current;
}
}
current = head;
while (current != NULL)
{
cout << current->num << endl;
current = current->next;
}
}
void buildlistBackward()
{
nodeType *head1 = NULL, *current1;
int digit;
cout << "The list built backward is: " << endl;
while (fin >> digit)
{
if (head1 == NULL)
{
head1 = new nodeType;
head1->num = digit;
head1->next = NULL;
}
else
{
current1 = new nodeType;
current1->num = digit;
current1->next = NULL;
current1->next = head1;
head1 = current1;
}
}
current1 = head1;
while (current1 != NULL)
{
cout << current1->num << endl;
current1 = current1->next;
}
}
The program does buildlistForward() first so when the end of the file is read there is nothing to read into for buildlistBackward() you would need to read from the file again by opening the ifstream, however you could also just print the linked list backwards by implementing a tail, and accessing the last node and print each from last to first, rather than reading the input and printing as each node is inputted.

General Linked List C++

New to C++ and I have a general linked list question. Say I have:
struct Node
{
string name;
Node *next
};
in a header file and I have a function
Node ReadIntoList(const string INPUT_FILE)
{
ifstream inFile;
Node *head;
head = NULL;
Node *perPtr;
perPtr = new Node;
inFile.open(INPUT_FILE);
while(inFile && perPtr!= NULL)
{
getline(inFile, perPtr->name);
perPtr -> next = head;
head = perPtr;
perPtr = new Node;
}
delete perPtr;
perPtr = NULL;
return *head;
}
My question is what do I need to return from the ReadIntoList function to main
so that I can access the list and then be able to setup a function to output it
to a file. Here is my main so far...
int main()
{
ofstream oFile;
string inputFile;
Node *head;
cout << left;
cout << "Please enter the name of the input file you would like to "
"use: ";
getline(cin, inputFile);
head = ReadIntoList(inputFile);
oFile.open("OFile.txt");
return 0;
}
This Node in main is not setup properly obviously but I'm not sure how to access the info from ReadIntoList.
In your code, ReadIntoList() is returning the content of the last node in the list (which will crash if the input file fails to open). ReadIntoList() needs to instead return a pointer to the first node in the list. That will allow main() to loop through the list, eg:
Node* ReadIntoList(const string &inputFile)
{
ifstream inFile;
Node *head = NULL;
Node *last = NULL;
Node *perPtr = NULL;
inFile.open(inputFile);
if (inFile)
{
do
{
perPtr = new Node;
if (!getline(inFile, perPtr->name))
{
delete perPtr;
break;
}
perPtr->next = NULL;
if (!head) head = perPtr;
if (last) last->next = perPtr;
last = perPtr;
}
while (true);
}
return head;
}
int main()
{
ofstream oFile;
string inputFile;
Node *head;
Node *perPtr;
Node *tmp;
cout << left;
cout << "Please enter the name of the input file you would like to use: ";
getline(cin, inputFile);
head = ReadIntoList(inputFile);
if (head)
{
oFile.open("OFile.txt");
if (oFile)
{
perPtr = head;
do
{
oFile << perPtr->name << endl;
perPtr = perPtr->next;
}
while (perPtr != NULL);
}
perPtr = head;
do
{
tmp = perPtr->next;
delete perPtr;
perPtr = tmp;
}
while (perPtr != NULL);
}
return 0;
}
That being said, since you are using C++, you should be using std::list (or std::forward_list in C++11 and later) instead, eg:
#include <list>
bool ReadIntoList(const string &inputFile, list<string> &outList)
{
outList.clear();
ifstream inFile(inputFile);
if (!inFile)
return false;
string name;
while (getline(inFile, name))
outList.push_back(name);
return true;
}
int main()
{
ofstream oFile;
string inputFile;
list<string> items;
cout << left;
cout << "Please enter the name of the input file you would like to use: ";
getline(cin, inputFile);
if (ReadIntoList(inputFile, items))
{
oFile.open("OFile.txt");
if (oFile)
{
for (list<string>::const_iterator iter = items.begin(), end = items.end(); iter != end; ++iter)
{
oFile << *iter << endl;
}
}
}
return 0;
}

Readin inFile into Linked List and sort by name

im quite a noob at linked list so i would be very grateful if you could help me with this code,so far if written what you can see below my 1st problem is how can i call my void do sort a text document like(see below) i have written the sort void but have no idea how to writte it properly to access the linked list...
***1stName lastname number email bday***
Nikos Nikolas 281085252 niko#hotmail.com 21/10/1995
mary ann 2810258963 mary#hotmail.com 22/10/1995
james bond 2810254789 james#hotmail.com 23/11/2000
luna loop 2810258741 luna#hotmail.com 24/04/1990
#include <iostream>
#include <fstream>
#include <string>
#define TRUE 1
using namespace std;
struct organizer
{
string first_name;
string last_name;
int number;
string email;
string bday;
organizer* next;
};
int main()
{
void sort_by_last(organizer* head_ptr);
char command;
ifstream inFile;
inFile.open("mycontacts.txt");
if (!inFile)
{
cerr << "Unable to open file." << endl;
return 0;
}
organizer* temp = new organizer;
organizer* head_ptr = temp;
while(inFile)
{
inFile >> temp->first_name;
inFile >> temp->last_name;
inFile >> temp->number;
inFile >> temp->email;
inFile >> temp->bday;
temp->next = new organizer;
temp = temp->next;
}
temp->next = NULL;
while (TRUE)
{
cout << "Write 'print' To print mycontacts." << '\n';
cout << "Write 'find' '..'to search myconacts."<< '\n';
cout << "Write 'delete' 'name'to delete a contact."<< '\n';
cout << "Write 'insert' 'details' to add a contact."<< '\n';
cout << "Write 'quit' to exit the programm."<< '\n';
command = getchar();
switch(command)
{
case 'p':
sort_by_last(organizer);
break;
case 'f':
cout << "search and print\n"; break;
case 'd':
cout << "delete\n";break;
case 'i':
cout << "insert\n";break;
case 'q':
cout << "Quitin programm.\n";
return 0;
}
}
return 0;
}
void sort_by_last(organizer* head_ptr)
{
organizer* node = head_ptr;
organizer* temp = NULL;
while (node->next != NULL)
{
if(node->last_name > node->next->last_name)
{
temp = node;
node = node->next;
temp->next = node;
node = temp;
}
}
}
Don't use struct, use class instead.
class Organizer
{
Organizer() { next = NULL; };
string first_name;
string last_name;
int number;
string email;
string bday;
Organizer* next;
bool operator <(const Organizer &other)
{ return last_name.compare(other.last_name) == -1; };
};
I don't think string supports <, so I used compare instead.
Since you only have a single-linked-list, not double-linked (only next variable, not previous as well), sort needs to take a **, or you need to compare ->next and ->next->next and have a blank head item.
Change sort_by_last(organizer); to sort_by_last(&head_ptr);
The sort function will look something like (assuming you want to do insertion sort, which is slow but simple): (untested)
void sort_by_last(Organizer **head_ptr)
{
Organizer **node = head_ptr;
while (*node != NULL)
{
Organizer **temp = head_ptr;
Organizer **next = &(*node)->next;
while (*temp != NULL && **temp < **node)
temp = &(*temp)->next;
if (*temp != NULL && *temp != *node)
{
(*node)->next = *temp;
(*temp)->next = (*node)->next;
*temp = *node; // same as (*temp)->prev->next = *node
*node = NULL; // so we don't point back to earlier in the list
}
node = next;
}
}
I assume you have to use a linked-list, but std::set would be a much simpler solution (it sorts on insert).
#include <set>
std::set<Organizer> theSet;
...
Organizer organizer;
// set up organizer
theSet.insert(organizer);