**following is my linked list code...
its not working for some reason. Can someone help me out here?
void insertAtTheEnd(node *&head, int data){
node *newNode= new node(data);
newNode->data=data;
node *temp=head;
while(temp!=NULL){
temp=temp->next;
}
temp->next=newNode;
newNode->next=NULL;
newNode->prev=temp->next;
}
As you have it coded, temp is guaranteed to be NULL when your while loop exits. Hence, temp->next=NULL will crash.
When you probe for a position in the list, you typically need to keep "previous" variable to point to the item before the one you are iterating with.
node* temp = head->next;
node* previous = head;
while (temp)
{
previous = temp;
temp = temp->next;
}
// when the while loop returns, `previous` is the last element in the list
previous->next = newNode;
newNode->prev = previous;
newNode->next = nullptr;
Another case you missing in your code. When head is NULL (empty list), you need to update head to be your newNode
// empty list - return the new node as head
if (head == nullptr)
{
newNode->next = nullptr;
newNode->prev = nullptr;
head = newNode;
return;
}
Related
What am I doing wrong here? I'm new to linked lists and would appreciate some insight.
I am trying to add a new node in an empty list, or add a new node at the beginning if a node exists:
void insert(node* previous, int value){
if(previous == nullptr){
node* newNode = new node;
newNode->next = nullptr;
newNode->prev = nullptr;
(*head) = newNode;
(*tail) = newNode;
}else{
node* newNode = new node;
newNode->next = (*head);
newNode->prev = nullptr;
(*head)->prev = newNode;
(*head) = newNode;
}
}
class dlist {
public:
dlist() { }
struct node {
int value;
node* next;
node* prev;
};
node* head() const { return _head; }
node* tail() const { return _tail; }
private:
node* _head = nullptr;
node* _tail = nullptr;
}
There are these issues:
The code refers to head and tail, but these are not defined. There are _head and _tail members which should be used. They are not pointer-pointers, but just pointers.
The code uses previous only to test against nullptr, nothing more. This can never accomplish that the new node should be inserted after that previous node.
The code assumes that if previous is nullptr that the list is currently empty, but that is not the meaning of previous. previous is a reference to the node after which a new node must be inserted. This tells us nothing about the list being empty or not.
The code assumes that the new node will always become the first in the list (as newNode->prev is always set to nullptr), but the goal is to make newNode the successor of previous, so that when previous is an existing node, newNode->prev should point to that previous node.
The value argument is never used. This value should be assigned to the new node's value member.
Here is a possible correction to your code, although we have no way to test it on whichever platform you are to submit it:
void insert(node* previous, int value) {
node* newNode = new node; // Always create a new node (no matter what the case is)
newNode->value = value; // Assign the argument as value
newNode->prev = previous; // previous is always going to be the predecessor
if (previous == nullptr) { // newNode becomes the first node of the list
newNode->next = _head;
_head = newNode; // Set it is the new head
} else { // newNode must come after previous
newNode->next = previous->next;
previous->next = newNode; // Set the reverse link
}
// If there is a node after the new node, it should have a backreference to it
if (newNode->next != nullptr) {
newNode->next->prev = newNode;
}
if (_tail == previous) { // Update tail
_tail = newNode;
}
}
I am trying to make a sorted doubly linked list that doesn't insert duplicates, but I am having trouble finding a way to do this. I looked at posts on how to remove duplicates, but no posts on preventing duplicate insertions.
Here is the code I have to insert and sort without rejecting duplicates. The parameter, dataIn takes values from a predefined Student object list in main (Student s = {{gpa, name}, ..., {gpa, name}}:
void StudentList::insertNode(Student dataIn)
{
ListNode *newNode; // A new node pointer
ListNode *pCur; // To traverse the list
// Allocate a new node and store num there.
newNode = new ListNode;
newNode->stu = dataIn;
newNode->forw = NULL;
newNode->back = NULL;
//Check if there is node in list
if(head ->forw == NULL && head->back == NULL){
head->forw = newNode;
newNode->back = head;
newNode->forw = head;
head->back = newNode;
}
else{
// Initialize pointers
pCur = head->forw;
// Find location: skip all nodes whose name is less than dataIn's name
while (pCur != head && pCur->stu.name < dataIn.name)
{
pCur = pCur->forw;
}
// Insert the new node between pPre and pCur
ListNode *pPre = pCur->back; // The previous node
newNode->back = pPre;
newNode->forw = pCur;
pCur->back = newNode;
pPre->forw = newNode;
}
// Update the counter
count++;
}
Does anyone know a way for rejecting duplicates without deleting? Thanks everyone!
What is the best way to reject duplicates in a sorted doubly linked list?
I suggest delaying the creation of the new ListNode until you know that the new node isn't a duplicate.
Assuming that the ListNode looks like this
struct ListNode {
Student stu;
ListNode *back;
ListNode *forw;
};
and that you have a head and tail ListNode* that is set to nullptr when the StudentList is empty, then the insertNode function could look like this:
bool StudentList::insertNode(const Student& dataIn) { // return true if node is inserted
ListNode* prev = nullptr;
ListNode* pCur = head;
// search for a good insertion spot
for(; pCur; prev = pCur, pCur = pCur->forw) {
if(dataIn.name == pCur->stu.name) return false; // equal, reject
if(dataIn.name < pCur->stu.name) break; // found a good spot before pCur
}
// delayed creation until here:
ListNode* newNode = new ListNode{dataIn, prev, pCur};
// linking
if(prev) prev->forw = newNode;
else head = newNode;
if(pCur) pCur->back = newNode;
else tail = newNode; // comment this line out if you don't have a "tail"
++count;
return true; // node inserted
}
I want to generate a random doubly linked list with a fixed length that is chosen by the user.
The list would insert the first value at the head and then all of the other values at the end of the list but it doesn't correctly adjust the pointers.
Head and tail nodes are both initialized in main to NULL.
Random values work, the problem is with the pointers since at the second iteration the tail stays the same as the head, meaning the list is not increasing.
void GenRandSeq(struct Node* &head, struct Node* &tail, int len){
int i = 0;
std::mt19937 rng;
std::uniform_int_distribution<uint32_t> uint_dist(0,10000);
while (i < len){
Node* newNode = new Node();
int new_el = uint_dist(rng);
newNode->key = new_el;
newNode->prev = NULL;
newNode->next = NULL;
if (head == NULL){
tail = newNode;
head = newNode;
}
else{
if (tail != NULL){
newNode->next = NULL;
newNode->prev = tail;
tail->next = newNode;
}
else
tail = newNode;
}
i++;
}
}
I don't see what I'm missing in the code.
You are not setting tail correctly.
When head and tail are both not null (which should always be true when the list is not empty), you are not updating the tail to point at the newly created node. The assignment of tail needs to be moved out of the else statement. You are appending new nodes to the end of the list, so the tail must be updated on every loop iteration.
Try something more like this instead:
void GenRandSeq(Node* &head, Node* &tail, int len){
std::mt19937 rng;
std::uniform_int_distribution<uint32_t> uint_dist(0,10000);
while (len > 0){
Node* newNode = new Node;
newNode->key = uint_dist(rng);
newNode->prev = tail;
newNode->next = nullptr;
if (!head){
head = newNode;
}
if (tail){
tail->next = newNode;
}
tail = newNode;
--len;
}
}
Which can then be streamlined a little bit further by eliminating the if statements inside the loop:
void GenRandSeq(Node* &head, Node* &tail, int len){
std::mt19937 rng;
std::uniform_int_distribution<uint32_t> uint_dist(0,10000);
Node **next = (tail) ? &(tail->next) : &head;
while (len > 0){
Node *newNode = new Node;
newNode->key = uint_dist(rng);
newNode->prev = tail;
newNode->next = nullptr;
*next = newNode;
tail = newNode;
next = &(newNode->next);
--len;
}
}
Below fragment is invalid to inserting a node in the end of Linked List.
void insert_end(int item){
nodeptr newNode = new ListNode;
newNode->data = item;
newNode->next = NULL;
if(head == NULL){
head = newNode;
curr = head;
}else{
curr = head;
while(curr != NULL) curr = curr->next;
curr = newNode;
}
}
Another fragment that is valid to inserting a node in the end of Linked List.
void insert_end(int item){
nodeptr newNode = new ListNode;
newNode->data = item;
newNode->next = NULL;
if(head == NULL){
head = newNode;
curr = head;
}else{
curr = head;
while(curr->next != NULL) curr = curr->next;
curr->next = newNode;
}
}
My question is why 1st one is invalid? Actually two fragments should be similar.
Assume i have three nodes already. Now i want to inserting another node.
As first algorithm when curr = NULL, then while loop will not satisfied.
As second algorithm when curr->next = NULL then while loop will not satisfied.
so can i say first algorithm's 'curr' and second algorithm 'curr->next' both are similar, when "while loop" terminated?
if it's not similar then why?
You must understand a pointer is a variable which value is an address.
First algorithm is wrong because when you finish the iteration of while loop, curr points to NULL (address 0x0), and NULL is not a valid node of your list.
Second algoritm works because when you finish the iteration of while loop, curr points to last node of your list, and you add newNode to curr->next, replacing NULL by the address of newNode.
Hope this helps! :)
I have to write a method that's going to delete the last node from the List. Do you guys have any ideas on how I should approach this?
If you have a single-linked list, you have no choice but to iterate through the entire list to the last node, maintaining a pointer to the previous node so you can reset its next field when freeing the last node:
if (head)
{
node *curNode = head;
node *prevNode = NULL;
while (curNode->next)
{
prevNode = curNode;
curNode = curNode->next;
}
if (prevNode) prevNode->next = NULL;
delete curNode;
}
If you were using a double-linked list instead, this would be easier, as you can keep a pointer to the last node in the list and just operate on it directly:
if (head == tail)
{
delete head;
head = tail = NULL;
}
else if (tail)
{
node *curNode = tail;
tail = curNode->previous;
tail->next = NULL;
delete curNode;
}
Of course, if you are really using C++ then you should be using the STL's std::list (double-linked) or std::forward_list (single-linked) containers instead, which handle these details for you.
To delete the last element on a list all you need to do is maintain two separate nodes. Initially one should point to the head of the list and the other should point to the second element on the list. You should do something like the following :
if(head == NULL)
return 0;
else if(head->next == NULL){
Node *temp = head;
delete temp;
head = NULL;
}
else{
Node *one = head;
Node *two = head->next;
while(two->next != NULL){
two = two->next;
one = one->next;
}
one->next = NULL;
delete two;
}