C语言实现泛型链表,C语言泛型初探----C链表

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指向尾节点,方便后续算法使用

39cadb5154cc09d53b0197d896c9fdbb.png

删除单个图示:

219d1f5d60f82a789345a7a91c9453ad.png

实现代码:

#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值