C語言泛型,能夠仿照 C庫函數 qsort 的方式node
用戶提供 一些回調函數。算法
數據結構不包含數據域,數據結構
數據域 由分配節點內存的時候,多分配一些空間提供函數
數據域的地址: spa
節點指針 是 p,則數據域地址爲 p+1;指針
下面,是個簡單的單鏈表實現code
#include <stdio.h> #include <stdlib.h> #include <memory.h> ////類型定義 typedef struct LNode{ struct LNode *next; }*PLNode,*List; /// 裸節點大小 enum{NodeOnlySize =(sizeof(struct LNode))}; #define NodeSize(elmSize) (NodeOnlySize + elmSize) ////節點大小,跟元素大小相關 #define GetElem(type,p) (*(type*)(void *)(p + 1)) //// 取節點元素 //////////////////////////////////////////////////////// //// 回調函數定義 //// 1)複製函數,用於複製元素數據。 //// 2)釋放函數,用於釋放元素內部數據。 typedef void* (*copy_elm)(void *elm,const void *data,size_t elmsize); typedef void (*free_elm)(void *elm); ////產生無數據節點,能夠私有化 PLNode GenNode(int elmSize){ PLNode p = malloc(NodeSize(elmSize)); p->next =NULL; return p; } //// 建立節點 PLNode CreateNode(copy_elm cpy,void *data,int elmSize){ PLNode p =GenNode(NodeSize(elmSize)); cpy(p + 1,data,elmSize); return p; } /// 建立鏈表,建立一個只有表頭節點的鏈表 List Create(int elmSize){ return GenNode(NodeSize(elmSize)); } ///批量插入數據,批量前插 List insertFrontBulk(List lst,copy_elm cpy, int n,void *d,int elmSize){ PLNode p; int i; if(!lst) return NULL; for(i=0;i<n;i++){ p = CreateNode(cpy,d+i,elmSize); p ->next =lst ->next; lst->next = p; } return lst; } ///前插 List insertFront(List lst,copy_elm cpy, void *d,int elmSize){ PLNode p; if(!lst) return NULL; p = CreateNode(cpy,d,elmSize); p ->next =lst ->next; lst->next = p; return lst; } ///批量插入數據,批量後插 List insertBackBulk(List lst,int n,copy_elm cpy, void *d,int elmSize){ PLNode p=lst,q; int i; if(!p)return NULL; while(p->next){ p =p->next; } for(i=0;i<n;i++){ q = CreateNode(cpy,d+i,elmSize); q ->next =p ->next; p->next = q; } return lst; } ///後插 List insertBack(List lst,copy_elm cpy, void *d,int elmSize){ PLNode p=lst,q; if(!p)return NULL; while(p->next){ p =p->next; } q = CreateNode(cpy,d,elmSize); q ->next =p ->next; p->next = q; return lst; } /// 銷燬鏈表 void Destory(List lst,free_elm fre){ PLNode p =lst,q; if(!lst)return ; p = lst->next; while(p){ q = p; p = p->next; if(fre) fre(&q->next+1); free(q); } free(lst); } ///實現數據複製 void *copyint(void *dst,const void *src,size_t n){ *(int *)dst = *(int*)src; return dst; } int main() { int n=10; const int elmSize = sizeof(int); List L =Create(elmSize); PLNode p ; while(n>0){ ///insertFront(L,memcpy,&n,elmSize); insertBack(L,memcpy,&n,elmSize); --n; } p = L; while(p = p->next){ printf("data =%d\n", GetElem(int,p)); } Destory(L,NULL); printf("Hello world!\n"); getchar(); return 0; }
雙向鏈表:blog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -內存
和單向鏈表相比有如下優點:element
插入刪除不須要移動元素外,能夠原地插入刪除
能夠雙向遍歷
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
初始化+尾插法圖示://head始終指向頭結點,p指向尾節點,方便後續算法使用
刪除單個圖示:
實現代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Node pNode; struct Node { int data; pNode *prev, *next; }; /* 初始化鏈表,尾插法 */ pNode *InitList(pNode **head, int n) { pNode *p, *s; (*head) = (pNode *)malloc(sizeof(pNode)); if ((*head) == NULL) exit(0); (*head)->next = NULL;//head的prev和next均指向NULL (*head)->prev = NULL; p = (*head);//p指向head int i; for (i = 0; i < n; ++i) { s = (pNode *)malloc(sizeof(pNode)); if (s == NULL) exit(0); printf("Input the value of the %dth node:", i + 1); scanf("%d", &s->data); s->next = NULL; p->next = s; s->prev = p; p = s;//p指向尾節點 } return p; } /* 遍歷打印 */ void PrintList(pNode *head) { pNode *p; p = head->next; if (head->next == NULL) printf("the list is empty\n"); while(p != NULL) { printf("%d ", p->data); p = p->next; } printf("\n"); } /* 清空鏈表 */ void DeleteList(pNode **head) { pNode *p; while((*head)->next != NULL) { p = (*head); p->next->prev = NULL; (*head) = p->next; free(p); } } /* 查找鏈表內的某個值 */ int SearchList(pNode *head) { int number; printf("Values are about to be deleted:"); scanf("%d", &number); pNode *p; p = head->next; while(p != NULL) { if (p->data == number) { return number; } p = p->next; } return 0; } /* 刪除鏈表中某個元素,令p的前驅節點和後驅節點相互指向便可,若是p是尾節點則直接將前驅節點指向NULL*/ void DelNumqList(pNode **head, int n) { int i; pNode *p; p = (*head)->next; for (i = 1; i < n; ++i) p = p->next; if(p->next == NULL) { p->prev->next = NULL; free(p); } else { p->next->prev = p->prev; p->prev->next = p->next; free(p); } } int main(int argc, char const *argv[]) { int n, element, flag; pNode *head, *last; /***************************************************************/ printf("Please input the size of the list:"); scanf("%d", &n); last = InitList(&head, n);//初始化鏈表並賦值,返回尾節點last printf("%d %d \n", head->next->data, last->data); //打印爲第一個元素和最後一個元素 PrintList(head); /***************************************************************/ flag = SearchList(head); //搜索某個值並刪除節點 if (flag > 0 && flag <= n) { DelNumqList(&head, flag); PrintList(head); } else printf("Element does not exist, cannot be deleted\n"); /***************************************************************/ DeleteList(&head);//清空列表 PrintList(head); return 0; }