这只是另一个采访问题。
我们是否可以拥有不同数据类型的链表,即链表中的每个元素都可以有不同的结构或联合元素?如果有可能请您举例解释一下?
答案 0 :(得分:15)
使用union创建数据类型
union u_tag{
char ch;
int d;
double dl;
};
struct node {
char type;
union u_tag u;
struct node *next;
};
使用struct node创建链接列表。 type决定数据的数据类型是什么。
Harsha T,班加罗尔
答案 1 :(得分:14)
在链接列表中,您不必将类似结构链接在一起。只要他们有适当的前进和/或后退指针你就可以了。例如:
struct BaseLink
{
BaseLink* pNext;
BaseLink* pPrev;
int typeId;
};
struct StringLink
{
BaseLink baseLink;
char* pString;
};
struct IntLink
{
BaseLink baseLink;
int nInt;
};
这样你就有了一个从BaseLink到BaseLink的链表。额外的数据不是问题。你想看到它作为StringLink?然后将BaseLink转换为StringLink。
请记住,你需要某种形式的typeid,所以当你到达时,你知道要把它投射到什么地方。
答案 2 :(得分:7)
您可以使用联合类型:
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;
};
我探索的另一种方法是对数据使用void *并将指针附加到处理类型感知内容的函数:
/**
* 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;
}
显然,我在这个例子中省略了一些错误检查和处理代码,我不怀疑它有很多问题,但它应该是说明性的。
答案 3 :(得分:1)
您可以让链接列表中的每个节点都具有指向您的数据的void *。由您决定指针指向的数据类型取决于您。
答案 4 :(得分:1)
如果您不想通过联合解决方案指定列表中每个节点的类型,您始终只需将数据存储在char *中,并将类型特定的函数指针作为参数进行输入 - 敏感操作,例如打印或排序列表。 这样您就不必担心哪个节点属于哪种类型,只需按照您喜欢的方式投放数据。
/* 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));
答案 5 :(得分:1)
是的,我这样做是通过将列表的元素值定义为无效指针 void*
。
为了知道存储在列表的每个元素中的类型,我在那里也有一个.type
字段,所以我知道如何取消引用指针指向每个元素的内容。
struct node {
struct node* next;
int type;
void* value;
};
以下是一个完整的例子:
//
// 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;
}
预期产出:
- INTEGER: 1
- STRING: anyfing, anyfing!
- TYPE_PERSON: Angel (35)
- BOOLEAN (true:1, false:0): 1
答案 6 :(得分:0)
如上所述,你可以让这个问题的节点有一个void *。我建议使用一些东西来了解你的类型:
typedef struct
{
/* linked list stuff here */
char m_type;
void* m_data;
}
Node;
请参阅this question。
答案 7 :(得分:0)
实际上,您不必将指针放在结构中,您可以将它放在任何位置,然后使用containerof()宏找到结构的开头。 Linux内核使用其链表进行此操作。
答案 8 :(得分:0)
我使用我编写的这些宏来制作一般链表。您只需创建自己的结构,并在某处使用宏list_link
作为结构的成员。给该宏指定一个命名结构的参数(不带struct
关键字)。这实现了没有虚节点的双链表(例如,最后节点链接回第一节点)。锚是指向第一个节点的指针,该节点由list_init(anchor)
初始化,通过给它左值(一个解除引用它的指针是左值)。然后,您可以使用标头中的其他宏。阅读有关每个可用宏功能的注释的来源。这是在宏中实现的100%。
答案 9 :(得分:0)
是的,可以在我设计的链表中插入任何数据类型值,并且这样做非常简单。我使用了不同的node和boolean变量构造函数来检查要插入哪种类型的值,然后根据我程序中的值进行操作和命令。
//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();
}
输出为
1
dsaf
sadf
999
sfa
12
67
23
45.677
12.4356
那就是您可以用来创建链接列表而无需担心数据类型的
答案 10 :(得分:-1)
仅供参考,在C#中,您可以使用Object
作为数据成员。
class Node
{
Node next;
Object Data;
}
然后,用户可以使用以下内容查找Object
个Node
商店:
if (obj.GetType() == this.GetType()) //
{
}