What is the time complexity of the first function? - c

static void ListInsert(List l, int value);
List findShortestSublist(List l, int start, int end) {
Node curr = l -> first;
Node startNode = NULL;
List shortest = ListNew();
while (curr != NULL) {
if (curr -> value == start) {
startNode = curr;
}
if (curr -> value == end) {
if (startNode != NULL) {
Node curr2 = startNode;
while (curr2 != curr) {
ListInsert(shortest, curr2 -> value);
curr2 = curr2 -> next;
}
ListInsert(shortest, curr -> value);
return shortest;
}
}
curr = curr -> next;
}
return shortest;
}
static void ListInsert(List l, int value) {
// Inserting List function that was used.
Node n = newNode(value);
if (l -> first == NULL) {
l -> first = n;
l -> last = n;
} else {
l -> last -> next = n;
l -> last = n;
}
}
Struggling to figure out the time complexity of findShortestSublist() I feel like it is a O(n^2) because it is a nested loop but it could also be O(n). The purpose of this function is to find the shortest sublist from a linked list.

The O complexity of your function is O(2n) because in the worst case you will browse your list twice.
One time to find the end node and one more time to insert the item.
NOTE: it would have been O(n^2) in the case you had browsed the whole list for each items in the main list. But this is not the case here ..

Related

My function to merge two linked lists is not working properly

I'm supposed to make a function that will merge two sorted singly linked lists.
The user inputs two sets of numbers in the console, for example: 5 3 1 0, which make a linked list, 0 signifies the end of that input and is not a part of that list. Then the lists are sorted, from the smallest to the largest value. After the sorting, elements of the lists are supposed to be added into a new list, one by one. At the end, the newly created list should be printed.
I've tried with a lot of different methods, but the one I liked the most was to have two different pointers to the heads, so p would be a pointer for head1 and q would be a pointer for head2. I start with whichever head value is smaller and move the pointer of that head to the next element. Then I remember that head with the node I'm going to return at the end, and move onto the while loop, where it goes from one list to another.
Okay, I use S to add the elements to my new list, first I start from the lower number between thew two lists, which is in this case 1 and the first list, as soon as I give S its value, I also move pointer p0 to the next element, so now its pointing to 3 (p1). Then I make that S the head of my new list and move onto the while loop. In while loop I check if the last element that was added to my new list was from the first or the second list, depending on the result, let's just say the last element was from the first list (number 1), we move onto the second list. I make S point to q1, q then points to the next element of the second list (q2) and the while loop starts again. The process repeats itself until one of the two pointers is NULL. After the while loop, I have two if statements (one for each pointers in case they point to NULL) where I return the other pointer. Hopefully now it's a bit more clear.
typedef struct Element Element;
struct Element {
int data;
Element *next;
};
Element *addNew(int data) {
Element *newN = (Element*)malloc(sizeof(Element));
newN->data = data;
newN->next = NULL;
return newN;
}
Element *add_on_beginning(Element *head, Element *newN) {
newN->next = head;
return newN;
}
Element *add_on_end(Element *head, Element *newN) {
if (head == NULL) {
return newN;
}
Element *temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newN;
return head;
}
void swap(Element *a, Element *b) {
int tempV;
tempV = a->data;
a->data = b->data;
b->data = tempV;
}
void sortList(Element *head) {
Element *temp;
int swapped;
do {
swapped = 0;
temp = head;
while (temp->next != NULL) {
if (temp->data > temp->next->data) {
swap(temp, temp->next);
swapped = 1;
}
temp = temp->next;
}
} while(swapped);
}
Element *merge(Element *head1, Element *head2, Element *newHead) {
Element *p = head1;
Element *q = head2;
Element *sort = NULL;
if (p == NULL) {
return q;
}
if (q == NULL) {
return p;
}
if (p != NULL && q != NULL) {
if (p->data <= q->data) {
sort = p;
p = sort->next;
} else {
sort = q;
q = sort->next;
}
}
newHead = sort;
while (p != NULL && q != NULL) {
if (sort->next == p->next) {
sort->next = q;
sort = q;
q = sort->next;
} else {
sort->next = p;
sort = p;
p = sort->next;
}
}
if (p == NULL) {
sort->next = q;
}
if (q == NULL) {
sort->next = p;
}
return newHead;
}
void printElement(Element *element) {
printf("%d ", element->data);
}
void printList(Element *head) {
Element *temp = head;
while (temp != NULL) {
printElement(temp);
temp = temp->next;
}
}
int main() {
Element *head = NULL;
Element *head2 = NULL;
Element *head3 = NULL;
char t;
int i;
char p;
int j;
printf("Input the first set of numbers: \n");
while (t != '\n') {
scanf("%d%c", &i, &t);
if (i == 0) {
break;
}
head = add_on_end(head, addNew(i));
}
printf("Input the second set of numbers: \n");
while (p != '\n') {
scanf("%d%c", &j, &p);
if (j == 0) {
break;
}
head2 = add_on_end(head2, addNew(j));
}
sortList(head);
sortList(head2);
head3 = merge(head, head2, head3);
printList(head3);
return 0;
}
The problem I'm having is with merging, it prints out those two lists sorted but not merged with one and other, instead its the first list and right after the second.
So for example:
INPUT:
2 6 4 8 1
7 9 2 3 5
OUTPUT:
1 2 4 6 8 2 3 5 7 9
It should be:
INPUT:
2 6 4 8 1
7 9 2 3 5
OUTPUT:
1 2 2 3 4 5 6 7 8 9
The merge function is too complicated:
the test if (p != NULL && q != NULL) is redundant
in the while loop you do not test the node values, which explains why merge fails.
the third argument newHead is useless.
Here is a modified version:
Element *merge(Element *p, Element *q) {
Element *newHead = NULL;
Element *sort = NULL;
if (p == NULL) {
return q;
}
if (q == NULL) {
return p;
}
if (p->data <= q->data) {
newHead = sort = p;
p = p->next;
} else {
newHead = sort = q;
q = q->next;
}
while (p != NULL && q != NULL) {
if (p->data <= q->data) {
sort = sort->next = p;
p = p->next;
} else {
sort = sort->next = q;
q = q->next;
}
}
if (p == NULL) {
sort->next = q;
}
if (q == NULL) {
sort->next = p;
}
return newHead;
}
Most of the added complexity in OP's code is caused by the need to handle the edge-cases(finding the address of the new head) Edge cases can sometimes be avoided.
Trivial solution using a pointer-to-pointer:
struct thing{
struct thing *next;
int value;
};
struct thing *merge(struct thing *one, struct thing *two)
{
struct thing *result;
struct thing **pp; // will always point to the _pointer_ that will be assigned the next node.
result=NULL;
for(pp = &result; one && two; pp = &(*pp)->next) {
if(one->value <= two->value) {
*pp = one; one = one->next;
}
else {
*pp = two; two = two->next;
}
}
// When we get here, one and/or two will be NULL
*pp = (one) ? one : two;
return result;
}
The same logic, but with an extra dereference instead of the pointer-to-pointer:
struct thing *merge2(struct thing *one, struct thing *two)
{
struct thing dummy;
struct thing *last;
dummy.next=NULL;
for(last = &dummy; one && two; last = last->next) {
if(one->value <= two->value) {
last->next = one; one = one->next;
}
else {
last->next = two; two = two->next;
}
}
last->next = (one) ? one : two;
return dummy.next;
}
Now, the fun fact is,that cc -Wall -omit-frame-pointer -O3 -S llist23.c generates exactly the same code for these two functions.

How to create and sort a singly linked list in runtime?

I am trying to create a linked list from reading a text file and output the words read and their count in an ascending order.
Everything is fine except trying to order nodes in runtime.
First I have tried like bubble sort but I cant wrap my head around the logic at the beginning part of the linked list.
Second I have tried to keep comparing x->next's count until I found one that's bigger than the one I wanted to push back. Then I swap them. I used many pointers but it works sometimes but failed at some edge cases.
I should've saved some of the code to let people point out the flaw of my logic but I was little bit frustrated just trying to start over from scratch.
Can someone provide some good logic or explicit pseudo? Thank you very much
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define MAX 999
typedef struct Node
{
char *name;
int count;
struct Node *next;
}node;
void insert(node **,char *);
void freeNode(node **);
int main()
{
char str[MAX];
node *head = NULL;
while(getword(str,MAX))
{
insert(&head,str);
}
print(head);
free(head);
return 0;
}
void insert(node **head,char *str)
{
node *mid = *head;
node *left = NULL, *right = NULL;
while(mid)
{
if(strcmp(mid->name,str) == 0)
{
++(mid->count);
node *temp = left;
while(mid->count > right->count)
{
//printf("in %s %s %s\n",left->name,mid->name, right->name);
left->next = mid->next;
mid->next = right->next;
right->next = mid;
left = left->next;
if(mid->next != NULL) right = mid->next;
if(left == mid) break;
//printf("in %s %s %s\n\n",left->name,mid->name, right->name);
// sleep(3);
}
return;
}
left = mid;
mid = mid->next;
if(mid != NULL) right = mid->next;
}
node *newnode = (node *) malloc(sizeof(node));
newnode->name = (char *) malloc(MAX * sizeof(char));
strcpy(newnode->name,str);
newnode->count = 1;
newnode->next = *head;
*head = newnode;
}
void freeNodes(node **head)
{
node *temp;
while(*head)
{
temp = (*head)->next;
free(*head);
(*head) = NULL;
(*head) = temp;
}
}
I just worked on a few edge case. I make sure when first node get repeated will be make sure to move down by one
node *mid = *head;
node *left = NULL, *right = NULL;
while(mid)
{
if(strcmp(mid->name,str) == 0)
{
++(mid->count);
if(mid->next == NULL) return;
node *temp = left;
if(left == NULL)
{
left = mid->next;
mid->next = left->next;
left->next = mid;
*head = left;
right = mid->next;
}
while(mid->count > right->count)
{
left->next = mid->next;
mid->next = right->next;
right->next = mid;
left = left->next;
if(mid->next != NULL) right = mid->next;
if(left == mid) break;
//printf("in %s %s %s\n\n",left->name,mid->name, right->name);
// sleep(3);
}
return;
}
left = mid;
mid = mid->next;
if(mid != NULL) right = mid->next;
}
Google merge-sort. IMHO it is the best algorithm for sorting singly connected lists.
Start with a list nodes:
node3 -> node7 -> node1 -> node20 -> node11 -> node13 -> NULL
Each subslist of length 1 is (trivially) sorted:
{ node3 } is sorted
{ node7 } is sorted
Then merge two consecutive sublists of length 1 into sublists of length 2:
node3 -> node7 -> node20 -> node1 -> node11 -> node13 -> node007 -> NULL
into
{node3 -> node7}->{node1 -> node20}->{node11 -> node13}->{node007} -> NULL
node007 is considered equal to node7.
Then merge two consecutive sublists of length 2 into subslists of length 4:
{node3 -> node7}->{node1 -> node20}->{node11 -> node13}->{node007} -> NULL
merge(node3, node1, 2):
returns {node1 -> node3 -> node7 ->node20}
merge(node11, node007, 2):
returns {node007 -> node11 -> node13}
So you get two sorted sublists of length 4:
{node1 -> node3 -> node7 ->node20}->{node007 -> node11 -> node13}->NULL
merge(node1,node007,4):
returns
{node1 -> node3 -> node7 -> node007 -> node11 -> node13 -> ode20}->NULL
So the length always doubles, and you are finished when it is equal or greater than the length of the entire list.
The merge alway compares the first element of each list and pops the smaller one from the list and appends it to the result tail:
merge(n1 = {node3 -> node7}->t1 , n2 = {node1 -> node20}-> t2 , 2):
does
count1 = count2 = 2;
result = NULL;
as node1 < node3 : result = { node1 }-> NULL;
n2 = { node20 } -> t2;
count2 = 1;
as node3 < node20 : result = {node1 -> node3}-> NULL;
n1 = {node7}->t1;
count1 = 1;
as node7 < node20 : result = {node1 -> node3-> node7 }-> NULL;
n1 = t1;
count1 = 0; (merge finished);
as count2 != 0 : result = {node1 -> node3-> node7 -> node20 } -> NULL.
This ia all pseudo code that should give you an idea.

Reversing a linked list using nested while loops

I need some help.
I have this homework assignment due on Wednesday and the only thing I haven't been able to do is reverse my linked list. I have literally been working on this all day.
My professor hasn't told us any way to do this and doesn't allow us to email him questions so I'm kind of stuck.
He wants us to accomplish this by using nested while loops and pointers called front & back, and newhead.
Below is my code. Let me know if you have any questions and thanks in advance.
NOTE: Code is compiled in Code::Blocks using the GNU compiler.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int random_number;
struct node *next;
} Node;
typedef Node *Nodeptr;
void printout(Nodeptr);
void sum(Nodeptr);
void reverse(Nodeptr);
int main() {
Nodeptr head = NULL;
if ((head = malloc(sizeof(Node))) == NULL)
return 0;
head->random_number = rand() % 50 + 50;
head->next = NULL;
Nodeptr here = head;
Nodeptr newnode = NULL;
int n;
for (n = 0; n < 10; n++) {
if ((newnode = malloc(sizeof(Node))) == NULL)
return 0;
newnode->random_number = rand() % 50 + 50;
newnode->next = NULL;
here->next = newnode;
here = here->next;
}
printout(head);
sum(head);
reverse(&head);
printout(head);
return 0;
}
void printout(Nodeptr head) {
Nodeptr aux = head;
int n = 0;
while (aux != NULL) {
printf("The value of node no. %d is %d \n", n, aux->random_number);
aux = aux->next;
n++;
}
}
void sum(Nodeptr head) {
Nodeptr aux = head;
int n = 0, sum = 0;
while (aux != NULL) {
sum += aux->random_number;
aux = aux->next;
n++;
}
printf("The sum total of all nodes in this list is %d\n", sum);
}
void reverse(Nodeptr head) {
Nodeptr newhead = head;
Nodeptr back = NULL;
Nodeptr front = NULL;
while (back != NULL) {
front->next = back;
back = NULL;
front = head->next;
back = head;
while (front != NULL) {
front = newhead->next;
newhead->next = back;
back = newhead;
}
newhead = head;
}
}
If you reverse a linked list:
A -> B -> C -> D -> E (odd numbered case)
E -> D -> C -> B -> A
A -> B -> C -> D (even numbered case)
D -> C -> B -> A
Do you see how the items have changed place? In the odd numbered case, A swapped places with E, B with D and C didn't move.
Now do you have some idea how to do it via a loop? The outer loop goes from the start of the list to the half-way point, the inner loop locates the matching item to swap them.
Definitely not the most efficient way to reverse a linked list, but I guess it's just a way to get you think more about the data structure.
The reverse() you posted didn't make sense, because the pointer values are incorrect. With back initialized to NULL, the while loop will not execute at all.
I am not sure what API you teacher want you to use for reverse:
The simplest one would take a Node * and return the new head pointer. You would invoke it from main as head = reverse(head);
Here is a simple implementation of this approach:
Node *reverse(Node *head) {
Node *front = head;
Node *newhead = NULL;
while (front) {
Node *back = front->next;
front->next = newhead;
newhead = front;
front = back;
}
return newhead;
}
An alternative API would have reverse take a pointer to the head pointer, hence a Node **, and update that to point to the reversed list.
Here is how it works:
void reverse(Node **headp) {
Node *front = *headp;
Node *newhead = NULL;
while (front) {
Node *back = front->next;
front->next = newhead;
newhead = front;
front = back;
}
*headp = newhead;
}
Note that you do not need nested loops.
Note also that you should not hide pointers behind typedefs, it is bad practice, error prone and creates confusion for both the next reader and the original author.

Swap items in a doubly linked list

I am studying for my Algorithms exam and I have an exercise where I need to swap two items of a doubly linked list if a condition is true. (Language: C)
More specifically, I have a list of this kind:
H <-> |prev|Frequency1|VALUE1|next| <-> |prev|Frequency2|VALUE2|next| <-> ... <-> NULL
The frequency field increases every time I search for the relative value. The list must be ordered according to the frequency (in decreasing order, so at the very top there is the most searched item)
The problem is, I am not very good in exchanging pointers, I tried many times to do it but I have no clue. I guess that the problem I am facing is that I don't know how to use a temp item to keep track of what I am doing without loosing data.
I think that the case I have to consider are:
First item of the list
Last item of the list
Item is in the middle of the list.
My attempt, certainly wrong is:
int Search(int x, list* head) {
int contapos = 0;
list* i;
list* aus;
for (i=head; i!=NULL; i = i->next, contapos++)
{
if (i->key == x)
{
i->freq++; // Increase frequency
aus = i->prev;
while ((i->freq > aus->freq))
{ // Keep ordered the frequencies
if (i->next != NULL)
{
i->next->prev = aus;
}
if (aus->prev != NULL)
{
aus->prev->next = i;
}
aus->next = i->next;
i->prev = aus->prev;
aus->prev = i;
i->next = aus;
}
/* Return counter */
return contapos;
}
}
return -1; // In case the item i am searching is not there
}
Thank you in advance for everything!
Edit:
as requested, I am adding the main (and the whole code just to be sure) of the program at the moment
typedef struct _list {
int key;
int freq;
struct _list *next;
struct _list *prev;
} list;
list* head;
list* tail;
void swap(list *lhs, list *rhs) {
list *temp;
temp = lhs->prev;
lhs->prev = rhs->prev;
rhs->prev = temp;
temp = lhs->next;
lhs->next = rhs->next;
rhs->next = temp;
}
void InsertAtTail(int value) {
list *newNode;
newNode = (list*)malloc(sizeof(list));
newNode->key = value;
if(head == NULL)
{
head = newNode;
}
else
{
tail->next = newNode;
newNode->prev = tail;
}
tail = newNode;
tail->next = NULL;
}
int SearchAndIncrement(int x, list** head) {
int contapos = 0;
list* i;
// Let's find the element with the matching key
for (i = *head; i != NULL; i = i->next, contapos++)
if (i->key == x)
break;
// If we did not find the node, return -1 to denote failure.
if (i == NULL)
return -1;
// Increase frequency
i->freq++;
// Move this node forward while the frequency is not in the correct position.
while (i->next && i->prev && (i->freq > i->prev->freq))
swap(i, i->prev);
// The head might have been moved.
while ((*head)->prev != NULL)
(*head) = (*head)->prev;
// Return the original position
return contapos;
}
int main () {
int N;
scanf("%d", &N);
head = NULL;
tail = NULL;
int i, value;
for (i=0; i<N; i++) {
scanf("%d", &value);
InsertAtTail(value);
}
/* Initializing frequencies */
list* aus;
for (aus=head; aus; aus = aus ->next) {
aus->freq = 0;
}
int x, pos;
do {
scanf("%d", &x);
pos = SearchAndIncrement(x, &head);
printf("%d ", pos);
printf("[");
aus = head;
while (aus!=NULL) {
printf("%d ", aus->key);
aus = aus->next;
}
printf("]\n");
} while (pos != -1);
return 0;
}
Let's simplify the problem. The complicated pointer portion is when we are trying to move a node forward in the list. So let's create some functions just for that.
void RemoveNode(list *node) {
if (node->prev)
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
}
void InsertNodeBetween(list *lhs, list *node, list *rhs) {
if (lhs) assert(lhs->next == rhs);
if (rhs) assert(rhs->prev == lhs);
if (lhs) lhs->next = node;
if (rhs) rhs->prev = node;
node->prev = lhs;
node->next = rhs;
}
Once we've done that, then we can more easily talk about the operation that you want to do.
int SearchAndIncrement(int x, list** head) {
int contapos = 0;
list* i;
// Let's find the element with the matching key
for (i = *head; i != NULL; i = i->next, contapos++)
if (i->key == x)
break;
// If we did not find the node, return -1 to denote failure.
if (i == NULL)
return -1;
// Increase frequency
i->freq++;
// Move this node forward while the frequency is not in the correct position.
while (i->next && (i->freq > i->next->freq)) {
list *prev = i->next;
list *next = i->next->next;
RemoveNode(i);
InsertNodeBetween(prev, i, next);
}
// The head might have been moved.
while ((*head)->prev != NULL)
(*head) = (*head)->prev;
// Return the original position
return contapos;
}
Some commentary:
The important thing to note here is that we have the ability to create multiple functions. And we can use those functions to make the amount of the problem that we need to keep in our head at any one time smaller.

C - How do you call the first element in a linked list?

I am trying to get a linked list to sort, then be able to display it.
The problem with my code is, I can display it before sorting, but after sorting, it won't display, it will crash. I think it has to do with the "top" variable, because through debugging, it doesn't contain anything. How can I call the first element in the linked list and use that to display them all? I am just really confused.
Below is only the display and sort functions.
//Sort and display all employees
void displayAllEmps()
{
if(numEmps == 0)
{
printf("No employees are hired.");
fflush(stdout);
}
else
{
char output[80];
struct EMP* emp = top;
int i;
for(i = 1; i < numEmps; i++)
{
if (emp != NULL)
{
displayEmployee(emp, output);
printf("%s", output);
fflush(stdout);
}
emp = emp -> next;
}
}
}
//Sort function to call insertion sort function
void sortEmps()
{
temp = NULL;
struct EMP* next = top;
while(temp != NULL)
{
next = top -> next;
insert(temp);
temp = next;
}
top = temp;
}
//Insertion sort function
void insert(struct EMP *emp)
{
prev = NULL;
current = temp;
while (current != NULL && current->id < emp->id)
{
prev = current;
current = current->next;
}
if (prev == NULL)
{
temp = emp;
}
else
{
emp -> next = prev -> next;
prev -> next = emp;
}
}
Your "sort" function is doing nothing except setting the head of your list to "NULL," so you don't actually have a list at all any more. The while loop is never entered, since temp is initially defined as NULL, so temp != NULL can't be true. You then set top = temp;, so now top = NULL.

Resources