C语言 泛型链表的实现
生活随笔
收集整理的這篇文章主要介紹了
C语言 泛型链表的实现
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
參考文章:使用C語(yǔ)言實(shí)現(xiàn)“泛型”鏈表
文章目錄
- jiang工給的泛型鏈表例子,有點(diǎn)看不怎么懂,自己寫(xiě)個(gè)看看:
- 實(shí)現(xiàn)方法
- 方法1:鏈表指針指向整個(gè)結(jié)點(diǎn),結(jié)點(diǎn)中存放指向數(shù)據(jù)的指針
- 方法2:結(jié)構(gòu)體數(shù)據(jù)作為結(jié)點(diǎn),結(jié)點(diǎn)中存放指向prev、next的指針(好像這樣的話結(jié)構(gòu)體數(shù)據(jù)確實(shí)不能直接作為結(jié)點(diǎn))
jiang工給的泛型鏈表例子,有點(diǎn)看不怎么懂,自己寫(xiě)個(gè)看看:
#include <stdio.h> struct list_head {struct list_head *next, *prev; };#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)//根據(jù)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; }實(shí)現(xiàn)方法
有一點(diǎn)懵逼,我的思路是,在結(jié)點(diǎn)中的數(shù)據(jù)域存放指向自定義數(shù)據(jù)結(jié)構(gòu)的指針
另一種思路是在自定義數(shù)據(jù)結(jié)構(gòu)中存放prev和next指針
思考一個(gè)問(wèn)題,是先有數(shù)據(jù),我們把數(shù)據(jù)串起來(lái)就,成了鏈表?
還是先有鏈表,我們?cè)賹?shù)據(jù)一個(gè)個(gè)放進(jìn)去?(好無(wú)聊的問(wèn)題( ̄、 ̄))
那么我自己實(shí)現(xiàn)兩個(gè)版本吧,其中一個(gè)版本是鏈表指針指向整個(gè)結(jié)點(diǎn),結(jié)點(diǎn)中存放指向數(shù)據(jù)的指針;另一個(gè)版本是將數(shù)據(jù)作為結(jié)點(diǎn),像jianggong寫(xiě)的那樣,但是可以將mylist(包含prev和next指針)寫(xiě)在最上面,這樣就不必用相對(duì)地址去計(jì)算了
方法1:鏈表指針指向整個(gè)結(jié)點(diǎn),結(jié)點(diǎn)中存放指向數(shù)據(jù)的指針
#include <stdio.h> #include <stdlib.h> #include <String.h>//定義結(jié)點(diǎn) struct Node {void* data;struct Node* prev;struct Node* next; };//尾插結(jié)點(diǎn) 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;} }//刪除結(jié)點(diǎ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("成功刪除結(jié)點(diǎn)!\n");return;//}}}else {h = h->next;}}printf("沒(méi)有找到要?jiǎng)h除的結(jié)點(diǎn)!\n"); }int main() {//創(chuàng)建鏈表Node header_task1 = { NULL, &header_task1, &header_task1 };//定義自定義結(jié)構(gòu)體struct User{char name[20];char phone[20];};//創(chuàng)建自定義結(jié)構(gòu)體u1(不是用malloc動(dòng)態(tài)分配堆空間,不用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_task1for (Node* node = header_task1.next; node->data != NULL; node = node->next) {printf("姓名:%s\t電話號(hào)碼:%s\n", ((User*)node->data)->name, ((User*)node->data)->phone);}//刪除某個(gè)結(jié)點(diǎn)list_del(&header_task1, &u1);//成功list_del(&header_task1, &u1);//沒(méi)有找到//遍歷//條件也可以是:node != &header_task1for (Node* node = header_task1.next; node->data != NULL; node = node->next) {printf("姓名:%s\t電話號(hào)碼:%s\n", ((User*)node->data)->name, ((User*)node->data)->phone);}return 0; }運(yùn)行結(jié)果:
姓名:唐三藏 電話號(hào)碼:18944443333 姓名:白骨精 電話號(hào)碼:18922223333 姓名:豬八戒 電話號(hào)碼:18911113333 姓名:牛魔王 電話號(hào)碼:18900003333 成功刪除結(jié)點(diǎn)! 沒(méi)有找到要?jiǎng)h除的結(jié)點(diǎn)! 姓名:白骨精 電話號(hào)碼:18922223333 姓名:豬八戒 電話號(hào)碼:18911113333 姓名:牛魔王 電話號(hào)碼:18900003333方法2:結(jié)構(gòu)體數(shù)據(jù)作為結(jié)點(diǎn),結(jié)點(diǎn)中存放指向prev、next的指針(好像這樣的話結(jié)構(gòu)體數(shù)據(jù)確實(shí)不能直接作為結(jié)點(diǎn))
#include <stdio.h> #include <stdlib.h> #include <String.h>struct list_head {struct list_head* next;struct list_head* prev; };//尾插結(jié)點(diǎn) 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; }//刪除結(jié)點(diǎn) 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;//刪除結(jié)點(diǎn)也用不到tmp(只有單向鏈表增刪才用到tmp吧!)printf("刪除結(jié)點(diǎn)成功!\n");}} }int main() {//創(chuàng)建鏈表list_head header_task1 = {&header_task1, &header_task1 };//定義自定義結(jié)構(gòu)體struct User{char name[20];char phone[20];list_head my_list;};//創(chuàng)建自定義結(jié)構(gòu)體u1(不是用malloc動(dòng)態(tài)分配堆空間,不用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 刪除結(jié)點(diǎn)成功! 姓名:白骨精 電話:18922223333 姓名:豬八戒 電話:18911113333 姓名:牛魔王 電話:18900003333總結(jié)
以上是生活随笔為你收集整理的C语言 泛型链表的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C语言数据结构(大话数据结构——笔记1)
- 下一篇: C语言malloc动态分配内存分配失败怎