Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm having a little trouble with getting my head around how this function would work and what I need to do. I have int number as my data type and node* next in my node class. I also have node pointers head, current and temp. My question is how would I go about getting my list of integers into order? Also how does ascending and decending work in a single linked list?
My header file:
#ifndef SDI_LL
#define SDI_LL
namespace SDI
{
class LinkedList
{
class Node
{
public:
int number; //data element
Node* next; //pointer to next, node inside each node
private:
};
private:
Node *head;
Node *current; //head, current and temp node pointers
Node *temp;
public:
LinkedList(); //constructor to access nodes from above
~LinkedList(); //destructor
void insert(int add);
void remove(int remove); //functions that access private data nodes above
void display();
void reverse();
void search(int searchNum);
void sortAscending();
void sortDecending();
void saveAll();
void restoreAll();
};
}
#endif
My ascending function so far where it starts from the beginning and searches through the list:
void LinkedList::sortAscending()
{
current = head;
for (current = head; current;)
{
temp = current;
current = current->next;
}
}
In general, you should use containers available in the standard libraries, which provide efficient sorting methods where applicable.
That said, if you want to do it for learning purposes - as you probably "should at least once" - then it is not too difficult to implement.
for (current = head; current;)
That's a funny for loop, personally I'd prefer:
current = head;
while(current) // or current != nullptr to be more explicit
Note also that you (unnecessarily, of course) assign head to current twice - immediately before the for loop, and in the initialisation of it.
A simple scheme (but not at all efficient!) might be to just swap 'out of order' elements as you iterate through the list, until no swaps were necessary:
bool changeMade;
do{
changeMade = false;
current = head;
while( current ){
temp = current;
current = current->next;
if( current && current->data < temp->data ){
changeMade = true;
swap( temp->data, current->data );
}
}
} while( changeMade );
This assumes a data field is the only other in the node - since it doesn't actually swap the nodes, just the data. (Doing the former is not really any more difficult - but without seeing your node type declaration I'd be making up names and risk confusing the issue.)
I don't see any declarations for current, head, and temp, but I assume they are pointers to node. Have you decided on a sort algorithm? Does the sort algorithm need to be efficient or is something with the performance of a bubble sort ok? With logic similar to a bubble sort, you can repeatedly move the node with the largest value to the end of the list. Or to save a bit of time, you could remove the node with the largest value from the original list and insert it into the front of a new list that would end up in sorted order. More efficient algorithms use logic based on merge sort.
To remove or swap nodes, using a pointer to pointer can avoid special handling for the first node of a list (the one pointed to by pList in this example):
NODE * SortList(NODE * pList)
{
NODE * pNew = NULL; /* sorted list */
NODE **ppNode; /* ptr to ptr to node */
NODE **ppLargest; /* ptr to ptr to largest node */
NODE * pLargest; /* ptr to largest node */
while(pList != NULL){ /* while list not empty */
ppLargest = &pList; /* find largest node */
ppNode = &((*ppLargest)->next);
while(NULL != *ppNode){
if((*ppNode)->data > (*ppLargest)->data)
ppLargest = ppNode;
ppNode = &((*ppNode)->next);
}
pLargest = *ppLargest; /* move node to new */
*ppLargest = pLargest->next;
pLargest->next = pNew;
pNew = pLargest;
}
return(pNew);
}
Related
I've been doing this as an exercise on my own to get better at C++ (messing around with a linked list I wrote). What I want to do is to reverse the list by twisting the pointers around, rather than just 'printing' the data out in reverse (which is relatively straightforward).
I have an array of pointers-to-pointers, each pointing to a node in a linked list. But this is less a question about linked-list dynamics (which I understand), and more about pointer magick.
A node looks like this,
template<class T>
struct node {
T data;
node *next;
node(T value) : data(value), next(nullptr) {}
};
And the code in question,
node<T> **reverseArr[listLength];
node<T> *parser = root;
for (auto i : reverseArr) {
i = &parser;
parser = parser->next;
}
root = *(reverseArr[listLength - 1]);
for (int ppi = listLength - 1; ppi >= 0; --ppi) {
if (ppi == 0) {
(*reverseArr[ppi])->next = nullptr;
//std::cout << "ppi is zero!" << "\t";
}
else {
(*reverseArr[ppi])->next = (*reverseArr[ppi - 1]);
//std::cout << "ppi, 'tis not zero!" << "\t";
}
}
My logic:
The new root is the last element of the list,
Iterate through the array in reverse,
Set the current node's next pointer to the previous one by setting the current node's nextNode to the next node in the loop.
What's happening:
If I leave the debug print statements commented, nothing. The function's called but the linked list remains unchanged (not reversed)
If I uncomment the debug prints, the program seg-faults (which doesn't make a whole lot of sense to me but seems to indicate a flaw in my code)
I suspect there's something I'm missing that a fresh pair of eyes might catch. Am I, perhaps, mishandling the array (not accounting for the decay to a pointer or something)?
You're overthinking the problem. The correct way to reverse a single-linked list is much simpler than you think, and does not involve arrays at all.
All you need to do is walk through the list setting each node's next pointer to the head of the list, then set the head of the list to that node. Essentially, you are unlinking each node and inserting it at the start of the list. Once you reach the end, your list is reversed.
It just requires a bit of care, because the order that you do things is important. Something like this should do it:
template <class T>
node<T> * reverse( node<T> * head )
{
node<T> *current = head;
head = NULL;
while( current != NULL )
{
// store remainder of list
node<T> *remain = current->next;
// re-link current node at the head
current->next = head;
head = current;
// continue iterating remainder of list
current = remain;
}
return head;
}
The operation has a linear time complexity. You would invoke it by passing your list's head node as follows:
root = reverse( root );
It should go without saying that it would be a bad idea to call this function with any node that is not the head of a list, or to pass in a list that contains cycles.
I recently saw an implementation of deleting a node from a single linked list using a double pointer . Other than making the code more beautiful does this implementation have any benefits efficiency wise . Also how can I implement a similar approach towards inserting a node to a linked list ( without keeping track of previous Node ). I am really curious if there is any better algorithm out there to achieve this
Node* Delete(Node *head, int value)
{
Node **pp = &head; /* pointer to a pointer */
Node *entry = head;
while (entry )
{
if (entry->value == value)
{
*pp = entry->next;
}
pp = &entry->next;
entry = entry->next;
}
return head;
}
For insertion to the back of a list storing only the head, no tail (which would imply a small list where linear-time insertion is acceptable), you can do this by introducing the extra pointer indirection to eliminate special cases:
Simple Version (Pointers to Pointers to Nodes)
void List::push_back(int value)
{
// Point to the node link (pointer to pointer to node),
// not to the node.
Node** link = &head;
// While the link is not null, point to the next link.
while (*link)
link = &(*link)->next;
// Set the link to the new node.
*link = new Node(value, nullptr);
}
... which you can reduce to just:
void List::push_back(int value)
{
Node** link = &head;
for (; *link; link = &(*link)->next) {}
*link = new Node(value, nullptr);
}
As opposed to, say:
Complex Version (Pointers to Nodes)
void List::push_back(int value)
{
if (head)
{
// If the list is not empty, walk to the back and
// insert there.
Node* node = head;
while (node->next)
node = node->next;
node->next = new Node(value, nullptr);
}
else
{
// If the list is empty, set the head to the new node.
head = new Node(value, nullptr);
}
}
Or to be fair and remove comments:
void List::push_back(int value)
{
if (head)
{
Node* node = head;
for (; node->next; node = node->next) {}
node->next = new Node(value, nullptr);
}
else
head = new Node(value, nullptr);
}
No Special Case for Simple Version
The main reason the first version doesn't have to special case empty lists is because if we imagine head is null:
Node** link = &head; // pointer to pointer to null
for (; *link; link = &(*link)->next) {}
*link = new Node(value, nullptr);
Then the for loop condition is immediately false and we then assign the new node to the head. We don't have to check for that case separately outside the loop when we use pointers to pointers.
Insertion Sort
If you want to do an insertion sort instead of simply inserting to the back, then this:
void List::insert_sorted(int value)
{
Node** link = &head;
for (; *link && (*link)->value < value; link = &(*link)->next) {}
// New node will be inserted to the back of the list
// or before the first node whose value >= 'value'.
*link = new Node(value, *link);
}
Performance
As for performance, not sure it makes much difference to eliminate the extra branch, but it definitely makes the code tighter and reduces its cyclomatic complexity. The reason Linus considers this style to be "good taste" is because in C, you often have to write linked list logic often since it's not so easy and necessarily worthwhile to generalize linked lists since we have no class templates there, e.g., so it's handy to favor a smaller, more elegant, less error-prone way to write this stuff. Plus it demonstrates that you understand pointers quite well.
Other than making the code more beautiful does this implementation
have any benefits efficiency wise.
Don't have anything to compare this to so hard to say but this is about as efficient as you can remove a node from a linked list. Note that the function name Delete would be more accurate as Remove since it does not actually clean up the node it removes from the list.
Also how can I implement a similar approach towards inserting a node
to a linked list ( without keeping track of previous Node ).
One way is to look ahead. Best shown in an example following the format of your Delete function.
void insert(Node *head, int value)
{
Node *entry = head;
while (entry)
{
if (entry->next == NULL)
{
entry->next = new Node(NULL, value);
return;
}
else if (value < entry->next->value)
{
entry->next = new Node(entry->next, value);
return;
}
entry = entry->next;
}
}
i want this function sortPair to take 2 Node pointers and return a pointer to a list of the 2 elements sorted alphabetically. The code below is what I have so far. If someone could let me know where I went wrong, that would be great.
struct Node{
string val;
Node* next;
};
Node* sortPair (Node* p1, Node* p2){
//Assert that neither pointer is null
assert(p1!=NULL);
assert(p2!=NULL);
Node* head=NULL;
Node* current=NULL;
Node* last = NULL;
current = new Node();
if(p1-> val >p2-> val) //If p1->val comes before p2->val in the alphabet
{
current->val = p1->val;
head = current;
last = current;
current = new Node();
current -> val = p2->val;
last = current;
last ->next = NULL;
}
else
{
current->val = p2->val;
head = current;
last = current;
current = new Node();
current -> val = p1->val;
last = current;
last ->next = NULL;
}
return head;
}
A linked list is just a series of nodes that are linked by each element having a pointer to the next one.
From your code, it seems like you do not want to make a list of the two nodes, but rather insert a node into a list that already exists.
If all you want to do is to make a linked list of the two nodes that are there, then set the one with the lower or higher value, depending on how you sort them, to point at the other one. For example, if you are sorting from smallest to biggest, set the smallest node's next pointer to point to the bigger one and return the pointer of the smallest one.
If you want to add one of the nodes into a list of nodes, then you must loop through the list until you find one that is larger or smaller than the node you want to insert. I recommend using a while loop.
If you want to merge two lists, then you must make a new loop that inserts each element of one list into the other list.
There is no need to make a new node for any of this, just use the ones you have and change the next pointers.
Hope this helps.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to read a singly linked list backwards?
Reverse a LinkedList c++
How can I reverse the elements of a connected list without using arrays
(I have to use only pointers thats my problem).
You need neither to swap node content or a stack. If you want to reverse a single-linked list just walk it with a pair of pointers plus on intermediate pointer within the iterative loop. Don't forget to update the head pointer when you're finished;
void reverse_list(node **head)
{
node *cur=NULL, *nxt=NULL;
if (!(head || *head || (*head)->next))
return;
nxt = *head;
while (nxt != NULL)
{
node *prv = cur;
cur = nxt;
nxt = nxt->next;
cur->next = prv;
}
*head = cur;
}
Assuming the list node is something like this:
typedef struct node
{
..data..
struct node *next;
} node;
and it is properly managed, then you invoke as such:
node *head = NULL;
...fill the list...
reverse_list(&head);
Treat the list like a stack, pop the elements off and push them into a new list.
Conside a list called lst which allows us to move forward backward i.e it is doubly linked list
You can reverse the list lst by simply swapping the content of the beginning and the end nodes
void reverse(lst *beg,lst *end)
{
lst temp;
while(beg!=end)
{
//swap the content of the nodes
*temp=*beg;
*beg=*end;
*end=*temp;
beg=beg->Next();//move to next node
end=end->prev();//move to previous node
}
}
OR
If its a singly linked list,you can use stack
void reverse(lst* beg)
{
stack<lst*> stc;
lst* temp=beg;
lst* temp1=beg;
while(temp)//store pointers to lst nodes in stack
{
stc.push(temp);
temp=temp.Next();
}
while(temp1)//pop the stack by inserting it into list from beginning
{
*temp1=*stc.top();
temp1=temp1.Next();
stc.pop();
}
}
This question already has answers here:
An interesting C linked list idiom
(11 answers)
Closed 5 years ago.
Ten years ago, I was shown a technique for traversing a linked list: instead of using a single pointer, you used a double pointer (pointer-to-pointer).
The technique yielded smaller, more elegant code by eliminating the need to check for certain boundary/edge cases.
Does anyone know what this technique actually is?
I think you mean double pointer as in "pointer to a pointer" which is very efficient for inserting at the end of a singly linked list or a tree structure. The idea is that you don't need a special case or a "trailing pointer" to follow your traversal pointer once you find the end (a NULL pointer). Since you can just dereference your pointer to a pointer (it points to the last node's next pointer!) to insert. Something like this:
T **p = &list_start;
while (*p) {
p = &(*p)->next;
}
*p = new T;
instead of something like this:
T *p = list_start;
if (p == NULL) {
list_start = new T;
} else {
while (p->next) {
p = p->next;
}
p->next = new T;
}
NOTE: It is also useful for making efficient removal code for a singly linked list. At any point doing *p = (*p)->next will remove the node you are "looking at" (of course you still need to clean up the node's storage).
By "double-pointer", I think you mean "pointer-to-pointer". This is useful because it allows you to eliminate special cases for either the head or tail pointers. For example, given this list:
struct node {
struct node *next;
int key;
/* ... */
};
struct node *head;
If you want to search for a node and remove it from the list, the single-pointer method would look like:
if (head->key == search_key)
{
removed = head;
head = head->next;
}
else
{
struct node *cur;
for (cur = head; cur->next != NULL; cur = cur->next)
{
if (cur->next->key == search_key)
{
removed = cur->next;
cur->next = cur->next->next;
break;
}
}
}
Whereas the pointer-to-pointer method is much simpler:
struct node **cur;
for (cur = &head; *cur != NULL; cur = &(*cur)->next)
{
if ((*cur)->key == search_key)
{
removed = *cur;
*cur = (*cur)->next;
break;
}
}
I think you mean doubly-linked lists where a node is something like:
struct Node {
(..) data // The data being stored in the node, it can be of any data type
Node *next; // A pointer to the next node; null for last node
Node *prev; // A pointer to the previous node; null for first node
}
I agree with the comments about using the STL containers for handling your list dirty work. However, this being Stack Overflow, we're all here to learn something.
Here's how you would normally insert into a list:
typedef struct _Node {
void * data;
Node * next;
} Node;
Node * insert( Node * root, void * data ) {
Node * list = root;
Node * listSave = root;
while ( list != null ) {
if ( data < list->data ) {
break;
}
listSave = list;
list = list->next;
}
Node * newNode = (Node*)malloc( sizeof(Node) );
newNode->data = data;
/* Insert at the beginning of the list */
if ( listSave == list ) {
newNode->next = list;
list = newNode;
}
/* Insert at the end of the list */
else if ( list == null ) {
listSave->next = newNode;
newNode->next = null;
list = root;
}
/* Insert at the middle of the list */
else {
listSave->next = newNode;
newNode->next = list;
list = root;
}
return list;
}
Notice all the extra checking you have to do depending on whether the insertion occurs at the beginning, end or middle of the list. Contrast this with the double pointer method:
void insert( Node ** proot, void * data ) {
Node ** plist = proot;
while ( *plist != null ) {
if ( data < (*plist)->data ) {
break;
}
plist = &(*plist)->next;
}
Node * newNode = (Node *)malloc( sizeof(Node) );
newNode->data = data;
newNode->next = *plist;
*plist = newNode;
}
As Evan Teran indicated, this works well for singly linked lists, but when it's doubly linked, you end up going through just as many if not more manipulations as the single pointer case. The other draw back is that you're going through two pointer dereferences for each traversal. While the code looks cleaner, it probably doesn't run as quickly as the single pointer code.
You probably mean a doubly-linked list, with one of the pointers going forward and the other going backward. This allows you to get to the next and previous nodes for a given node without having to remember the last one or two nodes encountered (as in a singly-linked list).
But the one thing I discovered which made the code even more elegant was to always have two dummy elements in the list at all times, the first and the last. This gets rid of the edge cases for insertion and deletion since you're always acting on a node in the middle of the list.
For example, an empty list is created:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
Obviously, traversing the list is slightly modified (forward version shown only):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
The insertions are much simpler since you don't have to concern yourself with whether you're inserting at the start or end of the list. To insert before the current point:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
Deletions are also simpler, avoiding the edge cases:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
All very much cleaner code and at the cost of only having to maintain two extra nodes per list, not a great burden in today's huge memory space environments.
Caveat 1: If you're doing embedded programming where space still might matter, this may not be a viable solution (though some embedded environments are also pretty grunty these days).
Caveat 2: If you're using a language that already provides linked list capabilities, it's probably better to do that rather than roll your own (other than for very specific circumstances).