Reverse Traversing singly linked list in C++ - c++

Recently I have been asked this question on an interview. All I could do is traverse from 9 to 1 from a linked list starting from 0 to 9. Here is the code:
#include <iostream>
typedef struct node {
int data; // will store information
node *next; // the reference to the next node
};
node *head;
int printList(node *traverse) {
if (traverse->next == NULL) {
return -1;
}
traverse=traverse->next;
printList(traverse);
cout << traverse->data << endl;
return 0;
}
int main() {
node *temp = NULL;
node *begin = NULL;
for (int i = 0; i < 10; i++) {
temp = new node;
temp->data = i;
if (begin == NULL) {
begin = temp;
}
if (head != NULL) {
head->next = temp;
}
head = temp;
head->next = NULL;
}
head = begin;
printList(head);
return 0;
}
1) How can I print 0(the first element) with the printList() recursive function?
2) How can I replace printList() recursive function with while loop?
3) If asked in an interview, does the main() function has proper node initialisation and insertation?

They are four possible ways to achieve this, each of which having its own merits.
Recursion
void print_list(node* traverse)
{
if (traverse == NULL) return;
print_list(traverse->next);
std::cout << traverse->data << std::endl;
}
This is maybe the first answer to come in mind. However, the process stack size is limited, so recursion has a pretty low limit. A big list will provoke a stack overflow. This is not a very good design in C++.
Iteration
void print_list(node *n)
{
using namespace std;
deque<node*> res;
for(;n != NULL; n = n->next) res.push_back(n);
for_each(res.rbegin(), res.rend(), [](node* n){cout << n->data << endl;});
}
Of course, if you want to make it the iterative way, you will need to stack the node pointers yourself (on the process heap) and not delegate this job to the call stack. This method lets you print far bigger lists, and is O(n) in computations. It is, however O(n) in memory usage, but you already have a list which use O(n) memory. So this should not be an issue. However, you may really need to avoid memory consumption. Which brings us to the next idea.
Double iteration
void print_list(node *head)
{
node* last = NULL;
while(last != head)
{
node* current = head;
while(current->next != last)
current = current->next;
std::cout << current->data << std::endl;
last = current;
}
}
This may seem a dumb solution, as it has O(n^2) complexity, but that is computation-complexity. It has O(1) memory complexity and, depending on the actual context and exact problem, it may be the answer you need. But this O(n^2) complexity is a lot to pay. Especially if n is so big you wanted to avoid another O(n) allocation. Which brings us to the last idea.
Hack the container
void print_list(node *head)
{
node* last = NULL;
for(node* next; head != NULL; head = next)
{
next = head->next;
head->next = last;
last = head;
}
for(node* next; last != NULL; last = next)
{
next = last->next;
last->next = head;
head = last;
cout << last->data << endl;
}
}
You first modify the container, then iterate in your new order. On a single-linked list, you can just reverse the links, then reverse-iterate while reversing the links again. The beauty of it is it stays O(n) in computing, and O(1) in memory. The problem is that you invalidate the full container while doing this : your outputing operation does not leave the list constant : this is not exception-safe: if your operation fails in middle of iteration, the list is not valid anymore. This may or may not be an issue depending on the problem.

There's an old trick for traversing the list in reverse with a while loop.
You walk the loop in the forward direction, but as you leave each node, you reverse the link -- i.e., you get its current value (the pointer to the next node), but then set it so it contains a pointer to the previous node. When you reach the end of the list, you now have a singly-linked list that goes the opposite direction -- i.e., following the pointers will take you back to the beginning of the list.
So then you walk back to the beginning, printing each node's value out as you go, and (again) reversing the links so when you're done, the list is as it started, with links going from beginning to end.
Note, however, that this can lead to problems in (for one obvious example) multi-threaded code. The entire traversal of the list from beginning to end and back to the beginning has to be treated as a single, atomic operation -- if two threads try to traverse the list simultaneously, very bad things will happen. Likewise, making this exception-safe can be somewhat challenging as well.
IOW, these are rarely effective solutions to real problems (but the same is generally true of linked lists in general). They are, however, effective ways of showing an interviewer that you can play stupid linked-list tricks.

If your list is [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
1) You want to output the list reversed, your printList should look like this:
int printList(node* traverse)
{
if (!traverse)
return (-1);
printList(traverse->next);
std::cout << traverse->data << std::endl;
return (0);
}
2) It is not really possible with a while loop, unless you do really ugly things like concatenating every node's data to the beginning of the result string that you will print.
3) Your main seems very strange to me. I don't understand why your 'head' variable is global, why not in the main itself?
Last but not least, why don't using std::list?

I was asked a question containing this in the interview. It was intended to traverse the single list from both ends simultaneously. So reversing the single list was not an option. Also, memory space complexity should be O(1). I try to solve with nested loops with O(n^2) time complexity. However, more effective way is to use XOR linked list which was mentioned by #chuckcottrill and #jerry-coffin. Single list can be converted to XOR linked list by applying xor operation to prev and next pointers of node. XOR linked list based on the following property of XOR operation.
a^a^b = b (order of left side is not important)
Let's consider a node in single list and its neighboring nodes:
X: address of prev node , Y: address of next node
While converting to XOR list Y' = X^Y (Y': new value of Y)
While reverse traversing on XOR list Y^(Y') =Y^Y^X=X
So we can attain prev node (X) and do reverse traversal. The following code converts the single list to XOR linked list and does reverse traversal (forward traversal is also possible at the same time):
node* curr = head;
node* prev = NULL;
node* next= curr->next;
while (curr) {
next = curr->next;
// apply xor to prev and next
curr->next = (node*)((uintptr_t)(prev)^(uintptr_t)(next));
// move pointers forward
prev = curr;
curr = next;
}
// prev becomes tail node
// -- Reverse Traversal --
curr = prev ; // curr points to tail
prev = NULL;
node* temp;
while (curr) {
cout << curr->data << " ";
temp = curr;
// apply xor to prev and next
curr = (node*)((uintptr_t)(prev)^(uintptr_t)(curr->next));
prev = temp;
}

Please correct me if I am wrong.
This solution uses an Iterative approach. An extra "previous" pointer is used to maintain the node that will eventually follow the node in the reverse order of the list.
public static Nodes reverse(Nodes head){
Nodes temp;
Nodes previous=null;
while(head!=null)
{
temp=head.next;
head.next=previous;
previous=head;
head=temp;
}
return previous;
}

1) Change
if (traverse->next == NULL)
to
if (traverse == NULL)
2)
while(traverse != NULL) {
// print sth
traverse = traverse->next;
}
3) seems ok to me. Why do you declare head outside of main?

traverse->next = traverse;
A possible solution you could use. Another possibility,
traverse = (traverse->next)- (traverse);
but you must error check for over/underflow.

Related

linked list, where is my logic flawed? [closed]

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 5 years ago.
Improve this question
so I have of course, looked through a lot of linked list help and all but i can't seem to figure out what is going wrong with mine. I think I understand the logic of other codes, but something is up with mine and I can't get it to work properly.
Code of the function:
void SparseM_list::newTerm(valueType newValue, int row, int column)
MatrixTerm *n = new MatrixTerm;
n->next = NULL;
n->column = column;
n->row = row;
n->value = newValue;
if (head != NULL)
{
cur = head;
while (cur->next != NULL)
{
cur = cur->next;
cout << "does it ever get inside the while loop? cur and curnext -> " << cur << " " << cur->next << endl; <-- never outputs
}
cur->next = n;
}
else //if head is null, n will be the starting point
{
head = n;
}
delete n;
}
and below is the private struct/variables of my sparse matrix using linked list
struct MatrixTerm {
valueType value; //store value of matrix element
int column; //store column position
int row; //store row position
MatrixTerm *next; //point to next node in the linked list
};
MatrixTerm *head; //head point for the linked list
MatrixTerm *cur, *prev;
So basically my logic is this
New term information is dynamically allocated to Matrix Term n.
If the head is null (which is set by the default constructor), then head = n
2nd set of data goes in. head != Null, so I set cur pointer equal to the head
the while loop is skipped for the 2nd data, because head->next should be null and so cur->next should be null. I set the cur->next equal to n
3rd data goes in. Cur->next has n from the previous, so it enters the while loop. Current is set to be cur->next. It checks the while loop condition, and this time, cur->next should be null, so it goes to setting cur->next = n (3rd data set).
However, it never enters the while loop. Where am I messing things up? the while loop is used to traverse through the linked list.
This statement
delete n;
does not make sense. Remove it.
I hope that initially the data member head indeed is set to NULL (or nullptr).
An alternative implementation of the function can look like
void SparseM_list::newTerm(valueType newValue, int row, int column)
{
MatrixTerm *n = new MatrixTerm { newValue, column, row, nullptr };
MatrixTerm **current = &head;
while ( *current ) current = &( *current )->next;
*current = n;
}
If the list allows to append new nodes it would be helpful to declare also one more data member tail. In this case a new node will be added to the tail that is more efficient then each time to execute the loop.
Also think about to remove data members cur and prev and use them as local variables of the methods.
You should not delete n;, because it will release the memory of your list nodes. You see, you keep push your key into a lock but before open the door you pull out the key...Can you come into the house?
ps, delete the nodes should be held in the desturctor of the list object.

Improving the Performance for inserting elements into Linked List from an Array

I want to insert the elements of an array into Linked List. The following is the piece of code that I am using:
for (int i = 0; i<MAXSIZE; i++)
{
Node* n1 = new Node();
n1->SetData(randArray[i]);
n1->SetIndex(i);
n1->SetNext(NULL);
//checks if NULL
if (start == NULL) {
start = n1;
start->SetNext(NULL);
}
else {
//inserts the values to the end of the node
Node *p = start;
while (p->GetNext() != NULL) {
p = p->GetNext();
}
p->SetNext(n1);
}
}
Here randArray[i] consists the elements say 100000 elements.
Now I want this process to be executed faster. At present it is taking 13 seconds for 50000 elements.
Can someone help out in this?
You're now looking for the last node every time you insert a new node... but you would already know where the last node is because you just inserted it in the last iteration - if only you hadn't thrown that information away. Simply keep a pointer to it stored in a variable that isn't destroyed at the end of the iteration. Another way - which is a bit more typical for singly linked lists - is to only insert at the front of the list. If you want the elements in the same order as in the array, then iterate the array in reverse order.
Getting rid of the linear search for end reduces your algorithm's runtime complexity from O(n^2) to O(n).
Another optimization that will have less impact on performance, but will make your code simpler: Use the insert-in-front-only-approach and implement your list using a sentinel node. That way you don't need a branch in every iteration. That said, the branch probably has little effect due to being easily predictable. You can get rid of the branch with the remember-last-node approach too, by moving the test outside of loop, but that won't simplify your code.
EDIT: sentinel node is not needed after all, even though it does simplify some other list algorithms. I was bored, so I implemented the insert-in-front-only approach:
Node* head = nullptr;
for (size_t i = MAXSIZE; i --> 0;) {
Node* n = new Node();
n->SetData(randArray[i]);
n->SetIndex(i); // †
n->SetNext(head);
head = n;
}
† You may want to reconsider if you really want to store the index in a node. Updating it when nodes are later inserted or removed from anywhere else other than the tail is going to be quite slow.
Applying user2079303 advice,
You should have something like that:
Node *p = start;
for (int i = 0; i<MAXSIZE; i++)
{
Node* n1 = new Node();
n1->SetData(randArray[i]);
n1->SetIndex(i);
n1->SetNext(NULL);
//checks if NULL
if (start == NULL)
{
start = n1;
start->SetNext(NULL);
p = start;
}
else
{
//inserts the values to the end of the node
p->SetNext(n1);
p = p->GetNext();
}
}
This is example was done in case you want an actual append operation. The get and set functions prevent you from using a pointer to pointer, but this just requires one if statement to check for an empty list.
Node* tail; // pointer to last node on list (if start != NULL)
for (int i = 0; i<MAXSIZE; i++)
{
Node* n1 = new Node();
n1->SetData(randArray[i]);
n1->SetIndex(i);
//checks if empty list
if (start == NULL) {
start = n1;
tail = n1;
}
else {
tail->SetNext(n1);
tail = tail->GetNext();
}
}
tail->SetNext(NULL);
You do not need to iterate on linked list every time if you want to add at last position you just keep hold the reference of last node and it will add the node on its next. Like:-
Node* head ;
Node* last= null;
for (int i = 0; i < MAXSIZE; i++) {
Node* n1 = new Node();
n1->SetData(randArray[i]);
n1->SetIndex(i);
n1->SetNext(null);
if(last != null){
last->SetNext(n1);
}else{
head = n1;
}
last = n;
}

Traversing linked list and modifying or inserting node C++

I am attempting to write a function that will traverse a linked list, wherein the nodes represent terms of a polynomial. Each node includes fields for coefficient (a double named coeff), power (a size_t named power), and link (a NodePtr *next). The function is called with a double variable value, which represents the coefficient the node should have, and a size_t variable i, which represents its power. The function should traverse the linked list looking for the node with power i. If the list already contains a node with power i, its coefficient should be changed to hold the new value. If it did not previously have a node with power i, such a term should be added with the coefficient value. The list should be ordered by power (i.e. the node with power 3 should be the node 3 in the list).
Below is the code I have written thus far, though it currently generates the following error:
Unhandled exception at 0x0130D2FA in Project 3.exe: 0xC0000005: Access violation writing location 0x0000000C.
I cannot figure out why the error is generated, so that is my first issue. The second is that I believe my function may have some logical errors and does not correctly modify and create new nodes.
I have been stumped on this for days and cannot test my other functions without this having this one in working order, so any help would be greatly appreciated! Thank you!
void Poly::setCoeff(double value, size_t i)
{
if (0 <= i){
Node* prev = new Node();
Node* curr = new Node();
Node* newNode = new Node();
newNode->coeff = value;
newNode->power = i;
curr = myHead; // Initialize curr to myHead;
if (curr != nullptr)
{
while (curr->next != nullptr && curr->power != i)
{
prev = curr;
curr = curr->next;
}
if (curr->power == i)
{
curr->coeff = value;
}
else if (curr->next == nullptr && i == curr->power + 1)
{
curr->next = new Node; // Creates a node at the end of the list
curr = curr->next; // Points to that node
curr->next = nullptr; // Prevents it from going any further
curr->power = i;
curr->coeff = value;
}
else
{
prev->next = newNode;
newNode->next = curr;
}
}
else
{
curr->next = newNode;
curr = curr->next;
}
}
else
{
throw std::out_of_range("Index out of range");
}
}
It is a series of clear incorrect assumptions of how dynamic memory is managed in C++ that is getting you into heap-loads of trouble in this code. Were this not an academic exercise I would tell you simply to throw it all away and use:
std::map<size_t, double>
also known as: The Good Stuff. It would do literally everything you need this code to accomplish.
But this is academia. Like most things in academia they make you crawl through trenches before you learn how it should be. So, I will expose what is deficient in your code, but suffice it to say, once you learn all this you will strive not to have to do it in the first place by using tools already available to you.
In other words, unless someone said I had to do this with a hand-coded linked list implementation, I would use the above map instead. You can't (yet), but know it is there.
Your Code
You didn't include the definition of Node, but I can only assume it looks something like this:
struct Node
{
double coeff;
size_t power;
Node *next;
};
Whether this is nested within class Poly or not (and it likely should be if the latter) is likewise unclear. It isn't entirely relevant to the question, but mentioned here to attempt to drive home that, when asking a question on SO, provide enough info to minimize assumptions that may affect the answers your getting.
With that your code:
void Poly::setCoeff(double value, size_t i)
{
if (0 <= i) // NOTE: not needed, unsigned, will always be i >= 0
{
Node* prev = new Node(); // NOTE: wrong. leaks memory.
Node* curr = new Node(); // NOTE: same as above
Node* newNode = new Node(); // NOTE: **may** leak (see below)
newNode->coeff = value;
newNode->power = i;
curr = myHead;
if (curr != nullptr) // OK: check for null good
{
// NOTE: should be checking `curr`, not curr->next
while (curr->next != nullptr && curr->power != i)
{
prev = curr;
curr = curr->next;
}
// NOTE: should check curr for NULL first.
if (curr->power == i)
{
curr->coeff = value;
}
// NOTE: same here. also,
else if (curr->next == nullptr && i == curr->power + 1)
{
// NOTE: this code path will leak newNode allocated at the
// top of the function.
curr->next = new Node;
curr = curr->next;
curr->next = nullptr;
curr->power = i;
curr->coeff = value;
}
else
{
prev->next = newNode;
newNode->next = curr;
}
}
else
{ // NOTE: this is where your mainline fault is coming from. you
// just validated curr can be NULL here (and will be on initial)
curr->next = newNode;
curr = curr->next;
}
}
// NOTE: this can't happen, as i can never be less than zero
else
{
throw std::out_of_range("Index out of range");
}
}
The following are somewhat obvious.
Your memory management is not correct, and includes introducing memory leaks.
Your pointer management is likewise poor. Pointers are not like Java references, and nothing will get you in trouble faster in a C/C++ program than improper pointer management.
The algorithm doesn't maintain the mandate the list be ordered.
Changes to Your Code
The requirements for your code mandate an ordered list is maintained, yet your coefficient insertion algorithm makes no attempts at fulfilling that requirement. The setCoeff member is required to insert a new term if the matching exponent cannot be found, and if kept sorted, you'll know by proper enumeration whether that is the case by discovering (a) an exponent beyond yours, or (b) the end of the list, whichever happens first.
i is a size_t value, which means it is a magnitude for object counting. The standard mandates size_t is unsigned, which means it cannot be negative. This means checking for i >= 0 is useless. It will always be so.
A new node is allocated before know you need one. Remember, this is supposed to update an existing node if you find a matching exponent entry. Only if there were no match should a new node be required.
Your first-insert detection needs a complete redeux. It is guaranteed to invoke undefined behavior.
First make it easier on yourself. Provide a Node constructor that sets up a node via parameters so you can stop littering your code with that setup. In doing so, it becomes both easier to read and safer, since you initialize all member variables at construction.
struct Node
{
Node *next;
double coeff;
size_t power;
Node(double coeff_, size_t power_, Node *next_=nullptr)
: coeff(coeff_), power(power_), next(next_)
{}
};
With that, things will get considerably easier. The punch list above can be fulfilled with the following changes:
void Poly::setCoeff(double value, size_t i)
{
Node *prev = nullptr; // points to prior node
Node *curr = myHead; // points to current node
while (curr && curr->power < i)
{
prev = curr; // remember current node...
curr = curr->next; // ... then move to next node
}
// only allocate a new node if
// (a) we reached the end of the list (curr == NULL)
// (b) we reached a node with non match (will be larger exponent)
if (!curr || curr->power != i)
{
// **NOW** allocate the new node. we know we need one and we
// have a pretty solid idea where it goes.
Node *newNode = new Node(value, i, curr);
// if prev is set, then it means the new node goes somewhere
// *past* the head pointer otherwise it will become the new head.
if (prev)
prev->next = newNode;
else
myHead = newNode;
}
else
{ // found matching node
curr->coeff = value;
}
}
I sincerely hope it helps, and wish you the best of luck in trenching through the cruft before you get to The Good Stuff. Its worth it in the end.
I will follow up with the answer using a std::map (as WhozCraig's excellent answer mentions):
#include <map>
#include <iostream>
typedef std::map<size_t, double> Polynomial;
void AddCoefficientAndPower(Polynomial& poly, double coeff, size_t power)
{
// This does everything your assignment asked for, except for implementing
// all of that linked list stuff
poly[power] = coeff;
}
using namespace std;
int main()
{
Polynomial myPoly;
// add the coefficient and power
AddCoefficientAndPower(myPoly, 3, 1);
AddCoefficientAndPower(myPoly, 4, 2);
AddCoefficientAndPower(myPoly, 9, 0);
AddCoefficientAndPower(myPoly, 6, 3);
// This one will replace the previous (4,2)
AddCoefficientAndPower(myPoly, 3, 2);
// write out the coefficients followed by the power
Polynomial::iterator it = myPoly.begin();
while (it != myPoly.end())
{
cout << it->second << "^" << it->first << "\n";
++it;
}
}
Output:
9^0
3^1
3^2
6^3
Basically your entire assignment is a one line C++ statement in AddCoefficent that inserts an item in the map, and replaces an existing entry if one did exist.
Note -- no memory leaks, no calls to new, no crashes, etc.
Also, if your requirements were to also include any integral power value, then the above method works for negative, 0, and positive power values.

Finding a circle in a linked list with lookup table

I'm trying to find a circle in a linked list, and return the node at the beginning of the circle. For example, if the list was A -> B -> C -> D -> C -- we would return C
Here is my code:
ListNode<T> * findCircle()
{
map<ListNode<T>*, bool> addresses;
ListNode<T>* node = head;
if(addresses.find(node)->second)
cout << " wtf " << endl;
while(node)
{
if((addresses.find(node))->second)
{
return node;
}
else
addresses.insert(pair<ListNode<T>*,bool>(node, 1));
node = node->next;
}
return NULL;
}
I have a few questions:
1) is this the right way to approach the problem
2) am I using the most efficient ways to lookup/insert the keys and values into the table
3) why is it not working? When I check in the map for head, before I've inserted head, it still executes that if statement and prints "wtf". My algorithm is to insert the node as a key with a true value if it is not found in the map, otherwise return the node if the key is already in the map.
I tried doing this with std::set but it gave me trouble, so I switched to map. What baffles me is that the following code works (Code to remove duplicates in a linked list, using a lookup table) using exactly the same methodology.
void removeDuplicates()
{
map<T, bool> listData;
ListNode<T> *node;
ListNode<T> *prev = node;
for(node = head; node; node = node->next)
{
if(listData.find(node->data)->second)
{
prev->next = node->next;
delete node;
}
else
{
listData.insert( pair<T, bool>(node->data, 1));
}
prev = node;
}
}
Is it just a fluke that the second block of code does what it is supposed to, but the first does not?
You need to check if the find operation actually finds the data
auto iterator itr = address.find(node);
if(itr != address.end()){
if(itr->second == true){ cout << "WTF" << endl; }
}
similar for the while loop. As for your approach, I think it has the best runtime possible of O(n). All you can do is lower the constant.
addresses.find(node)->second
currently produces undefined behavior when the find() fails, because you're trying to access the second field of a past-the-end iterator. Instead, use
addresses.find(node) != addresses.end()
Also: is it important to find the exact place where a cycle (that's what it's usually called), or do you just want to see whether a cycle exists or not? If yes latter, then an extremely clever algorithm can solve the problem in linear time and constant space using just two pointers, one of which moves twice as fast as the other :)

How can I use iteration instead of recursion to input values into a linked list?

Ok so let's say we have a linked list of characters with a head pointer. How can I create a loop to enter a string of characters into the linked list? My problem is when I think of head and head->next and head->next->next . . . it only seems natural to use a recursive function to set the characters at each node.
It's trivial to do it with iteration. You would just start at head, and use a loop to iterate over the list by doing current = current->next, until you hit a NULL.
Basically something like:
node* n = head;
while (n) {
// ... do something with n
n = n->next;
}
As you are using C++, then using std::list and an iterator would seem to be the way to go. Writing your own linked list is OK as a learning exercise, but please don't use such a thing in real code.
Assuming your linked list already has enough space in it:
node *n = head;
char *input = "hello list";
int len = strlen(input);
for (int i=0;i<len;i++)
{
n->data = input[i];
n=n->next;
}
Otherwise you need to check each time for a null value before adding the data:
node *n = head;
char *input = "hello list";
int len = strlen(input);
for (int i=0;i<len;i++)
{
if !(n)
{
break;
}
n->data = input[i];
n=n->next;
}
Another solution would involve adding a new element when you hit the end:
node *n = head;
char *input = "hello list";
int len = strlen(input);
for (int i=0;i<len;i++)
{
n->data = input[i];
if (!n->next && i < len-1)
{
n->next = new Node;
}
n = n->next;
}
First, it depends on whether it's a doubly-linked list, or a singly linked list -- but it sounds like you're dealing with a singly-linked list.
With a singly linked list it's easiest to add nodes to the beginning of the list. If that works for you, something like:
node *head; // head of the list
// insert node:
new_node->next = head;
head = new_node;
If you want to add to the end of the list, you walk through the list first:
// If the list is empty, just add the node at the head:
if (head == NULL) {
new_node->next = head;
head = new_node;
}
else {
// There's already data in the list, so walk to the end of the list:
node *pos;
for (pos=head; pos->next!=NULL; pos=pos->next)
;
new_node->next = NULL;
pos->next = new_node;
}
As a general rule, neither of these makes a lot of sense though. It's only really sensible to use a linked list when you plan on doing insertions and deletions somewhere in the middle of the list, and you normally save the position (i.e. a pointer to) where you're going to do the insertion or deletion.