I could use a little help. I'm trying to sort a queue of structures by year.
This are my structures:
struct element{
int id;
int sign;
int year;
int month;
double amount;
struct element *next;
};
struct queue{
struct element *head;
struct element *tail;
struct element *heads;
struct element *temp;
struct element *temph;
int size;
};
and this is the function i wrote:
void sort(struct queue* queue){
if (queue->size == 0){
printf("Struct is empty\n");}
else {
struct element* head=queue->head;
struct element* heads=queue->heads;
struct element* temp=NULL;
struct element* temph=queue->head;
int i, size=queue->size;
for(i=0;i<size-1;i++){
heads=head->next;
if((head->year)>(heads->year)){
temp=head;
head=heads;
heads=temp;
}
head=head->next;
heads=NULL;
temp=NULL;
}
head=temph;
}
}
It breaks when I copmare: if((head->year)>(heads->year)).
I'm pretty sure that my problem is caused by improper reference to the structure next to head (I named it heads).
I omitted all the non-important stuff, and reduced the linked-list bubbele sort to this skeletton.
void sort(struct queue* queue)
{
struct element **pp, *this;
if (!queue->head ){
fprintf(stderr, "OMG Struct is empty\n");
return;
}
for(pp = &queue->head; this = *pp; pp = &(*pp)->next){
struct element *other = this->next;
if (!this->next) break;
if (this->year < other->year) continue;
/*
** Now, Swap this (b) and other (c)
** old situation: #a -> (b) -> (c) -> (d)
** new situation: #a -> (c) -> (b) -> (d)
*/
*pp = other; /* #a -> (c) */
this->next = other->next; /* (b) -> (d) */
other->next = this; /* (c) -> (b) */
}
/* Note: when we get here, "this" will contain the last non-NULL node in the
** chain, and can be used to reset the tail-pointer
*/
return;
}
Related
I have a list defined as
typedef struct node {
Voo *voo;
ListaReservas nodeReservas; /* Ignore this */
struct node *next;
} *Node;
I created some functions to help me add or remove nodes from the list like:
/* creates a node */
Node criaNode(Voo v) {
Node new = (Node)malloc(sizeof(struct node));
new->voo = &v;
/* I had new->voo = v; but vscode told me it was wrong so i changed it to &v */
new->next = NULL;
return new;
}
Voo is defined as:
typedef struct {
int dia;
int mes;
int ano;
} Data;
typedef struct {
int horas;
int minutos;
} Tempo;
typedef struct {
char codigo[LEN_CODIGO + 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
Now I wanted to iterate through the list and print its values as such
Voo *v;
for (n = headVoos; n != NULL; n = n->next) {
v = n->voo;
printf("%s %s %s %.2d-%.2d-%d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
The program is not printing correctly. For example where it should appear
AA1 AAA AAD 16-03-2022 14:50
its appearing instead
� 146187376-32765--1940381952 40355300:50
What's causing this and how can I avoid it in the future?
EDIT
After replacing in the struct node the Voo *voo definition by Voo voo, I am now getting an error in one of the auxiliary functions:
/* deletes node */
Node eliminaNode(Node head, Voo v)
{
Node n, prev;
for (n = head, prev = NULL; n != NULL; prev = n, n = n->next)
{
if (n->voo == v) /* expression must have arithmetic or pointer error */
{
if (n == head)
head = n->next;
else
prev->next = n->next;
free(n->next);
free(n);
break;
}
}
return head;
}
In criaNode you're taking the address of the parameter v and returning it from the function via a pointer to dynamic memory. That address is no longer valid after the function returns. Subsequently dereferencing that invalid address then triggers undefined behavior.
It probably makes more sense for struct node to contain a Voo directly instead of a pointer to one. So change the member to a non-pointer:
Voo voo;
And assign the parameter directly:
new->voo = v;
There are multiple problems here:
there seems to be a confusion between structures and pointers to structures. In C, you must understand the difference between manipulating objects (allocating as local objects or from the head, passing as arguments or returning as values) and pointers to objects, which are a more idiomatic as arguments to functions and allow functions to modify the object they point to.
the confusion is amplified by a very error prone construction: hiding pointers behind typedefs. Do not do that, define object types for the actual structure, using the same or a different name as the struct tag, and make all pointers explicit with the * syntax.
you pass an actual Voo object as an argument and allocate a list node using the address of this argument. This is incorrect because the argument will be discarded as soon as the function returns, makeing the list point to invalid memory and explaining the weird output you observe.
Node eliminaNode(Node head, Voo v) should take a pointer to the head node and return a success indicator. It should take a Voo * argument and it should not free(n->next) because the next node is still in use after the removal.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#define LEN_CODIGO 30
#define LEN_ID 30
typedef struct Data {
int dia;
int mes;
int ano;
} Data;
typedef struct Tempo {
int horas;
int minutos;
} Tempo;
typedef struct Voo {
char codigo[LEN_CODIGO+ 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
typedef struct Node {
struct Voo *voo;
//ListaReservas nodeReservas; /* Ignore this */
struct Node *next;
} Node;
/* creates a node */
Node *criaNode(Voo *v) {
/* allocation with calloc is safer as the object will be initialized to 0 */
Node *nodep = calloc(1, sizeof(*new));
if (nodep) {
nodep->voo = v;
nodep->next = NULL;
}
return nodep;
}
/* deletes node */
int eliminaNode(Node **head, Voo *v) {
for (Node *n = *head, *prev = NULL; n != NULL; prev = n, n = n->next) {
if (n->voo == v) {
if (n == *head)
*head = n->next;
else
prev->next = n->next;
free(n);
return 1; /* article was found and freed */
}
}
return 0; /* article was not found */
}
void printList(const Node *head) {
for (const Node *n = head; n != NULL; n = n->next) {
const Voo *v = n->voo;
printf("%s %s %s %.2d-%.2d-%.2d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
}
Below is the code that implements List abstraction using both array and circular doubly linked list
/* list .h */
/*
List is an ordered collection of homogenuous type elements(unique or duplicate).
List is not designed to have collection of heterogenuous type elements
All elements in a List are related.
List is mutable
Each element has a position.
If an element is deleted, then still the remaining elements sit in new order.
Array implementation of List
*/
#include<stddef.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
typedef enum{false, true}bool;
typedef enum {CREATE_NEW_LIST, DOUBLE_THE_LIST, HALF_THE_LIST}Op;
#if defined(ARRAY)
typedef struct List{
int *array;
int lastItemPosition;
int size;
}List;
#define INITIAL_LIST_SIZE 50
#elif defined(LINKED_LIST)
typedef struct DListNode{
int item;
struct DListNode *next;
struct DListNode *prev;
}DListNode;
/*
Reason to introduce 'List' type:
Problem 1:
Say, user code has 'x' and 'y' pointing to the same list that is built using 'Node' type.
Some part of user code update list with new item using 'x'
'y' is not in sync with this updation
Node *x = someCreatedList;
Node *y = x;
Node *z = malloc(sizeof(Node));
z->next = x;
x = z; //y misses that reference.
Solution:
Maintain a List type, whose job is to point to head(first node) of the list.
User code will go via reference of List type
Problem 2:
It make sense to have references of 'Node' type pointing to NULL
Applying operation[insertItem()] on NULL pointer will cause runtime errors
Solution:
Run operations over List type because it does not make sense to have reference of SList type pointing to NULL.
To solve problem1 & problem2, here is 'List' type
*/
typedef struct List{ //Circular
DListNode *head;
int size; //size attribute is not part of list definition, but quick way to help user code
}List;
#define SENTINEL_ITEM -1
#else
#error "Wrong list implementation macro name !!!"
#endif
void insertItem(List *, int, int);
void deleteItem(List *, int);
List* createList(List *, Op);
/* linkedListImpl.c */
#if defined(LINKED_LIST)
#include"list.h"
DListNode* createNode(int value){
DListNode *newNode= malloc(sizeof(DListNode));
newNode->next = newNode;
newNode->prev = newNode;
newNode->item = value;
return newNode;
}
List *createList(List *list, Op opType ){
List *lptr = (List *)malloc(sizeof(List));
if(opType == CREATE_NEW_LIST){
/*
Amidst performing operations on 'List', you need to check special cases
for List with no item
To reduce the number of special cases, we designate one node as 'SENTINEL'
After using sentinel, there will be no NULL assignments/check in code.
*/
DListNode *sentinel = createNode(SENTINEL_ITEM);
lptr->head = sentinel;
lptr->size = 0;
return lptr;
}else{
fprintf(stderr, "Invalid flag passed to createList() \n");
return (List *)NULL;
}
}
void insertItem(List *linkedList, int newItem, int index){ //O(n)
DListNode *positionElem = linkedList->head;
bool isFirstElement = true; //assume
if(index + 1 <= linkedList->size){
fprintf(stderr, "Position already filled \n");
return;
}else{
DListNode *newNode = createNode(newItem);
while(index--){
positionElem = positionElem->next;
isFirstElement = false;
}
if(isFirstElement){
newNode->next = positionElem;
positionElem->prev = newNode;
}else{
newNode->next = positionElem->next;
newNode->next->prev = positionElem->next;
}
newNode->prev = positionElem;
positionElem->next = newNode;
}
return;
}
void deleteItem(List *linkedList, int index){
//delete element given index
return;
}
#endif
/* arrayImpl.c */
#if defined(ARRAY)
#include"list.h"
List *createList(List *list, Op opType){
List *lptr = (List *)malloc(sizeof(List));
if(opType == CREATE_NEW_LIST){
lptr->array = malloc(INITIAL_LIST_SIZE*sizeof(int));
lptr->array = memset(lptr->array, -1, INITIAL_LIST_SIZE*sizeof(int));
lptr->lastItemPosition = -1;
lptr->size = INITIAL_LIST_SIZE;
}else if(opType == DOUBLE_THE_LIST){
lptr->array = malloc(2*(list->size)*sizeof(int));
lptr->array = memcpy(lptr->array, list->array, list->size*sizeof(int));
lptr->lastItemPosition = list->lastItemPosition;;
lptr->size = 2*(list->size);
}else if(opType == HALF_THE_LIST){
lptr->array = malloc(((list->size)/2)*sizeof(int));
lptr->array = memcpy(lptr->array, list->array, (list->size/2)*sizeof(int));
lptr->lastItemPosition = list->lastItemPosition;;
lptr->size = (list->size)/2;
}
return lptr;
}
void insertItem(List *arrayList, int newItem, int index){
/* House keeping */
if(arrayList->lastItemPosition + 1 == arrayList->size){
arrayList = createList(arrayList, DOUBLE_THE_LIST);
}
/* Insert the element */
arrayList->array[index] = newItem;
if(index > arrayList->lastItemPosition){
arrayList->lastItemPosition = index;
}
return;
}
void deleteItem(List *arrayList, int index){
arrayList->array[index] = -1;
if(index == arrayList->lastItemPosition){
arrayList->lastItemPosition--;
}
/* House keeping */
if(arrayList->size > INITIAL_LIST_SIZE){
if(arrayList->lastItemPosition == ((arrayList->size)/2)){
arrayList = createList(arrayList, HALF_THE_LIST);
}
}
}
#endif
/* main.c */
#include"list.h"
int main(void){
List *linkedList = (List *)NULL;
linkedList = createList((List *)NULL, CREATE_NEW_LIST);
//List *arrayList = createList(CREATE_NEW_LIST);
if (linkedList == (List *)NULL){
fprintf(stderr, "Unable to createList() \n");
exit(1); //Nothing else to do without linkedList
}
insertItem(linkedList, 1, 0);
}
Compiled as
> gcc -DLINKED_LIST main.c arrayImpl.c linkedListImpl.c
Encapsulation is about maintaining invariants of an ADT List
The following invariants apply to the List with a sentinel.
(1) For any List d, d.head != NULL. (There’s always a sentinel.)
(2) For any DListNode x, x.next != NULL.
(3) For any DListNode x, x.prev != NULL.
(4) For any DListNode x, if x.next == y, then y.prev == x.
(5) For any DListNode x, if x.prev == y, then y.next == x.
(6) A List’s size member is the number of DListNode's, NOT COUNTING the sentinel (pointed by "head"), that can be accessed from the sentinel by a sequence of `next references.
Abstraction is the creation of barrier between representation and usage(user interface)
Question:
O(1) insertion and deletion is possible by providing DListNode node access via insertItem()/deleteItem() user interfacece to user(main.c). But, Encapsulation will be broken due to malfunction by user on that DListNode type node. How to enforce O(1) using linked list?
I have a linked_list struct:
typedef struct linked_list{
void *data;
struct linked_list *next;
struct linked_list *previous;
} linked_list;
And some linked list operations:
linked_list *init_linked_list() {
linked_list *ll;
ll = (linked_list *) malloc(sizeof(linked_list));
ll->next = ll;
ll->previous = ll;
return ll;
}
void add_element( linked_list *list, void *element) {
linked_list *list_element;
list_element = malloc(sizeof(linked_list));
list_element->data = element;
list_element->next = list->next;
list->next->previous = list_element ;
list->next = list_element ;
list_element->previous = list;
}
I have a graph struct:
typedef struct graph {
int number_vertices;
vertex **vertices;
} graph;
I have a vertex struct:
typedef struct vertex {
int time;
char *name;
linked_list *edges;
} vertex;
I have a edge struct:
typedef struct edge{
int weight;
int change;
vertex *to;
} edge;
And an "add-edge" function:
void add_edge_to_vertex(vertex *v, int weight, int change, vertex *to) {
edge *pEdge = malloc(sizeof(edge));
pEdge->weight = weight;
pEdge->change = change;
pEdge->to = to;
// add edge to vertex linked list
add_element(v->edges, pEdge);
}
Now to my problem. I setup my graph:
int aSize = 30;
int bSize = 30;
pGraph = malloc(sizeof(graph));
pGraph->vertices = malloc(sizeof(vertex*) * aSize);
pGraph->vertices[0] = malloc(sizeof(vertex) * bSize);
I setup my a vertex and init the linked_list:
vertex *pVertex ;
pVertex = malloc(sizeof(vertex));
pVertex->edges = init_linked_list();
And I add the vertex to my graph:
pGraph->vertices[a][b] = *pVertex;
Last I add an edge between two vertices:
add_edge_to_vertex(&pGraph->vertices[a][i], 100, 0, &pGraph->vertices[a][i+1]);
When I try to fetch the edge weight, I get an segment fault: 11
vertex *v = &pGraph->vertices[0][0];
linked_list *ll = v->edges;
int s = linked_list_size(ll);
printf("%d\n", s); // outputs 1 - works so far!
edge *e = (edge *) ll->data;
int weight = e->weight; // segment fault: 11 ..
I have also tried to add an int and a char to the linked_list struct, and fetched that value, instead of fetching (and casting) edge from the "void *data". This works.
My problem now is, that I don't know if my fault is when I fetch the data, or when I store the data.
Your linked list has one extra node at the start that does not have its data member initialized (the node created by the init_linked_list() function).
When you do :
edge *e = (edge *) ll->data;
you get that first node's data member, which is uninitialized. That causes the segmentation fault when you try to dereference e.
Try this instead :
edge *e = (edge *) ll->next->data;
which will get the data member for the node that was inserted by the last add_element function call. Obviously, this is only safe if there has been at least one element added into the linked list.
I'm trying to delete all nodes from my queue of structures.
Structure:
struct element{
int id;
int sign;
int year;
int month;
double amount;
struct element *next;
};
struct queue{
struct element *head;
int size;
};
And the function I wrote:
void delete(struct queue *queue) {
if (queue->size == 0){
printf("Structure is empty\n");
}
else {
struct element* this;
struct element* other;
for(this=queue->head;this!=NULL;this=other)
{
other=this->next;
free(this);
}
free(queue);
}
}
It doesn't work, and I'm out of ideas. Any suggestions?
In your delete routine, you do not free the queue if the size is empty, but you do free it if the size is non-empty. You should probably do the same for both cases. That is, either don't free in both places, or free in both places.
It is bothersome to need to figure out what the right thing to do is, because delete can not know how the queue was allocated. Given your current design, a way out may be to pass a flag to delete to indicate what it should do:
void delete(struct queue *queue, int do_free) {
if (queue->size == 0){
printf("Structure is empty\n");
}
else {
struct element* this;
struct element* other;
for(this=queue->head;this!=NULL;this=other) {
other=this->next;
free(this);
}
queue->head = 0;
queue->size = 0;
}
if (do_free) free(queue);
}
struct queue new;
/* ... */
delete(&new, 0); /* don't free the queue */
struct queue *empty_new = malloc(sizeof(struct queue));
empty_new->size = 0;
delete(empty_new, 1); /* free the empty queue */
Here
struct queue new;
//...
delete(&new);
new is allocated on the stack, so don't call free(queue) in delete.
Instead, set queue->head = NULL; queue->size = 0; to indicate that the queue is now empty as mentioned by #kirill.
How about just passing the first element of the queue.
void delete(element *el ) {
if(el) {
delete(el->next );
free(el);
}
}
with
typedef struct _element{
int id;
int sign;
int year;
int month;
double amount;
struct _element *next;
} element;
you might have forgotten to update at the end of the function the pointer to NULL as well as changing the size of the queue to 0.
This is just another interview question.
Can we have a linked list of different data types, i.e. each element in a linked list can have different structure or union elements? If it's possible can you please explain with an example?
Well in a linked list you don't HAVE to link like for like structs together. As long as they have the appropriate forward and/or backwards pointers you are fine. For example:
struct BaseLink
{
BaseLink* pNext;
BaseLink* pPrev;
int typeId;
};
struct StringLink
{
BaseLink baseLink;
char* pString;
};
struct IntLink
{
BaseLink baseLink;
int nInt;
};
This way you'd have a linked list that goes from BaseLink to BaseLink. The extra data is not a problem. You want to see it as a StringLink? Then cast the BaseLink to a StringLink.
Just remember that you need some form of typeid in there so you know what to cast it to when you arrive at it.
Use union to create the datatype
union u_tag{
char ch;
int d;
double dl;
};
struct node {
char type;
union u_tag u;
struct node *next;
};
Use struct node to create linked list. type decides what is the datatype of the data.
Harsha T, Bangalore
You can use a union type:
enum type_tag {INT_TYPE, DOUBLE_TYPE, STRING_TYPE, R1_TYPE, R2_TYPE, ...};
struct node {
union {
int ival;
double dval;
char *sval;
struct recordType1 r1val;
struct recordType2 r2val;
...
} data;
enum type_tag dataType;
struct node *prev;
struct node *next;
};
Another method I've explored is to use a void* for the data and attach pointers to functions that handle the type-aware stuff:
/**
* Define a key type for indexing and searching
*/
typedef ... key_t;
/**
* Define the list node type
*/
struct node {
void *data;
struct node *prev;
struct node *next;
void *(*cpy)(void *); // make a deep copy of the data
void (*del)(void *); // delete the data
char *(*dpy)(void *); // format the data for display as a string
int (*match)(void *, key_t); // match against a key value
};
/**
* Define functions for handling a specific data type
*/
void *copyARecordType(void *data)
{
struct aRecordType v = *(struct aRecordType *) data;
struct aRecordType *new = malloc(sizeof *new);
if (new)
{
// copy elements of v to new
}
return new;
}
void deleteARecordType(void *data) {...}
char *displayARecordType(void *data) {...}
int matchARecordType(void *data, key_t key) {...}
/**
* Define functions for handling a different type
*/
void *copyADifferentRecordType(void *data) {...}
void deleteADifferentRecordType(void *data) {...}
char *displayADifferentRecordType(void *data) {...}
int matchADifferentRecordType(void *data, key_t key) {...}
/**
* Function for creating new list nodes
*/
struct node *createNode(void *data, void *(*cpy)(void *), void (*del)(void *),
char *(*dpy)(void *), int (*match)(void *, key_t))
{
struct node *new = malloc(sizeof *new);
if (new)
{
new->cpy = cpy;
new->del = del;
new->dpy = dpy;
new->match = match;
new->data = new->cpy(data);
new->prev = new->next = NULL;
}
return new;
}
/**
* Function for deleting list nodes
*/
void deleteNode(struct node *p)
{
if (p)
p->del(p->data);
free(p);
}
/**
* Add new node to the list; for this example, we just add to the end
* as in a FIFO queue.
*/
void addNode(struct node *head, void *data, void *(*cpy)(void*),
void (*del)(void *), char *(*dpy)(void *), int (*match)(void*, key_t))
{
struct node *new = createNode(data, cpy, del, dpy, match);
if (!head->next)
head->next = new;
else
{
struct node *cur = head->next;
while (cur->next != NULL)
cur = cur->next;
cur->next = new;
new->prev = cur;
}
}
/**
* Examples of how all of this would be used.
*/
int main(void)
{
struct aRecordType r1 = {...};
struct aDifferentRecordType r2 = {...};
struct node list, *p;
addNode(&list, &r1, copyARecordType, deleteARecordType, displayARecordType,
matchARecordType);
addNode(&list, &r2, copyADifferentRecordType, deleteADifferentRecordType,
displayADifferentRecordType, matchADifferentRecordType);
p = list.next;
while (p)
{
printf("Data at node %p: %s\n", (void*) p, p->dpy(p->data));
p = p->next;
}
return 0;
}
Obviously, I've left out some error checking and handling code from this example, and I don't doubt there are a host of problems with it, but it should be illustrative.
You can have each node in a linked list have a void* that points to your data. It's up to you how you determine what type of data that pointer is pointing to.
If you don't want to have to specify the type of every node in the list via the union solution you can always just store the data in a char* and take type-specific function pointers as parameters to type-sensitive operations such as printing or sorting the list.
This way you don't have to worry about what node is what type and can just cast the data however you like.
/* data types */
typedef struct list_node list_node;
struct list_node {
char *data;
list_node *next;
list_node *prev;
};
typedef struct list list;
struct list {
list_node *head;
list_node *tail;
size_t size;
};
/* type sensitive functions */
int list_sort(list *l, int (*compar)(const void*, const void*));
int list_print(list *l, void (*print)(char *data));
Yes, I do this by defining the list's element's value as a void pointer void*.
In order to know the type stored in each element of the list I also have a .type field in there, so I know how to dereference what the pointer is pointing to for each element.
struct node {
struct node* next;
int type;
void* value;
};
Here's a full example of this:
//
// An exercise to play with a struct that stores anything using a void* field.
//
#include <stdio.h>
#define TRUE 1
int TYPE_INT = 0;
int TYPE_STRING = 1;
int TYPE_BOOLEAN = 2;
int TYPE_PERSON = 3;
struct node {
struct node* next;
int type;
void* value;
};
struct person {
char* name;
int age;
};
int main(int args, char **argv) {
struct person aPerson;
aPerson.name = "Angel";
aPerson.age = 35;
// Define a linked list of objects.
// We use that .type field to know what we're dealing
// with on every iteration. On .value we store our values.
struct node nodes[] = {
{ .next = &nodes[1], .type = TYPE_INT , .value=1 },
{ .next = &nodes[2], .type = TYPE_STRING , .value="anyfing, anyfing!" },
{ .next = &nodes[3], .type = TYPE_PERSON , .value=&aPerson },
{ .next = NULL , .type = TYPE_BOOLEAN, .value=TRUE }
};
// We iterate through the list
for ( struct node *currentNode = &nodes[0]; currentNode; currentNode = currentNode->next) {
int currentType = (*currentNode).type;
if (currentType == TYPE_INT) {
printf("%s: %d\n", "- INTEGER", (*currentNode).value); // just playing with syntax, same as currentNode->value
} else if (currentType == TYPE_STRING) {
printf("%s: %s\n", "- STRING", currentNode->value);
} else if (currentType == TYPE_BOOLEAN) {
printf("%s: %d\n", "- BOOLEAN (true:1, false:0)", currentNode->value);
} else if (currentType == TYPE_PERSON) {
// since we're using void*, we end up with a pointer to struct person, which we *dereference
// into a struct in the stack.
struct person currentPerson = *(struct person*) currentNode->value;
printf("%s: %s (%d)\n","- TYPE_PERSON", currentPerson.name, currentPerson.age);
}
}
return 0;
}
Expected output:
- INTEGER: 1
- STRING: anyfing, anyfing!
- TYPE_PERSON: Angel (35)
- BOOLEAN (true:1, false:0): 1
As said, you can have a node this questionwith a void*. I suggest using something to know about your type :
typedef struct
{
/* linked list stuff here */
char m_type;
void* m_data;
}
Node;
See this question.
Actually, you don't have to put the pointer first in the structure, you can put it anywhere and then find the beginning fo the struct with a containerof() macro. The linux kernel does this with its linked lists.
http://isis.poly.edu/kulesh/stuff/src/klist/
I use these macros I wrote to make general linked lists. You just create your own struct and use the macro list_link somewhere as a member of the struct. Give that macro one argument naming the struct (without the struct keyword). This implements a doubly linked list without a dummy node (e.g. last node links back around to first node). The anchor is a pointer to the first node which starts out initialized by list_init(anchor) by giving it the lvalue (a dereferenced pointer to it is an lvalue). Then you can use the other macros in the header. Read the source for comments about each available macro functions. This is implemented 100% in macros.
http://phil.ipal.org/pre-release/list-0.0.5.tar.bz2
Yes,Sure You can insert any data type values in the linked list I've designed and its very simple to do so.I have used different constructors of node and boolean variables to check that which type value is inserted and then I do operation and command according to that value in my program.
//IMPLEMENTATION OF SINGLY LINKED LISTS
#include"iostream"
#include"conio.h"
#include <typeinfo>
using namespace std;
class node //struct
{
public:
node* nextptr;
int data;
////////////////////////////////just to asure that user can insert any data type value in the linked list
string ss;
char cc;
double dd;
bool stringTrue=0;
bool intTrue = 0;
bool charTrue = 0;
bool doubleTrue = 0;
////////////////////////////////just to asure that user can insert any data type value in the linked list
node()
{
nextptr = NULL;
}
node(int d)
{
data = d;
nextptr = NULL;
intTrue = 1;
}
////////////////////////////////just to asure that user can insert any data type value in the linked list
node(string s)
{
stringTrue = 1;
ss = s;
nextptr = NULL;
}
node(char c)
{
charTrue = 1;
cc = c;
nextptr = NULL;
}
node(double d)
{
doubleTrue = 1;
dd = d;
nextptr = NULL;
}
////////////////////////////////just to asure that user can insert any data type value in the linked list
//TO Get the data
int getintData()
{
return data;
}
string getstringData()
{
return ss;
}
double getdoubleData()
{
return dd;
}
char getcharData()
{
return cc;
}
//TO Set the data
void setintData(int d)
{
data = d;
}
void setstringData(string s)
{
ss = s;
}
void setdoubleData(double d)
{
dd = d;
}
void setcharData(char c)
{
cc = c;
}
char checkWhichInput()
{
if (intTrue == 1)
{
return 'i';
}
else if (stringTrue == 1)
{
return 's';
}
else if (doubleTrue == 1)
{
return 'd';
}
else if (charTrue == 1)
{
return 'c';
}
}
//////////////////////////////Just for the sake of implementing for any data type//////////////////////////////
node* getNextptr()
{
return nextptr;
}
void setnextptr(node* nptr)
{
nextptr = nptr;
}
};
class linkedlist
{
node* headptr;
node* addnodeatspecificpoition;
public:
linkedlist()
{
headptr = NULL;
}
void insertionAtTail(node* n)
{
if (headptr == NULL)
{
headptr = n;
}
else
{
node* rptr = headptr;
while (rptr->getNextptr() != NULL)
{
rptr = rptr->getNextptr();
}
rptr->setnextptr(n);
}
}
void insertionAtHead(node *n)
{
node* tmp = n;
tmp->setnextptr(headptr);
headptr = tmp;
}
int sizeOfLinkedList()
{
int i = 1;
node* ptr = headptr;
while (ptr->getNextptr() != NULL)
{
++i;
ptr = ptr->getNextptr();
}
return i;
}
bool isListEmpty() {
if (sizeOfLinkedList() <= 1)
{
return true;
}
else
{
false;
}
}
void insertionAtAnyPoint(node* n, int position)
{
if (position > sizeOfLinkedList() || position < 1) {
cout << "\n\nInvalid insertion at index :" << position;
cout <<".There is no index " << position << " in the linked list.ERROR.\n\n";
return;
}
addnodeatspecificpoition = new node;
addnodeatspecificpoition = n;
addnodeatspecificpoition->setnextptr(NULL);
if (headptr == NULL)
{
headptr = addnodeatspecificpoition;
}
else if (position == 0)
{
addnodeatspecificpoition->setnextptr(headptr);
headptr = addnodeatspecificpoition;
}
else
{
node* current = headptr;
int i = 1;
for (i = 1; current != NULL; i++)
{
if (i == position)
{
addnodeatspecificpoition->setnextptr(current->getNextptr());
current->setnextptr(addnodeatspecificpoition);
break;
}
current = current->getNextptr();
}
}
}
friend ostream& operator<<(ostream& output,const linkedlist& L)
{
char checkWhatInput;
int i = 1;
node* ptr = L.headptr;
while (ptr->getNextptr() != NULL)
{
++i;
checkWhatInput = ptr->checkWhichInput();
/// <summary>
switch (checkWhatInput)
{
case 'i':output <<ptr->getintData()<<endl;
break;
case 's':output << ptr->getstringData()<<endl;
break;
case 'd':output << ptr->getdoubleData() << endl;
break;
case 'c':output << ptr->getcharData() << endl;
break;
default:
break;
}
/// </summary>
/// <param name="output"></param>
/// <param name="L"></param>
/// <returns></returns>
ptr = ptr->getNextptr();
}
/// <summary>
switch (checkWhatInput)
{
case 'i':output << ptr->getintData() << endl;
break;
case 's':output << ptr->getstringData() << endl;
break;
case 'd':output << ptr->getdoubleData() << endl;
break;
case 'c':output << ptr->getcharData() << endl;
break;
default:
break;
}
/// </summary>
/// <param name="output"></param>
/// <param name="L"></param>
/// <returns></returns>
if (ptr->getNextptr() == NULL)
{
output << "\nNULL (There is no pointer left)\n";
}
return output;
}
~linkedlist() {
delete addnodeatspecificpoition;
}
};
int main()
{
linkedlist L1;
//Insertion at tail
L1.insertionAtTail(new node("dsaf"));
L1.insertionAtTail(new node("sadf"));
L1.insertionAtTail(new node("sfa"));
L1.insertionAtTail(new node(12));
L1.insertionAtTail(new node(67));
L1.insertionAtTail(new node(23));
L1.insertionAtTail(new node(45.677));
L1.insertionAtTail(new node(12.43556));
//Inserting a node at head
L1.insertionAtHead(new node(1));
//Inserting a node at any given point
L1.insertionAtAnyPoint(new node(999), 3);
cout << L1;
cout << "\nThe size of linked list after insertion of elements is : " << L1.sizeOfLinkedList();
}
The output is
1
dsaf
sadf
999
sfa
12
67
23
45.677
12.4356
Thats what you can use to create a linked list without worrying of data type
Just an FYI, In C# you can use Object as your data member.
class Node
{
Node next;
Object Data;
}
User can then use something like this to find out which Object the Node stores:
if (obj.GetType() == this.GetType()) //
{
}