Pointer back and next for a node - pointers

I'm new to C++. I'm now trying to create a class with back and forth pointer. My code is listed below:
#include<iostream>
using namespace std;
class Node
{
public:
Node(int d, Node*k = NULL, Node*q = NULL) :data(d), back(k), next(q){};
int data;
Node*next; // point to next value on the list
Node*back; // point to back value on the list
};
int main()
{
int n;
Node*p = NULL;
Node*k = NULL; //k is back
while (cin >> n)
{
p = new Node(n,k);
p->back->next = p;
k = p;
}
for (; p; p = p->back)
cout << p->data << "->";
cout << "*\n";
system("pause");
}
However, I always have this error: "Access violation writing location"
I wonder if anybody have a solution ? Thanks

In the first iteration of the loop p->back is NULL. You get the access violation because you dereference it. Write this instead:
while (cin >> n)
{
p = new Node(n,k);
if (p->back != NULL) // p->back == NULL in the first iteration
p->back->next = p;
k = p;
}

Related

code got strucked in a infinite loop when I tried to reverse a linked list using recursion

I was trying to reverse a linked list using recursion but when I tried to print out all the elements of the linked list at first it was printing out elements as expected but after printing out the last element it started printing the last and second last element repeatedly. I tried to debug it and I think the problem is that the last element is pointing towards the second last element whether it should be pointing towards NULL. I am not able to figure out what is wrong with my code so please help me out.
example- input 1,2,3,4,5,6
expected output 6,5,4,3,2,1
actual output 6,5,4,3,2,1,2,1,2 ...
#include<iostream>
using namespace std;
class node{
public:
int val;
node *next;
node(int val)
{
this->val = val;
this->next = NULL;
}
node(int val,node *next)
{
this->val= val;
this->next=next;
}
};
void insertAtTail(node *&head,int val){
node *n = new node(val);
if (head==NULL)
{
head = n;
return;
}
node *temp = head;
while (temp->next!=NULL)
{
temp = temp->next;
}
temp->next=n;
}
void display(node *head)
{
node *n = head;
while (n!=NULL)
{
cout << n->val << "->";
n = n->next;
}
cout << "NULL" << endl;
}
node* reverseRecursive(node *&head)
{
if (head == NULL || head->next==NULL)
{
return head;
}
node *nHead = reverseRecursive(head->next);
head->next->next = head;
head->next == NULL;
return nHead; // 1->2->3->4->5->6->NULL
}
int main()
{
node *head = NULL;
insertAtTail(head,1);
insertAtTail(head,2);
insertAtTail(head,3);
insertAtTail(head,4);
insertAtTail(head,5);
insertAtTail(head,6);
display(head);
node *newhead = reverseRecursive(head);
display(newhead);
return 0;
}
There is a bug in function reverseRecursive().
Line head->next == NULL; should be head->next = NULL;
node* reverseRecursive(node *&head)
{
if (head == NULL || head->next==NULL)
{
return head;
}
node *nHead = reverseRecursive(head->next);
head->next->next = head;
head->next == NULL; // <<< should be head->next = NULL;
return nHead; // 1->2->3->4->5->6->NULL
}
Not sure which compiler you were using, but this statement will typically generate a warning.

when to use to double pointers and pointers

// A C program to demonstrate linked list based implementation of queue
#include <stdio.h>
#include <stdlib.h>
struct QNode {
int key;
struct QNode* next;
};
struct Queue {
struct QNode *front, *rear;
};
struct QNode* newNode(int k)
{
struct QNode* temp = (struct QNode*)malloc(sizeof(struct QNode));
temp->key = k;
temp->next = NULL;
return temp;
}
struct Queue* createQueue()
{
struct Queue* q = (struct Queue*)malloc(sizeof(struct Queue));
q->front = q->rear = NULL;
return q;
}
void enQueue(struct Queue* q, int k)
{
struct QNode* temp = newNode(k);
if (q->rear == NULL) {
q->front = q->rear = temp;
return;
}
q->rear->next = temp;
q->rear = temp;
}
void deQueue(struct Queue* q)
{
if (q->front == NULL)
return;
struct QNode* temp = q->front;
q->front = q->front->next;
if (q->front == NULL)
q->rear = NULL;
free(temp);
}
int main()
{
struct Queue* q = createQueue();
enQueue(q, 10);
enQueue(q, 20);
deQueue(q);
deQueue(q);
enQueue(q, 30);
enQueue(q, 40);
enQueue(q, 50);
deQueue(q);
printf("Queue Front : %d \n", q->front->key);
printf("Queue Rear : %d", q->rear->key);
return 0;
}
The above code is from geeksforgeeks website.
in function calls they used pointer to struct,
in function definition they passed pointer to struct.
how it works, I thought we need to use double pointers , otherwise > it is pass by value instead of pass by reference.
the above code works fine, but i have doubt about it.
In main there is a variable q declared which is a pointer to a struct. The variable q is used as the function argument which means the function receives a pointer to the struct. The function can dereference the pointer and modify the struct. The variable q is technically passed by value because its value is a pointer and that's what the function receives. But you have to remember that q points to a struct that could be modified by the function.
Because this situation causes some confusion some people have tried to introduce new terminology like "pass by sharing" or "object sharing" to distinguish it from passing primitive values like an `int' by value.
If you had passed a pointer to a pointer then the function could have modified the variable q declared in main and changed it so it points to a completely different struct. That would be (technically) pass by reference because you are passing a reference to the variable.

Is my binary tree program reaching an overflow/recursive maximum?

#include <iostream>
using namespace std;
struct Node{
bool flag;
char letter;
Node* left;
Node* right;
};
typedef Node* Nodeptr;
int stop = 0;
void splitString(string sequence, Nodeptr branch){
//cout << sequence << " ";
//cout << sequence.size() << endl;
if(stop == 20) return;
else stop++;
if(sequence.size() == 1){
branch->flag = true;
branch->letter = sequence[0];
}
else{
int half = sequence.size()/2;
Node* left = new Node;
Node* right = new Node;
branch->flag = false;
branch->left = left;
branch->right = right;
splitString(sequence.substr(0, half), left);
splitString(sequence.substr(half), right);
}
return;
}
void print(Nodeptr root){
if(root->flag)
cout << root->letter;
else{
print(root->left);
print(root->right);
}
return;
}
int main() {
std::cout << "Hello World!\n";
Nodeptr tree = new Node;
splitString("Heaven on ", tree);
print(tree);
//the above two lines run fine
Nodeptr tree2 = new Node;
splitString("Heaven on E", tree2); //this code will run fine
//print(tree2); //this code will give me an EXITED, SEGMENTATION FAULT error
}
Considering that the two lines:
splitString("Heaven on ", tree);
print(tree);
run fine, but these do not:
splitString("Heaven on E", tree2);
//print(tree2); //this code will give me an EXITED, SEGMENTATION FAULT error
I come to think that I have reached the maximum recursion depth. I reviewed my code for the building and traversing the binary tree but I cannot find any problems there. What is the reason for the error? Thanks!
For two reason:
you are using a global, which is a very bad practice, and for example in this case you are not resetting it after the first splitString
you are not managing the case where the string has 0 as size, in the right way
This is a possible implementation of splitString which works (without globals):
void splitString(string sequence, Nodeptr branch){
if(sequence.size() == 1){
branch->flag = true;
branch->letter = sequence[0];
}
else if (sequence.size() > 1){
int half = sequence.size()/2;
Node* left = new Node;
Node* right = new Node;
branch->flag = false;
branch->left = left;
branch->right = right;
splitString(sequence.substr(0, half), left);
splitString(sequence.substr(half), right);
}
else {
branch->flag = true;
branch->letter = '\0';
}
}
There is surely a better way to do this, and i'll encourage you to change the data structor in order to makes it happen (for example don't use the flag to mark the leaves of the tree, just check if there is left is been set or is nullptr)

Queue implementation throws incompatible pointer type error

I think I'm missing general concepts on structs and pointers. Hence, below code is producing 2 warnings/errors and I don't understand why.
Why is "queue->head = temp" producing following warning:
warning: assignment from incompatible pointer type [enabled by default]
Why is "queue->tail->next = temp" producing following error:
error: dereferencing pointer to incomplete type.
Note: The line "Node *temp = newNode(data)" does not throw any error/warnings so it's successful.
typedef struct {
int data;
struct Node *next;
} Node;
typedef struct {
struct Node *head;
struct Node *tail;
} Queue;
void enQueue(Queue *queue, int data)
{
// Create a new node
Node *temp = newNode(data);
// If queue is empty, then new node is both head and tail
if (queue->tail == NULL)
{
queue->head = temp;
queue->tail = temp;
return;
}
// Add the new node at the end of queue and change tail
queue->tail->next = temp;
queue->tail = temp;
}
How did you get this code to compile?
Your Node structure contains a pointer to another Node. In the way you declared your structure, the compiler does not know Node while parsing your structure definition. Hence, you must write:
1 typedef struct Node{
2 int data;
3 struct Node *next;
4 } Node;
In this way, the compiler knows how to handle your structure when parsing it. In line 3 it already knows that Nodeis structure. Since some of your code is missing, I created a minimal example that implements a super simple queue:
#include <stdlib.h>
#include <stdio.h>
#define MAX 5
typedef struct Node{
int data;
struct Node *next;
} Node;
typedef struct {
struct Node *head;
struct Node *tail;
} Queue;
Node* newNode(const int nodeData){
Node* tmp = malloc(sizeof(*tmp));
if (NULL == tmp){
printf("Could not allocate Node ... exiting");
exit(EXIT_FAILURE);
}
tmp->data = nodeData;
tmp->next = NULL;
return tmp;
}
void enQueue(Queue *queue, int data)
{
// Create a new node
Node *temp = newNode(data);
// If queue is empty, then new node is both head and tail
if (queue->tail == NULL)
{
printf("Queue is empty\n");
queue->head = temp;
queue->tail = temp;
return;
}
// Add the new node at the end of queue and change tail
queue->tail->next = temp;
queue->tail = temp;
}
void printQueue(Queue* q){
Node* tmp = q->head;
while (tmp != NULL){
printf("Value: %d\n", tmp->data);
tmp = tmp->next;
}
}
int main(void){
Queue q;
q.head = q.tail = NULL;
int i;
for (i = 0; i < MAX; ++i){
printf("%d is entered into the queue\n", i);
enQueue(&q, i);
}
printQueue(&q);
}

Base case condition in quick sort algorithm

For the quick sort algorithm(recursive), every time when it calls itself, it have the condition if(p < r). Please correct me if I am wrong: as far as I know, for every recursive algorithm, it has a condition as the time when it entered the routine, and this condition is used to get the base case. But I still cannot understand how to correctly set and test this condition ?
void quickSort(int* arr, int p, int r)
{
if(p < r)
{
int q = partition(arr,p,r);
quickSort(arr,p,q-1);
quickSort(arr,q+1,r);
}
}
For my entire code, please refer to the following:
/*
filename : main.c
description: quickSort algorithm
*/
#include<iostream>
using namespace std;
void exchange(int* val1, int* val2)
{
int temp = *val1;
*val1 = *val2;
*val2 = temp;
}
int partition(int* arr, int p, int r)
{
int x = arr[r];
int j = p;
int i = j-1;
while(j<=r-1)
{
if(arr[j] <= x)
{
i++;
// exchange arr[r] with arr[j]
exchange(&arr[i],&arr[j]);
}
j++;
}
exchange(&arr[i+1],&arr[r]);
return i+1;
}
void quickSort(int* arr, int p, int r)
{
if(p < r)
{
int q = partition(arr,p,r);
quickSort(arr,p,q-1);
quickSort(arr,q+1,r);
}
}
// driver program to test the quick sort algorithm
int main(int argc, const char* argv[])
{
int arr1[] = {13,19,9,5,12,8,7,4,21,2,6,11};
cout <<"The original array is: ";
for(int i=0; i<12; i++)
{
cout << arr1[i] << " ";
}
cout << "\n";
quickSort(arr1,0,11);
//print out the sorted array
cout <<"The sorted array is: ";
for(int i=0; i<12; i++)
{
cout << arr1[i] << " ";
}
cout << "\n";
cin.get();
return 0;
}
Your question is not quite clear, but I will try to answer.
Quicksort works by sorting smaller and smaller arrays. The base case is an array with less than 2 elements because no sorting would be required.
At each step it finds a partition value and makes it true that all the values to the left of the partition value are smaller and all values to the right of the partition value are larger. In other words, it puts the partition value in the correct place. Then it recursively sorts the array to the left of the partition and the array to right of the partition.
The base case of quicksort is an array with one element because a one element array requires no sorting. In your code, p is the index of the first element and r is the index of the last element. The predicate p < r is only true for an array of at least size 2. In other words, if p >= r then you have an array of size 1 (or zero, or nonsense) and there is no work to do.

Resources