Trying to implement k-medoids in C - c

I am trying to implement an algorithm in C which splits a linked list. So what I am trying to do is, I have a linked list of all entries, I am trying to split that linked list into two separate lists based on distance of elements from a specific node.
What shiftAndCluster does is takes in a linked list list, 2 empty lists oldFreshList and newList and 2 nodes best1 and best2. It first searches for these 2 nodes in list and pushed them into 2 empty lists respectively. Then the function iterates over each node of list and calculates its distance from either of the nodes and pushes it to the list containing the closer best node.
The code goes like this
void shiftAndCluster(SinglyLinkedList* list, SinglyLinkedList* oldFreshList, SinglyLinkedList* newList, SinglyLinkedListNode *best1, SinglyLinkedListNode *best2)
{
SinglyLinkedListNode *curr1 = list->front;
SinglyLinkedList *temp = cloneFullList(list);
SinglyLinkedListNode *prev = curr1;
while (curr1 != NULL)
{
if (curr1 == best2)
{
break;
} //reach till best2 in the list, so we have the prev of best2 with us
prev = curr1;
curr1 = curr1->next;
}
if (prev == curr1)
{
list->front = curr1->next;
list->size--;
SinglyLinkedList_pushFront(newList,curr1);
}
else
{
prev->next = curr1->next;
list->size--;
SinglyLinkedList_pushFront(newList,curr1);
}
curr1 = list->front;
prev = curr1;
while(curr1 != NULL)
{
if (curr1 == best1) {
// break when found best1
break;
};
prev = curr1;
curr1 = curr1->next;
}
// first, middle and last
if (prev == curr1)
{
list->front = curr1->next;
list->size--;
SinglyLinkedList_pushFront(oldFreshList,curr1);
}
else
{
prev->next = curr1->next;
list->size--;
SinglyLinkedList_pushFront(oldFreshList,curr1);
}
int firstSize = 1;
int secondSize = 1;
curr1 = list->front;
double dist1, dist2;
while (curr1 != NULL && list->size)
{
curr1=list->front;
SinglyLinkedList_popFront(list);
dist1 = calculateDistance(curr1,best1);
dist2 = calculateDistance(curr1,best2);
if (dist1 < dist2)
{
SinglyLinkedList_pushFront(oldFreshList,curr1);
firstSize++;
if (firstSize == 10) break;
}
else
{
SinglyLinkedList_pushFront(newList,curr1);
secondSize++;
if (secondSize == 10) break;
}
}
list->front = temp->front;
list->size = temp -> size;
}
The size of list is 11 nodes so the algorithm stops when either of the new list reaches size 10. At the end, the old list is repopulated with it's original entries.
The struct has been defined as
typedef struct SinglyLinkedListNode
{
void *data;
struct SinglyLinkedListNode *next;
}SinglyLinkedListNode;
typedef struct SinglyLinkedList
{
int size;
struct SinglyLinkedListNode *front;
}SinglyLinkedList;
Helper functions are:
SinglyLinkedListNode* cloneList(SinglyLinkedListNode *head) {
if(head == NULL) return NULL;
SinglyLinkedListNode *result = (SinglyLinkedListNode *)malloc(sizeof(SinglyLinkedListNode));
result->data = head->data;
result->next = cloneList(head->next);
return result;
}
SinglyLinkedList* cloneFullList(SinglyLinkedList *list) {
if(list == NULL) return NULL;
SinglyLinkedList *result = (SinglyLinkedList *)malloc(sizeof(SinglyLinkedList));
result->size = list->size;
result->front = cloneList(list->front);
return result;
}
pushFront, popFront and calculateDistance functions are trivial and work correctly. (Can provide them if required, but I have tested them extensively, they work correctly)
The issue I am facing is that when I try to use this function in a loop, it breaks after a single iteration.
Example is
//templist is a normal linked list containing 11 nodes
SinglyLinkedListNode *ppp1 = templist->front;
SinglyLinkedListNode *ppp2 = templist->front;
int ctrin = 0, ctr=0;
while (ppp1 != NULL)
{
ctr++;
ppp2 = templist->front;
ctrin = 0;
while (ppp2 != NULL)
{
SinglyLinkedList* tp2 = createEmptyList();
SinglyLinkedList* np2 = createEmptyList();
ctrin++;
if (ppp1 == ppp2)
{
ppp2 = ppp2->next;
ctrin++;
}
shiftAndCluster(templist, tp2, np2, ppp1, ppp2, listType, 1);
templist = cloneFullList(list);
printf("(%d, %d)\n", ctr, ctrin);
ppp2 = ppp2->next;
}
iter++;
ppp1 = ppp1->next;
}
createEmptyList function just creates an empty list.
The output prints (1,2) indicating it does check for (1,1) and skip it and after shifting and clustering once, it breaks down. The incoming list is fine and I think there are issues with the logic of the function. Can someone please help?

May not be the only problem but when you do :
prev = curr1;
curr1 = curr1->next;
prev will always be different of curr1. So the test if (prev == curr1) if always false except if list->front is NULL

Related

Linked list: get node by index has unexpected results

This is my code:
#include <stdlib.h>
typedef struct _node {
int data;
struct _node* next;
} llnode;
llnode* llgetindex(llnode** header, int index){
if(*header == NULL) return NULL;
llnode* i = *header;
llnode* j = *header;
if(index < 0){
// negative indexes
while(index < 0){
if(i == NULL) return NULL;
i = i->next;
index++;
}
while(i != NULL){
i = i->next;
j = j->next;
}
return j;
} else {
//positive indexes
while(index > 0){
if(i == NULL) return NULL;
i=i->next;
index--;
}
return i;
}
}
llnode* push(llnode** header, int data){
if(*header == NULL) {
llnode* item = malloc(sizeof(llnode));
item->data = data;
item->next = NULL;
*header = item;
return item;
} else {
llnode* item = llgetindex(header, (-1));
item->next = malloc(sizeof(llnode));
item->next->data = data;
item->next->next = NULL;
return item->next;
}
}
llnode* pop(llnode** header){
if(*header == NULL) return NULL;
llnode* last = NULL;
// if list is one item long
if((*header)->next == NULL){
last = *header;
*header = NULL;
} else {
llnode* blast = llgetindex(header,(-2));
printf("[0]%lli\n",*header);
printf("[1]%lli\n",(*header)->next);
last = blast->next;
blast->next = NULL;
}
return last;
}
I've traced the problem to the function llgetindex; it somehow is overwriting the pointer to the first element of the list and changing it to what llgetindex should return when given a negative index, but i don't get how.
The strangest thing is that calling push works fine, pop doesn't and calling llgetindex directly also destroys the list.
If you can explain why it happens i would be happy.
To reproduce the problem:
create a llnode** pointer and call push function a few times to populate the list, after call either pop or llgetindex using a negative index and check the list, now the first node of the list should now be either the last if you called pop, or the element indexed by the negative index given to llgetindex.
gcc (Debian 10.2.1-6) 10.2.1 20210110

Infinite loop when trying to add to the beginning of a linked list in C

I'm trying to practice Linked Lists in C and I created a simple LL with an add function that takes a position index and inserts the data at that position.
I keep getting an infinite loop when trying to add to the beginning of my list using the add_beg, which just calls the add_at function with position 0 (add(0, data)) function. I can't seem to find the reason why this is happening. I need another set of eyes. Here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node_t {
int _data;
struct node_t *_next;
} node_t;
node_t *_head = NULL;
void add_at(int pos, int data) {
node_t *node = malloc(1 * sizeof(node_t));
node->_data = data;
node->_next = NULL;
// insert if empty
if (_head == NULL) {
_head = node;
}
else {
int index = 0;
node_t *prev = NULL;
node_t *curr = _head;
while (curr != NULL && index != pos) {
prev = curr;
curr = curr->_next;
index++;
}
// insert beginning
if (index == 0) {
_head = node;
node->_next = _head;
}
// insert end
else if (index != 0 && curr == NULL) {
prev->_next = node;
}
// insert middle
else {
prev->_next = node;
node->_next = curr;
}
}
}
void add_beg(int data) {
add_at(0, data);
}
void add_end(int data) {
add_at(-1, data);
}
void dump() {
if (_head != NULL) {
node_t *curr = _head;
while (curr != NULL) {
if (curr->_next != NULL) {
printf("%d -> ", curr->_data);
}
else {
printf("%d", curr->_data);
}
curr = curr->_next;
}
printf("\n");
}
else {
printf("The list is empty\n");
}
}
int main() {
add_beg(6);
add_at(1, 1);
add_at(2, 3);
add_at(3, 9);
add_at(4, 8);
add_at(5, 5);
add_at(7, 2);
add_at(8, 4);
add_beg(9); // commenting this out prevents the infinite loop
dump();
return 0;
}
The error is in this section:
if (index == 0) {
_head = node;
node->_next = _head;
}
That second command sets node->_next to head. However, the line before set _head to node. Therefore, you just set node->_next to node, creating the infinite loop.
You need to reverse the order of those two statements.
if (index == 0) {
_head = node;
node->_next = _head;
}
here you set _head as node but after next node at _head then when your doing while loop you had already broke your linked list.
Fix :
first set the _head as node->_next then set _head as node

From struct, pointer to NULL, and back

typedef struct Element
{
int number;
struct Element *right;
struct Element *left;
} Element;
Element *newElement;
Element *head;
Element *pos;
Element *current;
void insert_Element()
{
newElement = malloc(sizeof(Element));
if (head==NULL)
{
head = newElement;
current = newElement;
current->right = pos;
//pos->left = current;
}
}
The head of the double-linked-list should have a pointer to the next (right) element (which is NULL, but also pos). This works fine, but the pointer back(left) from pos/NULL doesn't work.
What did I do work; Is it even possible?
Thank you in advance :)
The present version of the insert_Element function does not work unless head is NULL and pos is not NULL, and it does not set the left member of the new element. The purpose of the pos variable has not been stated, but appears to be used to point to the element before which the new element is to be inserted. We could use pos == NULL to indicate that the new element is to be placed at the end of the list. Here is a version that does that:
void insert_Element(void)
{
newElement = malloc(sizeof(Element));
if (newElement == NULL)
{
return;
}
newElement->right = pos;
if (pos != NULL)
{
/* insert before pos */
newElement->left = pos->left;
pos->left = newElement;
}
else if (head != NULL)
{
/* add to end of list */
current = head;
while (current->right != NULL)
{
current = current->right;
}
newElement->left = current;
current->right = newElement;
}
else
{
/* add to empty list */
newElement->left = NULL;
}
if (pos == head)
{
/* make it the start of the list */
head = newElement;
}
/* make it the 'current' element */
current = newElement;
}
It is better not to use global variables so much and uses function parameters instead. Here is a version that uses no global variables and returns a pointer to the new element on the list (or NULL on allocation failure):
Element *insert_Element(Element **phead, Element *pos)
{
Element *newElement = malloc(sizeof(Element));
if (newElement == NULL)
{
return NULL;
}
newElement->right = pos;
if (pos != NULL)
{
/* insert before pos */
newElement->left = pos->left;
pos->left = newElement;
}
else if (*phead != NULL)
{
/* add to end of list */
Element *current = *phead;
while (current->right != NULL)
{
current = current->right;
}
newElement->left = current;
current->right = newElement;
}
else
{
/* add to empty list */
newElement->left = NULL;
}
if (pos == *phead)
{
/* make it the start of the list */
*phead = newElement;
}
return newElement;
}
It's possible you just need to allocate you Element *pos. Actually pos is equal to NULL and logically don't have pointer left or right, it's like looking for the toilet in a house that doesn't exist.

Segregating even and odd nodes in a Linked List

I need to segregate even and odd nodes in a Linked List in C.
Example:
Original list: 3,1,8,2,5,6
After change: 8,2,6,3,1,5
I have a problem when the head list data is an odd number, it is cutting out the even numbers.
Example:
Original list: 3,1,8,2,5,6
After change: 3,1,5
typedef struct Node {
int data; // store information
struct Node * next; //referance to the next node
}Node;
Node * create(Node * L, int value)
{
Node *current = L ,* new_node = (Node*)malloc(sizeof(Node)); // create and allocate a node
new_node->data = value;
new_node->next = NULL;
if (L == NULL)
{
L = new_node;
current = new_node;
}
else
{
while (current->next != NULL)
current = current->next;
current->next = new_node;
current = new_node;
}
return L;
}
Node * Change_Even_Odd(Node * L)
{
Node *oddhead = NULL, *evenhead = NULL, *lastodd = NULL, *lasteven = NULL, *current = L;
while (current != NULL)
{
// if current is even node
if (current->data % 2 == 0)
{
if (evenhead == NULL)
{
evenhead = current;
lasteven = current;
}
else
{
lasteven->next = current; // to connect the node to the list in the end
lasteven = current; // final list
}
}
else
{
// if current is odd node
if (oddhead == NULL)
{
oddhead = current;
lastodd = current;
}
else
{
lastodd->next = current;
lastodd = current;
}
}
current = current->next;
}
if (evenhead != NULL) // to put the even node in the head list
L = evenhead;
if (lasteven != NULL) // link the odd nodes to the even nodes
lasteven->next = oddhead;
if (lastodd != NULL) //end of list
lastodd->next = NULL;
return L;
}
void Print_List(Node * head)
{
while (head != NULL)
{
printf("%4d", head->data);
head = head->next;
}
}
int main()
{
Node * list = NULL; //empty linked list
srand(time(NULL));
int i, size = rand() % 10 + 1;
for (i = 0; i < size; i++)
list = create(list, rand() % 10 + 1);
printf("%d\n",size);
Print_List(list);
printf("\n");
Change_Even_Odd(list);
Print_List(list);
printf("\n");
}
Change_Even_Odd(list); should be list = Change_Even_Odd(list); (I already pointed out.)
– BLUEPIXY

sorting linked list simplest way

I am trying to code very basic sorting method for linked lists. I am getting unhandled exception. What is the mistake i am making? Here is my code:-
struct LinkedNode// structure for linked list
{
int data;
struct LinkedNode *next;
}*start = NULL;
following function creates a linked list
void CreateLinkedList()
{
LinkedNode *newNode, *current;
printf("enter 5 numbers to create linked list\n");
for(int i=0; i<5; i++)
{
newNode = (struct LinkedNode *)malloc(sizeof(LinkedNode));
scanf("%d", &newNode->data);
newNode->next = NULL;
if(start == NULL)
{
start = newNode;
current = newNode;
}
else
{
current->next = newNode;
current = newNode;
}
}
}
following function is used for sorting the linked list nodes
void SortLinkedList()
{
struct LinkedNode *node=NULL, *temp = NULL;
int tempvar;//temp variable to store node data
node = start;
temp = node->next;//temp node to hold node data and next link
while(node != NULL && node->next != NULL)
{
for(int j=0; j<5; j++)//value 5 because I am taking only 5 nodes
{
if(node->data > temp->data)//swap node data
{
tempvar = node->data;
node->data = temp->data;
temp->data = tempvar;
}
temp = temp->next;
}
node = node->next;
}
}
Try This code
void SortLinkedList()
{
struct LinkedNode *node=NULL, *temp = NULL;
int tempvar;//temp variable to store node data
node = start;
//temp = node;//temp node to hold node data and next link
while(node != NULL)
{
temp=node;
while (temp->next !=NULL)//travel till the second last element
{
if(temp->data > temp->next->data)// compare the data of the nodes
{
tempvar = temp->data;
temp->data = temp->next->data;// swap the data
temp->next->data = tempvar;
}
temp = temp->next; // move to the next element
}
node = node->next; // move to the next node
}
}
1 - outer while loop is use for the total number of pass that will require to sort the linked list..
2- In second while loop we are actually comparing the data of the nodes that we want to sort
Instead of implementing your own sort, you can just use qsort. Of course, qsort requires an array, but that is easy enough to create.
In this case, you know that the list has 5 members. But, if you didn't know, you could just count them.
int size_of_list = 0;
struct LinkedNode *p;
for (p = start; p != NULL; p = p->next) ++size_of_list;
if (size_of_list == 0) {
// Nothing to do
return;
}
Now you can create your array;
struct LinkedNode *arr[size_of_list + 1], **arrp = arr;
for (p = start; p != NULL; p = p->next) *arrp++ = p;
*arrp = NULL;
Then, use qsort on arr. There are lots of examples, but the trick is writing an appropriate comparison function.
int cmp_LinkedNode(const void *a, const void *b) {
const struct LinkedNode * const *aa = a;
const struct LinkedNode * const *bb = b;
return ((*aa)->data > (*bb)->data) - ((*aa)->data < (*bb)->data);
}
//...
qsort(arr, size_of_list, sizeof(*arr), cmp_LinkedNode);
And then, rewire the list into the sorted order.
for (int i = 0; i < size_of_list; ++i) arr[i]->next = arr[i+1];
start = arr[0];
yeah sorting a linked list using nodes/links is a pretty hard job. Spend hours doing it myself but since i have done it why not help others..
What you need to do is simply find the minimum value in your list. Swap it with the head node and the recur for head->next.
The code for sort is only of 3 to 4 lines if you have FindMin() and Swap() functions made..
here is the complete code for sort(),swap()and findmin().
void sort(node **start)
{
if (((*start)->next == NULL) || (*start == NULL))
{
return;
}
node *min = findmin(*start);
swap(*start, min, start);
sort(&((*start)->next));
}
void swap(node *p1, node *p2, node **start)
{
node *p1pre = NULL;
node *p1curr = *start;
while (p1curr!=p1)
{
p1pre = p1curr;
p1curr = p1curr->next;
}
node *p2pre = NULL;
node *p2curr = *start;
while (p2curr != p2)
{
p2pre = p2curr;
p2curr = p2curr->next;
}
if (p1pre != NULL)
{
p1pre->next = p2curr;
}
else
{
*start = p2curr;
}
if (p2pre != NULL)
{
p2pre->next = p1curr;
}
else
{
*start = p1curr;
}
node *temp = p2curr->next;
p2curr->next = p1curr->next;
p1curr->next = temp;
}
node* findmin(node *start)
{
int flag = 0;
if (start == NULL)
{
cout << "list is empty" << endl;
}
else
{
node *curr = start->next;
node *min = start;
while (curr->next != NULL)
{
if (min->value > curr->value)
{
min = curr;
flag++;
}
curr = curr->next;
}
if ((curr->next == NULL) && (min->value > curr->value))
{
min = curr;
flag++;
}
if (flag > 0)
{
return min;
}
}
}

Resources