C语言泛型,可以仿照 C库函数 qsort 的方式
用户提供 一些回调函数。
数据结构不包含数据域,
数据域 由分配节点内存的时候,多分配一些空间提供
数据域的地址:
节点指针 是 p,则数据域地址为 p+1;
下面,是个简单的单链表实现
#include
#include
#include
类型定义
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
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
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;
}
双向链表:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
和单向链表相比有以下优势:
插入删除不需要移动元素外,可以原地插入删除
可以双向遍历
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
初始化+尾插法图示://head始终指向头结点,p指向尾节点,方便后续算法使用
删除单个图示:
实现代码:
#include
#include
#include
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;
}
运行:
$ gcc -o linkList2 linkList2.c
$ ./linkList2
Please input the size of the list:8
Input the value of the 1th node:12
Input the value of the 2th node:1
Input the value of the 3th node:13
Input the value of the 4th node:4
Input the value of the 5th node:16
Input the value of the 6th node:7
Input the value of the 7th node:29
Input the value of the 8th node:-11
12 -11
12 1 13 4 16 7 29 -11