How to reduce runtime from linear to constant? - c

lengthOfLinkedList() below counts the number of nodes in a linked list, but the runtime is linear which I do not want. How can I reduce it to a constant runtime function? Are there any library functions I can use?
typedef struct node {
int val;
struct node *next;
} NODE;
struct list_struct {
NODE *front;
NODE *back;
};
int lengthOfLinkedList(LIST *l) {
NODE *n = l->front;
int count = 0;
while (n != NULL) {
count++;
n = n->next;
}
return count;
}

You cannot achieve constant time size calculation with your current struct definition. Now, if you add a size_t member to the struct and use it to store the length, modifying it on any additions or deletions, you can access the length in constant time.
typedef struct node {
int val;
struct node *next;
size_t length;
} NODE;

Define the head-node struct accordingly.
For int value type the list-node remains same:
typedef struct _node {
int val;
struct _node* next;
} listNode_t;
We alter the head-node to suit our needs:
typedef struct {
// add members as scenario demands
int size; // updated after every insert/delete
int min; // updated/checked after every insert/delete/update
int max; // updated/checked after every insert/delete/update
long sum; // updated after every insert/delete/update
listNode_t* first; // to insert/delete from beginning (LIFO-Stack)
listNode_t* last; // to insert at the end (can't delete though)
} listHead_t;
Then you can get those values in O(1), provided they're updated consistently.
listHead_t* head;
...
int listLength = list_getSize (head);
int listMin = list_getMin (head);
int listMax = list_getMax (head);
long listSum = list_getSum (head);
float listAvg = list_getAverage (head); // (float)sum/size
/* List Methods */
list_prefix (head, value); // add value as the first node
list_suffix (head, value); // add value as the last node
That makes list_prefix() like:
...
#include <limits.h>
...
listHead_t* head = list_init_head ();
...
...
listHead_t* list_init_head () {
listHead_t* head = malloc (sizeof(listHead_t));
if (!head) {
perror("list_init_head-malloc");
exit (1);
}
head->size = head->sum = 0;
head->first = head->last = NULL;
head->min = INT_MAX;
head->max = INT_MIN;
return head;
}
int list_prefix (listHead_t* head, int val) {
if (!head) return -1; // invalid call
listNode_t* node = malloc (sizeof(listNode_t));
if (!node) {
perror("list_prefix-malloc");
exit (1);
}
node->val = val;
// update list-head stats
++head->size;
head->sum += val;
if (val < head->min) head->min = val;
if (val > head->max) head->max = val;
if (!head->first) {
node->next = NULL;
head->first = head->last = node;
} else {
node->next = head->first;
head->first = node;
}
return 0;
}

Related

Set a limit on how many items can be used in a link list in c

I'm trying to figure out how to limit the number of items in a linked list to 5 from an array of 20, any ideas would be great.
You need a container storing the size of the list, something like:
struct node
{
the data;
struct node *next;
};
typedef struct
{
struct node *head;
struct node *tail;
size_t size;
} queue;
queue *queue_create(void)
{
return calloc(1, sizeof(queue));
}
Now your insert function can return NULL or false when the list is full:
bool insert(queue *list, the *data)
{
if (list->size == 5)
{
return false;
}
struct node *node = malloc(sizeof *node);
if (node == NULL)
{
return false;
}
node->data = data;
node->next = NULL;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
list->size++;
return true;
}
It can be done in so many different ways. The best solution depends on your program, i.e. how the list is used in your program.
One way is like:
// This struct is used for the individual nodes in the list
typedef struct node {
int data;
struct node * next;
} node;
// This struct is used for managing the list - includes a size counter
typedef struct node_list {
struct node * head;
struct node * tail; // optional
size_t size;
} node_list;
#define MAX_SIZE 10
int insert(node_list * l, int data)
{
if (l->size == MAX_SIZE)
{
// List is full
return -1;
}
// Add code to insert the new node
l->size = l->size + 1; // Increase size
return 0;
}
int main()
{
node_list list = {NULL, NULL, 0}; // Create empty list
if (insert(&list, 42) != 0)
{
// Insert failed - list is full
}
return 0;
}
Like the insert function increases size, you need a delete function where you decrease size when a node is deleted.

Trouble declaring an adjacency list in C

It's the very first time I am trying to use a adjacency list and I am really confused with its declaration
This is my node structure and the list for using as my first node, what I called head
typedef struct node
{
int NodeNum;
struct node *next;
}node;
typedef struct list
{
node *head;
}list;
and here is where I try to allocate the correct amount of memory for the array of heads that the user wants
int n;
scanf("%d", &n);
list *NodList[n] = {0};
for(int i = 0; i < n; i++)
{
NodList[i] = (list*)malloc(sizeof(list));
NodList[i]->head = NULL;
}
Here is the thing, I want the user to tell me how many nodes I'll have and then allocate the correct amount of memory for it, but apparently I am getting something wrong here
Expanding a little bit on Antonin GAVREL's answer. Basically using the same linked list he brought up, and introducing an AListEntry used to represent the adjacency list. Each AListEntry points to a vertex and that vertex's adjacent vertices. It also points to the next AListEntry.
You could, instead, also just replace the AListEntry with a dynamically allocated array of Node pointers if you know the number of vertices ahead of time. Each index in the array will correspond to a vertex, and the pointer will point to the head Node pointer of your adjacent vertices for that vertex, which will a linked list. You'll end up with an array of linked lists.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int value;
struct Node* next;
} t_Node;
t_Node* createNode(int value)
{
t_Node* node = (t_Node*)malloc(sizeof(t_Node));
node->value = value;
node->next = NULL;
return node;
}
t_Node* addNode(int value, t_Node* node)
{
node->next = createNode(value);
return node->next;
}
typedef struct AListEntry
{
t_Node* vertex;
t_Node* adjacentVertices;
struct AListEntry* next;
} t_AListEntry;
t_AListEntry* createAListEntry(
t_Node* vertex,
t_Node* adjacentVertices)
{
t_AListEntry* entry = (t_AListEntry*)malloc(sizeof(t_AListEntry));
entry->vertex = vertex;
entry->adjacentVertices = adjacentVertices;
entry->next = NULL;
return entry;
}
void printAListEntries(t_AListEntry* aList)
{
while (aList != NULL)
{
printf("%d -> [ ", aList->vertex->value);
t_Node* node = aList->adjacentVertices;
while (node != NULL)
{
printf("%d ", node->value);
node = node->next;
}
printf("]\n");
aList = aList->next;
}
}
int main()
{
t_Node* v1 = createNode(1);
t_Node* v1Adjacents = createNode(2);
addNode(3, v1Adjacents);
t_AListEntry* aList = createAListEntry(v1, v1Adjacents);
t_Node* v2 = createNode(2);
t_Node* v2Adjacents = createNode(1);
addNode(3, v2Adjacents);
aList->next = createAListEntry(v2, v2Adjacents);
t_Node* v3 = createNode(3);
t_Node* v3Adjacents = createNode(1);
addNode(2, v3Adjacents);
aList->next->next = createAListEntry(v3, v3Adjacents);
printAListEntries(aList);
return 0;
}
Example where the array is declared on the stack as a VLA:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node
{
int value;
struct Node *next;
} t_Node;
bool build_linked_list(t_Node **head, int n) {
t_Node *node;
t_Node *tmp;
static int a = 1024; // just for test purposes
if (!(node = (t_Node*)malloc(sizeof(t_Node))))
return false;
node->value = a;
*head = node;
for(int i = 1; i < n; i++)
{
if (!(tmp = (t_Node*)malloc(sizeof(t_Node))))
return false;
tmp->value = i + a;
node->next = tmp;
node = tmp;
}
a <<= 1; // so that other nodes have different values
return true;
}
int main(void) {
int n;
scanf("%d", &n);
t_Node *nodes[n];
for (int i = 0; i < n; i++) {
if (!build_linked_list(&nodes[i], n)) {
perror("Failed to malloc node");
return 1;
}
}
for (int i = 0; i < n; i++) {
while (nodes[i]) {
printf("%d\n", nodes[i]->value);
nodes[i] = nodes[i]->next;
}
}
return 0;
}
Let me know if you have any question

c linked list append insert

I want to insert a node int the end of the linked list, but I don't know how to achieve.
#include <stdio.h>
#include <stdlib.h>
typedef struct Info* PtrToNode;
struct Info {
int number;
PtrToNode next;
};
typedef struct Info* list;
typedef struct HashNode* HashTable;
struct HashNode {
list Heads;
int size;
};
HashTable createTable(int size) {
HashTable H = (HashTable)malloc(sizeof(struct HashNode));
H->size = size;
H->Heads = (PtrToNode)malloc(H->size * sizeof(struct Info));
for (int i = 0; i < H->size; ++i)
{
H->Heads[i].number = 0;
H->Heads[i].next = NULL;
}
return H;
}
int Hash(int n, int size) {
return n % size;
}
void insert(HashTable H, int index, int number) {
int pos = Hash(number, H->size);
list check = H->Heads[pos].next;
while (check) {
check = check->next;
}
PtrToNode newNode = (PtrToNode)malloc(sizeof(struct Info));
newNode->number = number;
newNode->next = NULL;
check = newNode;
}
I want append in the insert function, but the params "check" like temporary, and if I "while" the H->heads[pos], the node always in the head.
You are confusing arrays and lists. H->Heads[i].number is not the proper way to access a list. For a list you need H->Heads->number and H->Heads->next. The next pointer will point to the next element of the list
Basically you have an array of numbers with an extra unused pointer.
For the create function given to add an element at the end, you need to realloc the entire array with new size. However, this is probably not what you want.
You need to modify the create function to make a true list and then you can append.
Code below, inserts at the end, you can modify to insert at a particular index.
typedef struct Info* PtrToNode;
struct Info {
int number;
PtrToNode next;
};
typedef struct Info* list;
typedef struct HashNode* HashTable;
struct HashNode {
list Heads;
int size;
};
HashTable createTable(int size) {
HashTable H = (HashTable)malloc(sizeof(struct HashNode));
H->size = size;
H->Heads = malloc(sizeof(struct Info));
H->Heads->number = 0;
H->Heads->next = NULL;
list curr = H->Heads;
list nextval;
for (int i = 1; i < H->size; ++i)
{
nextval = malloc(sizeof(struct Info));
nextval->number = 0;
nextval->next = NULL;
curr->next = nextval;
curr = curr->next;
}
return H;
}
int Hash(int n, int size) {
return n % size;
}
void insert(HashTable H, int index, int number) {
int pos = Hash(number, H->size);
list check = H->Heads;
while (check->next) {
check = check->next;
}
PtrToNode newNode = (PtrToNode)malloc(sizeof(struct Info));
newNode->number = number;
newNode->next = NULL;
check->next = newNode;
(H->size)++;
}

error in function that counts the number of times an int appears in a list

I'm trying to count the number of times a given int occurs in a list, but I'm having a difficult time getting my pointers to work. Can someone spot where is my logic failing? Is it because of how I'm implementing the "follows" "->" in the counting function?
//this is in my .h file
typedef struct list_struct LIST;
///// the rest is in my .c file
typedef struct node {
ElemType val;
struct node *next;
} NODE;
struct list_struct {
NODE *front;
NODE *back;
};
//this is my counting function
int lst_count(LIST *l, ElemType x) {
LIST *current = l;
int count = 0;
while (current != NULL) {
if ((current->front->val) == x) count++;
current = current->front->next;
//in the line above I get the following warning:
//"incompatible pointer types assigning to 'LIST*' (aka 'struct list_struct*') from 'struct node*'"
}
return count;
}
Your problem is in the while loop
You are in a list struct, then you do
current->front->next;
Now you are in a NODE type struct, in the next iteration there is no front in NODE.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
struct node *previous;
} NODE;
int lst_count(NODE *l, int x) {
NODE *current = l;
NODE *start = current; /* so that we wont loose the start*/
int count = 0;
while (current != NULL) {
if ((current->val) == x)
count++;
current = current->next;
}
return count;
}
int main()
{
NODE* p = (NODE*)malloc(sizeof(NODE));
NODE* p1 = (NODE*)malloc(sizeof(NODE));
NODE* p2 = (NODE*)malloc(sizeof(NODE));
NODE* start = p;
p->val = 5;
p->next = p1;
p1->next = p2;
p2->next=NULL;
p1->val = 5;
p2->val = 5;
printf("%d", lst_count(start, 5));
}
I got the function to work thanks to your all advises
int lst_count(LIST *l, int x) {
NODE *current = l->front;
int count = 0;
while (current != NULL) {
if ((current->val) == x) count++;
current = current->next;
}
return count;
}

Creating a queue from a LinkedList in C

currently I'm writing a code which requires me to "copy" a series of integers(user input) from a linkedlist and place them into a queue.
I understand that I require a function called enqueue to proceed, however, I was taught that by simply using the insertNode() function, I can create a basic enqueue function. e.g
void enqueue(Queue *q, int item)
{
insertNode(&(q->ll),q->ll.size, item);
removeNode(ll,0);
}
Given insertNode() :
int insertNode(LinkedList *ll, int index, int value)
{
ListNode *pre, *cur;
if (ll == NULL || index < 0 || index > ll->size + 1)
return -1;
if (ll->head == NULL || index == 0) {
cur = ll->head;
ll->head = malloc(sizeof(ListNode));
ll->head->item = value;
ll->head->next = cur;
ll->size++;
return 0;
}
if ((pre = findNode(ll, index - 1)) != NULL) {
cur = pre->next;
pre->next = malloc(sizeof(ListNode));
pre->next->item = value;
pre->next->next = cur;
ll->size++;
return 0;
}
return -1;
}
and then finally by using another function to make use of the enqueue()
void createQueueFromLinkedList(LinkedList *ll, Queue * q)
{
if (isEmptyQueue) {
removeAllItemsFromQueue(q);
}// empty the queue if it is not empty
while (ll->size)
{
enqueue(q, ll->head->item);
//code to remove ll->size by 1 each time
}
}
int isEmptyQueue(Queue *q)
{
if ((q->ll).size == 0){
return 0;
}
return 1;
}
The problem which I'm facing is that I am not sure whether is my enqueue() working correctly or if there is a better way of going about doing it?
Thanks in advance.
definition of Queue, Linkedlist and ListNode; Suppose I'm not allow to change them :
typedef struct _listnode
{
int item;
struct _listnode *next;
} ListNode;
typedef struct _linkedlist
{
int size;
ListNode *head;
} LinkedList;
typedef struct _queue
{
LinkedList ll;
} Queue;

Resources