Sorting a linked list in C++? [duplicate] - c++

I have a linked-list and I want to sort it in a special order.
I tried to use bubble sort.
As I have many data types in my struct(called Node), I can't swap the values.
struct Node
{
int data;
Node *next;
Node(int x)
{
data = x;
next = NULL;
}
union
{
sold s;
apartment a;
villa v;
}u;
};
Actually I can't swap my union values in my_swap function.
what I need is a new swap function.
here's my code.
#include<iostream>
#include<vector>
#include<string>
using namespace std;
struct adderess {
char city[50];
char street[100];
char alley[100];
int code;
};
struct apartment {
float structure_s;
float price;
int floor;
bool elevator;
adderess adr;
};
struct villa {
float structure_s;
float yard_s;
float price;
int floor;
adderess adr;
};
struct sold {
int type;
float comission;
bool con;
};
struct Node
{
int data;
Node *next;
Node(int x)
{
data = x;
next = NULL;
}
union
{
sold s;
apartment a;
villa v;
}u;
};
void print_list(Node *head)
{
Node *start = head;
while (start)
{
cout << start->data << " -> ";
start = start->next;
}
cout << "\n\n";
}
void my_swap(Node *node_1, Node *node_2)
{
int temp = node_1->data;
node_1->data = node_2->data;
node_2->data = temp;
}
double total_price(Node **n) {
if ((*n)->data == 1)
return((*n)->data*(*n)->data);
else
return((*n)->data*(*n)->data*(*n)->data);
}
void bubble_sort(Node *head)
{
int swapped;
Node *lPtr; // left pointer will always point to the start of the list
Node *rPrt = NULL; // right pointer will always point to the end of the list
do
{
swapped = 0;
lPtr = head;
while (lPtr->next != rPrt)
{
if (total_price(&lPtr) >total_price(& lPtr->next))
{
my_swap(lPtr, lPtr->next);
swapped = 1;
}
lPtr = lPtr->next;
}
//as the largest element is at the end of the list, assign that to rPtr as there is no need to
//check already sorted list
rPrt = lPtr;
} while (swapped);
}
int main()
{
Node *head = new Node(2);
head->next = new Node(1);
head->next->next = new Node(4);
head->next->next->next = new Node(3);
head->next->next->next->next = new Node(6);
head->next->next->next->next->next = new Node(5);
cout << "The original list = " << endl;
print_list(head);
bubble_sort(head);
cout << "The Sorted list = " << endl;
print_list(head);
return 0;
}

Rather than swapping the values within two nodes, you can swap their positions itself in the linked list. For that you'll need to maintain a prev pointer which is the pointer occurring before lPtr in the linked list.
void my_swap(Node*& head, Node*& prev, Node*& node_1, Node*& node_2)
{
if (prev == nullptr)
{
node_1->next = node_2->next;
node_2->next = node_1;
prev = node_2;
head = node_2;
}
else
{
node_1->next = node_2->next;
node_2->next = node_1;
prev->next = node_2;
prev = node_2;
}
}
void bubble_sort(Node *head)
{
bool swapped;
Node *prev, *lPtr, *rPtr; // left pointer will always point to the start of the list
rPtr = nullptr; // right pointer will always point to the end of the list
do
{
swapped = false;
prev = nullptr;
lPtr = head;
while (lPtr->next != rPtr)
{
if (total_price(&lPtr) > total_price(&lPtr->next))
{
my_swap(head, prev, lPtr, lPtr->next);
swapped = true;
}
else
lPtr = lPtr->next;
}
//as the largest element is at the end of the list, assign that to rPtr as there is no need to
//check already sorted list
rPtr = lPtr;
} while (swapped);
}
I haven't checked if it runs correctly but hopefully you get the idea after going through the code.

Related

dynamically allocated struct array for open hash table

I am trying to implement a simple open hash in c++ for the sake of learning. I am getting very confused about the interaction of functions with array pointers, and I am at the end of my wits.
The code:
struct node{
int data;
node* next;
node* prev;
bool state;
node(){
prev = next = NULL;
state = true;
}
};
//state true means empty, state false means full.
void insert(node *array,int value){
node *current = array;
if(array->state == true){
array->data = value;
array->state = false;
} else {
node* add = new node();
add->data = value;
add->state = false;
while(current->next != NULL){
current = current->next;
}
current->next = add;
add->prev = current;
}
}
void display(node *array, int size){
node *show = new node();
for(int i = 0; i< size; i++){
if(array->state == false){
cout<<array->data;
show = array;
while(show->next != NULL){
show = show->next;
cout<<" --> "<<show->data;
}
} else {
cout<<"Empty.";
}
cout<<"\n\n";
}
}
int main(){
int size;
cout<<"Enter size of the hash table: ";
cin>>size;
node *array = new node[size];
int value;
cout<<"Enter Value: ";
cin>>value;
int index = value%size;
//inserting single value
insert(&array[index],value);
//Hash table output.
display(array,size);
return 0;
}
When I run this code, instead of showing "empty" in places where the array's state is empty, it seems as if the entire array has the same value. The problem lies in the insert function, but I cannot figure it out.
You can simplify this by making the Hashtable an array of pointers to Node. A nullptr then means the slot is empty and you don't have empty and full nodes. Also Nodes only need a next pointer and usually new entries are added to the beginning of the buckets instead of the end (allows duplicate entries to "replace" older ones). Inserting at the beginning of a list becomes real easy with Node **.
#include <cstddef>
#include <iostream>
struct Table {
struct Node {
Node * next;
int data;
Node(Node **prev, int data_) : next{*prev}, data{data_} {
*prev = this;
}
};
std::size_t size;
Node **tbl;
Table(std::size_t size_) : size{size_}, tbl{new Node*[size]} { }
~Table() {
for (std::size_t i = 0; i < size; ++i) {
Node *p = tbl[i];
while(p) {
Node *t = p->next;
delete p;
p = t;
}
}
delete[] tbl;
}
void insert(int value) {
Node **slot = &tbl[value % size];
new Node(slot, value);
}
void display() const {
for(std::size_t i = 0; i < size; i++) {
std::cout << "Slot " << i << ":";
for (const Node *node = tbl[i]; node; node = node->next) {
std::cout << " " << node->data;
}
std::cout << std::endl;
}
}
};
int main(){
std::size_t size;
std::cout << "Enter size of the hash table: ";
std::cin >> size;
Table table{size};
int value;
std::cout << "Enter Value: ";
std::cin >> value;
//inserting single value
table.insert(value);
//Hash table output.
table.display();
return 0;
}

Trying to initialize a linked list using array

I need to define a class of linked list,List, in a way such that object of class can be defined in two ways,
List obj1 = L1();//head=0
List obj2 = L2(given_arr[], size of array) // I would be given an array, whose elements are elements of list
so, I need to form a construter for both,
for obj1, Its easy.
List(){head=0};
But I am not abe to do so for second type of object.
I tried to form a program for this.
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head;
int arr[];
List() { head = 0; }
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
int i;
head->val = arr[0];
for (i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[4] = {9, 89, 0, 43};
List* M = new List();
List* L = new List(barr[4], 4);
L->display();
return 0;
}
This program doesn't work. Please suggest a way to do so.
Make these changes to your main().
int main() {
int barr[] = {9, 89, 0, 43}; // No need to specify size if you're initializing
// List* M = new List(); // unused
// Your array is barr, barr[4] makes no sense. You also don't allocate the List,
// the list allocates
List L = List(barr, sizeof(barr) / sizeof(barr[0]);
L.display(); // -> to .
return 0;
}
This now compiles, but immediately segfaults. Simply running the program in the debugger shows a simple error. The line head->val = arr[0]; attempts to dereference a null pointer. Which takes us to the next thing. Use nullptr, not NULL or 0.
Your array constructor was over-complicated, you just need this:
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
Your addnode() function already handled an empty list. Fixing that, your code should run. I made a couple other small changes, mostly trimming cruft out. Here's your complete code:
#include <iostream>
using namespace std;
class List {
class node {
public:
int val;
node* next;
};
public:
node* head = nullptr;
List() = default;
List(int arr[], int size);
void addnode(int value) {
node* newnode = new node();
newnode->val = value;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
node* temp = head;
while (temp != NULL) {
cout << temp->val << " ";
temp = temp->next;
}
cout << endl;
}
}
};
List::List(int arr[], int size) {
for (int i = 0; i < size; i++) addnode(arr[i]);
}
int main() {
int barr[] = {9, 89, 0, 43};
List L = List(barr, sizeof(barr) / sizeof(barr[0]));
L.display();
return 0;
}

Exception thrown: write access violation. this was nullptr (C++)

I'm trying to initialize a Double-Link List and creating new nodes within it
However, I keep getting this error when trying to create a new node "temp", filling it with data, then inserting it into the dLink list.
Here's the code:
// Node of the Double-Link List
struct node {
double x, y;
node *prev;
node *next;
};
// Double-Link List Function
struct dList {
node *head;
node *rear;
};
// Function to check if a list is empty
bool isEmpty(dList *L)
{
if (L == NULL)
return true;
return false;
}
// Function to insert a node at the rear of a list
void insertAtRear(dList *L, double a, double b)
{
node *temp = new node;
temp->x = a;
temp->y = b;
if (isEmpty(L))
{
L->head = temp;
L->rear = temp;
return;
}
temp->prev = L->rear;
L->rear->next = NULL;
L->rear = temp;
return;
}
// Main Function
int main() {
dList *L1=NULL;
dList *L2=NULL;
string fileName1, fileName2;
cout << "Please insert the name of the first csv file in which the information is stored:" << endl;
cin >> fileName1;
readFile(L1, fileName1);
cout << "Please insert the name of the second csv file in which the information is stored:" << endl;
cin >> fileName2;
readFile(L2, fileName2);
system("pause");
return 0;
}
I didn't include the readFile function seeing as it's not the issue, just keep in mind that I'm calling insertAtRear() from within that function
I tried setting *prev and *next as nullptr when initializing them in the structure init.
I'm aware that the issue is related to pointers and them not being correctly initialized but I can't seem to figure out how to fix the issue.
#Yksisarvinen is right, did you initialize L1 & L2 in the readFile function? they appear to be null.
"I'm aware that the issue is related to pointers and them not being correctly initialized"
You can initialize objects correctly with class constructors
struct node {
double x, y;
node *prev;
node *next;
node(const double &x, const double &y) : x(x), y(y), prev(nullptr), next(nullptr) {}
node(const node&) = delete;
~node(void) {}
};
struct dList {
node *head;
node *rear;
dList(node *head=nullptr, node *rear=nullptr) : head(head), rear(rear) {}
dList(const dList&) = delete;
~dList(void)
{
for (; head != nullptr; head = rear)
{
rear = head->next;
head->next = head->prev = nullptr;
delete head;
}
}
};
implementation of isEmpty & insertAtRear should be something like:
bool isEmpty(dList *L)
{
if (L == nullptr) throw "error: null dList pointer!!!!";
return ((L.head == nullptr) || (L.rear == nullptr));
}
bool insertAtRear(dList *L, double a, double b)
{
if (L == nullptr) return false;
node *temp = new node(a, b);
if (isEmpty(L)) L->head = L->rear = temp;
else { temp->prev = L->rear; L->rear = L->rear->next = temp; }
return true;
}
and main function can be:
int main() {
dList L1;
dList L2;
...
readFile(&L1, fileName1);
...
readFile(&L2, fileName2);
system("pause");
return 0;
}
I hope this is helpful

I am getting a breakpoint and i do not know why

I am trying to implement a priority Queue by using a linked list in c++. However, when I run the program it triggers a breakpoint within "priorityQLinkedList::dequeue()" method. Can someone tell why this is the case and give me suggestions on how to fix it?
Code:
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
struct DAT
{
int id;
char fullname[50];
double savings;
};
struct NODE
{
DAT data;
NODE *N;
NODE *P;
NODE(const int i, const char *f, const double s)
{
data.id = i;
strcpy_s(data.fullname, f);
data.savings = s;
N = NULL;
P = NULL;
}
};
class priorityQLinkedList
{
private:
NODE *front;
NODE *back;
public:
priorityQLinkedList() { front = NULL; back = NULL; }
~priorityQLinkedList() { destroyList(); }
void enqueue(NODE *);
NODE* dequeue();
void destroyList();
};
void priorityQLinkedList::enqueue(NODE *n)
{
if (front == NULL) {
front = n;
back = n;
}
else {
NODE *temp = front;
if (n->data.id > temp->data.id)
{
front->P = n;
n->N = front;
front = n;
}
else
{
//search for the posistion for the new node.
while (n->data.id < temp->data.id)
{
if (temp->N == NULL) {
break;
}
temp = temp->N;
}
//New node id's smallest then all others
if (temp->N == NULL && n->data.id < temp->data.id)
{
back->N = n;
n->P = back;
back = n;
}
//New node id's is in the medium range.
else {
temp->P->N = n;
n->P = temp->P;
n->N = temp;
temp->P = n;
}
}
}
}
NODE* priorityQLinkedList::dequeue()
{
NODE *temp;
//no nodes
if (back == NULL) {
return NULL;
}
//there is only one node
else if (back->P == NULL) {
NODE *temp2 = back;
temp = temp2;
front = NULL;
back = NULL;
delete temp2;
return temp;
}
//there are more than one node
else {
NODE *temp2 = back;
temp = temp2;
back = back->P;
back->N = NULL;
delete temp2;
return temp;
}
}
void priorityQLinkedList::destroyList()
{
while (front != NULL) {
NODE *temp = front;
front = front->N;
delete temp;
}
}
void disp(NODE *m) {
if (m == NULL) {
cout << "\nQueue is Empty!!!" << endl;
}
else {
cout << "\nID No. : " << m->data.id;
cout << "\nFull Name : " << m->data.fullname;
cout << "\nSalary : " << setprecision(15) << m->data.savings << endl;
}
}
int main() {
priorityQLinkedList *Queue = new priorityQLinkedList();
NODE No1(101, "Qasim Imtiaz", 567000.0000);
NODE No2(102, "Hamad Ahmed", 360200.0000);
NODE No3(103, "Fahad Ahmed", 726000.0000);
NODE No4(104, "Usmaan Arif", 689000.0000);
Queue->enqueue(&No4);
Queue->enqueue(&No3);
Queue->enqueue(&No1);
Queue->enqueue(&No2);
disp(Queue->dequeue());
disp(Queue->dequeue());
disp(Queue->dequeue());
disp(Queue->dequeue());
disp(Queue->dequeue());
delete Queue;
return 0;
}
One problem which stands out in your dequeue() method is that you are calling delete on a NODE pointer, and then attempting to return this deleted pointer to the caller. This could cause an error either in dequeue() itself, or certainly in the caller who thinks he is getting back a pointer to an actual live NODE object.
One potential fix would be to create a copy of the NODE being dequeued. You would still remove the target from your list, but the caller would then be returned a valid pointer, which he could free later.
NODE* priorityQLinkedList::dequeue()
{
NODE *temp;
// no nodes
if (back == NULL) {
return NULL;
}
NODE *temp2 = back;
temp = new NODE(temp2->data.id, temp2->data.fullname, temp2->data.savings);
// there is only one node
else if (back->P == NULL) {
front = NULL;
back = NULL;
delete temp2;
return temp;
}
// there are more than one node
else {
back = back->P;
back->N = NULL;
delete temp2;
return temp;
}
}
You're deleting pointers in dequeue that priorityQLinkedList does not own, so you don't know if it is safe to delete them.
In this case, they are not since the node pointers passed to enqueue are addresses of local, stacked based variables and have not been allocated by new. (There's also the already mentioned problem of deleting a pointer then returning it, which is Undefined Behavior.)
The fix for the code as shown is to remove the calls to delete in dequeue. However, if changes are made so that the nodes passed to enqueue are dynamically allocated, you'll need to add something to handle that.
1.First change strcpy_s to strcpy is struct NODE.
2.Instead of Delete(temp2) use temp2--.
//no nodes
if (back == NULL) {
return NULL;
}
//there is only one node
else if (back->P == NULL) {
NODE *temp2 = back;
temp = temp2;
front = NULL;
back = NULL;
temp2--;
return temp;
}
//there are more than one node
else {
NODE *temp2 = back;
temp = temp2;
back = back->P;
back->N = NULL;
temp2--;
return temp;
}
I hope this will resolve the problem.

After exiting from function, nodes aren't saved

My program should create a linked list and show it. My problem is when the addelemnt_end function ends, it doesn't update head and last.
I tried with debug and when my function is done, the info and next part from head and last are "unable to read memory".
struct node{
int info;
node *next;
};
node *head, *last;
void addelement_end(node *head, node *last, int element)
{if (head == NULL)
{ node *temp = new node;
temp->info = element;
temp->next = NULL;
last = temp;
head = temp;
}
else {node*temp = new node;
last->next = temp;
temp->info = element;
temp->next = NULL;
last = temp;
}
}
void show(node* head, node *last)
{
if (head==NULL)
cout << "Empty list";
else
while (head != NULL)
{
cout << head->info << " ";
head = head->next;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int x, n, i;
cout << "how many numbers";
cin >> n;
head = last = NULL;
for (i =1; i <= n; i++)
{
cin >> x;
addelement_end(head, last, x);
}
show(head, last);
return 0;
}
It's a very common error. Here is a similar illustration of the problem:
int change_a(int a) {
a = 42;
}
int main() {
int a = 10;
change_a(a);
printf("%d\n", a);
return 0;
}
This will print 10 because in the function change_a you are only modifying a copy of the value contained in the variable a.
The correct solution is passing a pointer (or using a reference since you are using C++).
int change_a(int *a) {
*a = 42;
}
int main() {
int a = 10;
change_a(&a);
printf("%d\n", a);
return 0;
}
But maybe you're going to tell me: "I'm already using a pointer!". Yes, but a pointer is just a variable. If you want to change where the pointer points, you need to pass a pointer to that pointer.
So, try this:
void addelement_end(node **head, node **last, int element)
{
if (*head == NULL)
{ node *temp = new node;
temp->info = element;
temp->next = NULL;
*last = temp;
*head = temp;
}
else {
node *temp = new node;
(*last)->next = temp;
temp->info = element;
temp->next = NULL;
*last = temp;
}
}