目录
一、图例
1.基本图例
2.插入结点
3.删除结点
二、根据用户需求对链表进行操作
1. llist.h文件中宏定义
#ifndef __LLIST_H__
#define __LLIST_H__
#define LLIST_FORWARD 1
#define LLIST_BACKWARD 2
typedef void llist_op(void *);
typedef int llist_cmp(const void *, const void *);
struct llist_node_st //初始化结构体 常规结点类型
{
struct llist_node_st *prev,*next;
char data[1];
};
typedef struct //头节点类型
{
int size;
struct llist_node_st head;
}LLIST;
LLIST* llist_create(int size);
int llist_insert(LLIST *, const void *data,int mode);
int llist_delete(LLIST*, const void *key, llist_cmp *cmp);
int llist_fetch(LLIST*, const void *key, llist_cmp *cmp,void *data);
void *llist_find(LLIST *,const void *key,llist_cmp *cmp);
void llist_travel(LLIST *, llist_op *op);
void llist_destroy(LLIST *);
#endif
2. llist.c文件中创建头节点函数
LLIST* llist_create(int size)
{
LLIST *new;
new = malloc(sizeof(*new));
if(new == NULL)
return NULL;
new->size = size; //头节点中size大小根据用户需求设定
new->head.prev = new->head.next = &new->head; //让头结点的前驱和后继都指向自己
return new;
}
3. llist.c插入结点函数
int llist_insert(LLIST *ptr, const void *data,int mode)
{
struct llist_node_st *newnode;
newnode = malloc(sizeof(*newnode) + ptr->size);
if(newnode == NULL)
return -1;
memcpy(newnode->data, data, ptr->size); //将传入的data赋值到新结点中的data中
if(mode == LLIST_FORWARD) //头部插入
{
newnode->prev = &ptr->head; //新结点的前驱是头结点中的head
newnode->next = ptr->head.next; //新结点的后继是头结点 head原来指向的后继结点
}
else
{
if(mode == LLIST_BACKWARD) //尾部插入
{
newnode->prev = ptr->head.prev; //新结点的前驱是头结点 head原来指向的前驱结点
newnode->next = &ptr->head; //新结点的后继是头结点中的head
}
else
return -3;
}
newnode->prev->next = newnode; //新结点前驱的后继是新结点
newnode->next->prev = newnode; //新结点后继的前驱是新结点
return 0;
}
4.llist.c查找结点函数
struct llist_node_st *find_(LLIST *ptr,const void *key,llist_cmp *cmp)
{
struct llist_node_st *cur;
for(cur = ptr->head.next; cur != &ptr->head ; cur = cur->next)
{
if(cmp(key, cur->data) == 0) //调用比较函数,在链表中进行查找
break;
}
return cur; 将找到的结点返回
}
void *llist_find(LLIST *ptr,const void *key,llist_cmp *cmp)
{
struct llist_node_st *node;
node = find_(ptr,key,cmp); //找到结点
if(node == &ptr->head) //判断不是头结点
return NULL;
else
return node->data; //返回找到结点中的数据
}
5.llist中删除结点函数
int llist_delete(LLIST *ptr, const void *key, llist_cmp *cmp)
{
struct llist_node_st *node;
node = find_(ptr,key,cmp); //找到要删除的结点
if(node == &ptr->head)
return -1;
node->prev->next = node->next; //将要删除结点前驱的后继指向要删除结点的后继
node->next->prev = node->prev; //将要删除结点后继的前驱指向要删除结点的前驱
free(node); //将要删除的结点释放
return 0;
}
6.llist中删除结点并进行回显
int llist_fetch(LLIST* ptr, const void *key, llist_cmp *cmp,void *data)
{
struct llist_node_st *node;
node = find_(ptr,key,cmp); //找到要删除的结点
if(node == &ptr->head)
return -1;
node->prev->next = node->next; //将要删除结点前驱的后继指向要删除结点的后继
node->next->prev = node->prev; //将要删除结点后继的前驱指向要删除结点的前驱
memcpy(data, node->data, ptr->size); //将要删除结点中的data赋值给data
free(node); //释放要被删除的结点
return 0;
}
7.llist中遍历函数
void llist_travel(LLIST *ptr, llist_op *op)
{
struct llist_node_st *cur;
for(cur = ptr->head.next; cur != &ptr->head ; cur = cur->next)
op(cur->data); //调用输出函数,输出结点中data的数据
}
8.llist中销毁结点函数
void llist_destroy(LLIST *ptr)
{
struct llist_node_st *cur,*next;
for(cur = ptr->head.next; cur != &ptr->head ; cur = next)
{
next = cur->next;
free(cur);
} //循环销毁普通结点
free(ptr); //销毁头结点
}
9.main函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "llist.h"
#define NAMESIZE 32
struct score_st
{
int id;
char name[NAMESIZE];
int math;
}; //用户想要在链表中操作的数据
void print_s(void *data) //定义输出函数
{
struct score_st *d = data;
printf("%d %s %d\n",d->id, d->name, d->math);//将传回来的结构体类型的参数进行输出
}
int id_cmp(const void *key, const void *data) //比较id
{
const int *k = key;
const struct score_st *d = data;
return *k - d->id; //将用户输入的id和链表中data中的id进行比较,0表示成功找到
}
int name_cmp(const void *key, const void *data) 比较name
{
const char *k = key;
const struct score_st *d = data;
return strcmp(k, d->name); //将用户输入的name和链表中data中的name进行比较,0表示成功找到
}
int main()
{
LLIST *handler;
struct score_st tmp;
int i;
handler = llist_create(sizeof(struct score_st));
if(handler == NULL)
{
printf("llist_create() failed.\n");
exit(1);
}
for(i = 0 ; i < 7 ; i++)
{
tmp.id = i;
tmp.math = 100-i;
snprintf(tmp.name, NAMESIZE,"STU%d",i);
llist_insert(handler, &tmp, LLIST_BACKWARD); //调用插入结点函数,在尾部插入
}
llist_travel(handler,print_s); //调用遍历函数,对链表中的data进行输出
printf("\n\n");
int findid = 2;
char *findname = "STU4";
struct score_st *retp;
/*
//retp = llist_find(handler,&findid,id_cmp); //通过id找
retp = llist_find(handler,findname,name_cmp); //通过name找
if(retp)
print_s(retp);
else
printf("Can not find.\n");
*/
// llist_delete(handler,&findid,id_cmp); //通过id找删除结点
if(llist_fetch(handler,&findid,id_cmp,&tmp) == 0)
print_s(&tmp); //通过id找删除结点并回显删除结点中的数据
printf("\n\n");
llist_travel(handler,print_s);
llist_destroy(handler); //销毁结点
exit(0);
}
注:本文是通过听李慧芹老师上课记的笔记,如有理解不到位请多多包涵,也请多多指教