Randomly shuffling a linked list - c++

I'm currently working on a project and the last piece of functionality I have to write is to shuffle a linked list using the rand function.
I'm very confused on how it works.
Could someone clarify on how exactly I could implement this?
I've looked at my past code examples and what I did to shuffle an array but the arrays and linked lists are pretty different.
Edit:
For further clarifications my Professor is making us shuffle using a linked list because he is 'awesome' like that.

You can always add another level of indirection... ;)
(see Fundamental theorem of software engineering in Wikipedia)
Just create an array of pointers, sized to the list's length, unlink items from the list and put their pointers to the array, then shuffle the array and re-construct the list.
EDIT
If you must use lists you might use an approach similar to merge-sort:
split the list into halves,
shuffle both sublists recursively,
merge them, picking randomly next item from one or the other sublist.

I don't know if it gives a reasonable random distribution :D
bool randcomp(int, int)
{
return (rand()%2) != 0;
}
mylist.sort(randcomp);

You can try iterate over list several times and swap adjacent nodes with certain probablity. Something like this:
const float swapchance = 0.25;
const int itercount = 100;
struct node
{
int val;
node *next;
};
node *fisrt;
{ // Creating example list
node *ptr = 0;
for (int i = 0; i < 20; i++)
{
node *tmp = new node;
tmp.val = i;
tmp.next = ptr;
ptr = tmp;
}
}
// Shuffling
for (int i = 0; i < itercount; i++)
{
node *ptr = first;
node *prev = 0;
while (ptr && ptr->next)
{
if (std::rand() % 1000 / 1000.0 < swapchance)
{
prev->next = ptr->next;
node *t = ptr->next->next;
ptr->next->next = ptr;
ptr->next = t;
}
prev = ptr;
ptr = ptr->next;
}
}

The big difference between an array and a linked list is that when you use an array you can directly access a given element using pointer arithmetic which is how the operator[] works.
That however does not preclude you writing your own operator[] or similar where you walk the list and count out the nth element of the list. Once you got this far, removing the element and placing it into a new list is quite simple.
The big difference is where the complexity is O(n) for an array it becomes O(n^2) for a linked list.

Related

why do we use pos in c++? assume by my code int pos = cHash(symbol);

so I was doing a program of SymbolTable for my compiler course ....I landed with a problem of pos ...why do we use it on the first place? TIA <3
void insert(char *symbol, char *type)
{
int pos = cHash(symbol);
if (block[pos] == NULL)
{
block[pos] = new SymbolInfo();
block[pos]->symbol = symbol;
block[pos]->type = type;
block[pos]->next = NULL;
}
else
{
SymbolInfo *newNode = new SymbolInfo();
newNode->symbol = symbol;
newNode->type = type;
// pointer swap
SymbolInfo *nextNode = block[pos];
block[pos] = newNode;
newNode->next = nextNode;
}
}
The code here implements what’s called a chained hash table. We maintain an array of linked lists, and use the function cHash to assign each symbol to one of those linked lists.
The advantage of storing things this way is speed. If we put everything into a single linked list, then the average cost of looking something up is O(n), where n is the number of items in the list, since on average we have to look at at least half the items in the list. But by having multiple linked lists (say, b of them) and distributing items across them more or less randomly, we decrease the average cost of a lookup to O(1 + n/b), which is a lot faster if b is roughly the same order of magnitude as n.
If there is no element in the chain then new element is added in front,
otherwise through hashing if we reach a chain or, bucket that contains an element then we insert the new element at the beginning of the chain and
the rest of the elements is linked to the end of new node.

Sort struct that contains pointer to the next

so I have something like:
struct Something
{
int number;
Something* next;
};
And I want to sort them, by the number, though I don't want to change the number, but I want to change the pointer to the next.
How would I do that?
I know the end and the beginning of the "list", (FIFO order)
Use MergeSort for linked lists: first traverse the list with two running pointers, one of them advancing twice slower. When you reach the end of the list, the slow pointer points to the middle. Split the list and sort the halves recursively, then Merge.
There are various sorting algorithms (http://www.sorting-algorithms.com/), and by far, I would use the random|selection one for this example. It will look something like:
void Something::SortAscending() {
Something* current = next;
Something* smallest = next;
while( current ) {
if( current->number < smallest->number ) {
smallest = current;
}
current = current->next;
}
if( smallest != next )
smallest->next = next;
next = smallest;
next->SortAscending();
}
Note, however, that if you're given the head of the list, you may not change it with the type of function I provided above.
Sort -> for each element of sorted array update next pointer

Get smallest value from a linked list?

I am currently writing a piece of code which loops through a linked list and retrieves the smallest, but is not working. Instead it seems to be returning the last value I enter into the list...
(list is the head being passed from main)
int i = 0;
Stock *node = list;
int tempSmallest = (list + 0)->itemStock;
while (node!=NULL)
{
if ((list+i)->itemStock < tempSmallest)
{
tempSmallest = node->itemStock;
node = node->nodeptr;
}
i++;
}
return list;
Thanks for any advice!
You are dereferencing (list+i) and incrementing i with every visited node for some reason. I don't know why you're doing this, but it's wrong. You basically traverse the linked list and also conceptually traverse an array (which doesn't exist at all). This is undefined behavior and cannot give meaningful results.
You must dereferece the currently valid node, not an array element that is a few indices after it somewhere in RAM, and advance by the list's next node pointer (I assume this is called nodeptr in your code?).
Something like...
Stock *node = list; // hopefully not NULL since I don't check in the next line
int smallest = node->itemStock;
while(node && node = node->nodeptr)
smallest = std::min(smallest, node->itemStock);
return smallest;
struct stock{
stock *next;
...
};
this will be the struct of your nodes.
then when you initialize them, you should refer the next pointer of the last node added, to the node you're adding currently.
then the code will be like this:
stock *node = head; // the head you passed from main
int min = node->price;
for(;node;node=node->next)
{
if(node->price < min)
min = node->price;
if(!node->next)
break();
}
return min;

How do i make a link list print out its contents in alphabetical order?

I have a single linked phonebook list with last names, first names, and values.
I am able to print them out in the order they were created, but not by value. How can i modify this? If you need to see anything else in the code let me know, but this function is my main concern.
ostream& operator<<(ostream& out, const PhoneBook& p) // out stream
{
if(p.head==NULL)
{
cout << "is empty";
}else
{
PhoneBookItem* item = p.head;
for(int i=0; i < p.num; i++)
{
cout << item->lastname<< " ";
cout << item->firstname<< " : ";
cout << item->phone<<endl;
item = item->next;
}
}
return out;
Option 1: Sort the list, then print
Option 2: For every loop, search which item should be printed next. (Expensive)
Option 3: Use Hash/Dictionary approach instead of linked-list. Hash/Dictionary is
combination of fixed array and link list. They are good for
searching items faster than fixed array and linked-list.
Option 4: Use other data structure other than link list that has ability to access your data in order/alphabetically.
Sorting a linked list can be done in several ways.
Temporary reference array: Allocate a temporary array or vector of pointers and traverse the linked list to fill it. Sort the pointers. Library std::sort or qsort is fine for this. Then traverse the sorted array to reset the "next" pointer of each node. Finally release the temporary array storage.
Insertion sort: Pop elements off the list and re-insert in a new list at the correct sorted location.
Mergesort: It's not too hard to implement, and this runs much faster on long lists than insertion sort. The algorithm is simple: Split the list in 2. Mergsort the halves recursively. Then merge the results by repeatedly removing the smallest head and appending to the tail of a new list.
Quicksort: This is a bit tricky to implement efficiently with lists, but it is possible. I won't discuss it because it's not a good early programming project, and mergesort is faster in many cases.
Here is some untested code for insertion sort:
PhoneBookItem* sorted = NULL;
while (p.head) {
// Pop
PhoneBookItem* head = p.head;
p.head = head->next;
head->next = NULL;
// Find the place to insert.
PhoneBookItem* lead = sorted;
PhoneBookItem* trail = NULL;
while (lead && lead->phone <= head->phone) {
trail = lead;
lead = lead->next;
}
// Insert either within the list or at the head.
head->next = lead;
if (trail)
trail->next = head;
else
sorted = head;
}
p.head = sorted;
// Now print the sorted list as before...

Deep Copy Linked List - O(n)

I'm trying to deep copy a linked list . I need an algorithm that executes in Linear Time O(n). This is what i have for now , but i'm not able to figure out what's going wrong with it. My application crashes and i'm suspecting a memory leak that i've not been able to figure out yet. This is what i have right now
struct node {
struct node *next;
struct node *ref;
};
struct node *copy(struct node *root) {
struct node *i, *j, *new_root = NULL;
for (i = root, j = NULL; i; j = i, i = i->next) {
struct node *new_node;
if (!new_node)
{
abort();
}
if (j)
{
j->next = new_node;
}
else
{
new_root = new_node;
}
new_node->ref = i->ref;
i->ref = new_node;
}
if (j)
{
j->next = NULL;
}
for (i = root, j = new_root; i; i = i->next, j = j->next)
j->ref =i->next->ref;
return new_root;
}
Can anyone point out where i'm going wrong with this ??
This piece alone:
struct node *new_node;
if (!new_node)
{
abort();
}
Seems good for a random abort() happening. new_node is not assigned and will contain a random value. The !new_node expression could already be fatal (on some systems).
As a general hint, you should only require 1 for-loop. Some code upfront to establish the new_root.
But atruly deep copy would also require cloning whatever ref is pointing to. It seems to me the second loop assigns something from the original into the copy. But I'm not sure, what is ref ?
One thing I immediately noticed was that you never allocate space for new_node. Since auto variables are not guaranteed to be initialized, new_node will be set to whatever value was in that memory before. You should probably start with something like:
struct node *new_node = (new_node *) malloc(sizeof(struct node));
in C, or if you're using C++:
node* new_node = new node;
Copying the list is simple enough to do. However, the requirement that the ref pointers point to the same nodes in the new list relative to the source list is going to be difficult to do in any sort of efficient manner. First, you need some way to identify which node relative to the source list they point to. You could put some kind of identifier in each node, say an int which is set to 0 in the first node, 1 in the second, etc. Then after you've copied the list you could make another pass over the list to set up the ref pointers. The problem with this approach (other that adding another variable to each node) is that it will make the time complexity of the algorithm jump from O(n) to O(n^2).
This is possible, but it takes some work. I'll assume C++, and omit the struct keyword in struct node.
You will need to do some bookkeeping to keep track of the "ref" pointers. Here, I'm converting them to numerical indices into the original list and then back to pointers into the new list.
node *copy_list(node const *head)
{
// maps "ref" pointers in old list to indices
std::map<node const *, size_t> ptr_index;
// maps indices into new list to pointers
std::map<size_t, node *> index_ptr;
size_t length = 0;
node *curn; // ptr into new list
node const *curo; // ptr into old list
node *copy = NULL;
for (curo = head; curo != NULL; curo = curo->next) {
ptr_index[curo] = length;
length++;
// construct copy, disregarding ref for now
curn = new node;
curn->next = copy;
copy = curn;
}
curn = copy;
for (size_t i=0; i < length; i++, curn = curn->next)
index_ptr[i] = curn;
// set ref pointers in copy
for (curo = head, curn = copy; curo != NULL; ) {
curn->ref = index_ptr[ptr_index[curo->ref]];
curo = curo->next;
curn = curn->next;
}
return copy;
}
This algorithm runs in O(n lg n) because it stores all n list elements in an std::map, which has O(lg n) insert and retrieval complexity. It can be made linear by using a hash table instead.
NOTE: not tested, may contain bugs.