views:

740

answers:

9

Hi All, This is just another interview question-------

Can we have a linked list of different data types i.e each elements in a linked list can have different structure or union elements.If its possible can u please explain me with an example.

Thanks and regards Maddy

+1  A: 

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.

Robert
+10  A: 

You could use a general pointer in your nodes (void*), and put a pointer to any object into it :) Of course you should have some way of checking what is the type of the stored object. So you could use something like this:

struct node {
    void * data;
    int type;
    struct node * next;
};

That should work. But code for checking can be tricky.

Marcin Cylke
+8  A: 

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.

Goz
A: 

You can do this by placing the pointer first in the structures, unlike the usual convention of it being last:

struct anode {
    void * next;
    // ... other stuff
}
struct bnode {
    void * next;
    // ... other stuff
}

But this gets really awkward to use due to the casts required.

EDIT: You can mitigate the casts using Goz's idea.

You could also do this:

struct anode {
    struct anode * next;
    void * data;
    int type;
}

The main difference is that, with the first one, the data is stored directly in the nodes. With the second approach, the data is stored elsewhere. This may or may not be important due to cache issues...

Martinho Fernandes
A: 

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.

neuro
A: 

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/

smcameron
A: 

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()) //
{

}

Learner
You can do that in Java, too, which has about as much to do with C as C# does ;-)
Steve Jessop
+2  A: 

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.

John Bode
A: 

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