C语言 泛型链表的实现
Posted Dontla
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言 泛型链表的实现相关的知识,希望对你有一定的参考价值。
文章目录
jiang工给的泛型链表例子,有点看不怎么懂,自己写个看看:
#include <stdio.h>
struct list_head {
struct list_head *next, *prev;
};
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
//根据structd的成员获取struct的地址
#define container_of(ptr, type, member) ((type *)(((char *)ptr) - (int)(&(((type*)0)->member))))
//链表遍历
#define list_for_each(pos, head) \\
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_prev(pos, head) \\
for (pos = (head)->prev; pos != (head); pos = pos->prev)
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \\
struct list_head name = LIST_HEAD_INIT(name)
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
typedef struct _student {
int data ;
struct list_head mylist;
}student;
int main()
{
LIST_HEAD(header_task);
student s1 ={.data =1};
student s2 ={.data =2};
student s3 ={.data =3};
struct list_head* pos;
student* s;
list_add(&s1.mylist,&header_task);
list_add(&s2.mylist,&header_task);
list_add(&s3.mylist,&header_task);
list_for_each(pos, &header_task){
s = container_of(pos, student, mylist);
printf("data is %d\\n",s->data);
}
printf("----------\\n");
list_del(&s2.mylist);
list_for_each(pos, &header_task){
s = container_of(pos, student, mylist);
printf("data is %d\\n",s->data);
}
printf("Hello World!\\n");
return 0;
}
实现方法
有一点懵逼,我的思路是,在结点中的数据域存放指向自定义数据结构的指针
另一种思路是在自定义数据结构中存放prev和next指针
思考一个问题,是先有数据,我们把数据串起来就,成了链表?
还是先有链表,我们再将数据一个个放进去?(好无聊的问题( ̄、 ̄))
那么我自己实现两个版本吧,其中一个版本是链表指针指向整个结点,结点中存放指向数据的指针;另一个版本是将数据作为结点,像jianggong写的那样,但是可以将mylist(包含prev和next指针)写在最上面,这样就不必用相对地址去计算了
方法1:链表指针指向整个结点,结点中存放指向数据的指针
#include <stdio.h>
#include <stdlib.h>
#include <String.h>
//定义结点
struct Node
{
void* data;
struct Node* prev;
struct Node* next;
};
//尾插结点
void list_add_tail(Node* p, void* e) {
struct Node* n = (Node*)malloc(sizeof(Node));
if (NULL != n) {
n->data = e;
Node* tmp = p->prev;
p->prev = n;
n->prev = tmp;
n->next = p;
tmp->next = n;
}
}
//删除结点
void list_del(Node* h, void* u) {
while (NULL != h->next->data) {
if (u == h->next->data) {
Node* tmp = h->next;
h->next = h->next->next;
h->next->prev = h;
if (NULL != tmp) {
//if (NULL != tmp->data) {
//free(tmp->data);
free(tmp);
printf("成功删除结点!\\n");
return;
//}
}
}
else {
h = h->next;
}
}
printf("没有找到要删除的结点!\\n");
}
int main() {
//创建链表
Node header_task1 = { NULL, &header_task1, &header_task1 };
//定义自定义结构体
struct User
{
char name[20];
char phone[20];
};
//创建自定义结构体u1(不是用malloc动态分配堆空间,不用free)
User u1 = { "唐三藏", "18944443333" };
User u2 = { "白骨精", "18922223333" };
User u3 = { "猪八戒", "18911113333" };
User u4 = { "牛魔王", "18900003333" };
//尾插
list_add_tail(&header_task1, &u1);
list_add_tail(&header_task1, &u2);
list_add_tail(&header_task1, &u3);
list_add_tail(&header_task1, &u4);
//遍历
//条件也可以是:node != &header_task1
for (Node* node = header_task1.next; node->data != NULL; node = node->next) {
printf("姓名:%s\\t电话号码:%s\\n", ((User*)node->data)->name, ((User*)node->data)->phone);
}
//删除某个结点
list_del(&header_task1, &u1);//成功
list_del(&header_task1, &u1);//没有找到
//遍历
//条件也可以是:node != &header_task1
for (Node* node = header_task1.next; node->data != NULL; node = node->next) {
printf("姓名:%s\\t电话号码:%s\\n", ((User*)node->data)->name, ((User*)node->data)->phone);
}
return 0;
}
运行结果:
姓名:唐三藏 电话号码:18944443333
姓名:白骨精 电话号码:18922223333
姓名:猪八戒 电话号码:18911113333
姓名:牛魔王 电话号码:18900003333
成功删除结点!
没有找到要删除的结点!
姓名:白骨精 电话号码:18922223333
姓名:猪八戒 电话号码:18911113333
姓名:牛魔王 电话号码:18900003333
方法2:结构体数据作为结点,结点中存放指向prev、next的指针(好像这样的话结构体数据确实不能直接作为结点)
#include <stdio.h>
#include <stdlib.h>
#include <String.h>
struct list_head {
struct list_head* next;
struct list_head* prev;
};
//尾插结点
void list_add_tail(list_head* head, list_head* new_node) {
/*list_head* tmp = head->prev;
head->prev = new_node;
new_node->prev = tmp;
tmp->next = new_node;
new_node->next = head;*/
//根本不用temp啊!
head->prev->next = new_node;
new_node->prev = head->prev;
head->prev = new_node;
new_node->next = head;
}
//删除结点
void list_del(list_head* head, list_head* del) {
list_head* i = head;
for (i = i->next; i != head; i = i->next) {
if (i == del) {
i->prev->next = i->next;
i->next->prev = i->prev;
//删除结点也用不到tmp(只有单向链表增删才用到tmp吧!)
printf("删除结点成功!\\n");
}
}
}
int main() {
//创建链表
list_head header_task1 = {&header_task1, &header_task1 };
//定义自定义结构体
struct User
{
char name[20];
char phone[20];
list_head my_list;
};
//创建自定义结构体u1(不是用malloc动态分配堆空间,不用free)
User u1 = { "唐三藏", "18944443333", {NULL, NULL} };
User u2 = { "白骨精", "18922223333", {NULL, NULL} };
User u3 = { "猪八戒", "18911113333", {NULL, NULL} };
User u4 = { "牛魔王", "18900003333", {NULL, NULL} };
//尾插
list_add_tail(&header_task1, &u1.my_list);
list_add_tail(&header_task1, &u2.my_list);
list_add_tail(&header_task1, &u3.my_list);
list_add_tail(&header_task1, &u4.my_list);
list_head* pos1;
User* u;
//遍历
for (pos1 = header_task1.next; pos1 != &header_task1; pos1 = pos1->next) {
u = (User*)((int)pos1 - (int)&(((User*)0)->my_list));
printf("姓名:%s\\t电话:%s\\t\\n", u->name, u->phone);
}
//删除
list_del(&header_task1, &u1.my_list);
for (pos1 = header_task1.next; pos1 != &header_task1; pos1 = pos1->next) {
u = (User*)((int)pos1 - (int)&(((User*)0)->my_list));
printf("姓名:%s\\t电话:%s\\t\\n", u->name, u->phone);
}
return 0;
}
姓名:唐三藏 电话:18944443333
姓名:白骨精 电话:18922223333
姓名:猪八戒 电话:18911113333
姓名:牛魔王 电话:18900003333
删除结点成功!
姓名:白骨精 电话:18922223333
姓名:猪八戒 电话:18911113333
姓名:牛魔王 电话:18900003333
以上是关于C语言 泛型链表的实现的主要内容,如果未能解决你的问题,请参考以下文章