双向链表
双向环链(非环连只需将尾部与头节点断开即可)
组成:每个节点主要包含三个部分,数据域、前驱指针、后继指针。
分类:带头结点的和无头结点的。
- 带头结点的双向环链
实现目的,写一个针对不同数据的双向的库。
链表指针操作小贴士:假设链表节点内有三部分组成,数据域,前驱指针,后继指针三部分,现在在双向链表中有A、B两个相邻的节点,即A的后继指向B,B的前驱指向A。此时要在AB中插入节点N,如何快捷简单地操作指针?
首先,将节点N接入到A,B之间,将N的前驱指向A,N的后继指向B,这一步很简单;接下来将有一个很奇幻的操作,将N的前驱的后继指向N,N的后继的前驱指向N,这样就完成了指针变换的操作。第二步发生了什么?首先当第一步将N的前驱指向A,那么N的前驱的后继就是A的后继,将N的前驱的后继指向N也就是将A的后继指向N,剩下的部分同理,这样就避免了对A,B节点指针的多余操作,减小了出错的概率,另外从逻辑上分析N的前驱的后继也确实是N,这样就确保了指针操作的逻辑正确性。
makefile
all:llist
llist:llist.o main.o
$(CC) $^ -o $@
clean:
rm *.o llist -rf
llist.h
#ifndef LLIST_H__
#define LLIST_H__
#define LLIST_FORWARD 0x0
#define LLIST_BACKWARD 0x1
typedef void llist_op(const void *);
typedef int llist_cmp(const void *, const void *);
struct llist_node_st{
void *data;
struct llist_node_st *prev;
struct llist_node_st *next;
};
typedef struct {
int size;
struct llist_node_st head;
}LLIST;
LLIST *llist_creat(int size);
int llist_insert(LLIST *, const void *data, unsigned char mode);
void *llist_find(LLIST *, const void *key, llist_cmp *);
int llist_delete(LLIST *, const void *key, llist_cmp *);
int llist_fetch(LLIST *, const void *key, llist_cmp *, void *data);
void llist_travel(LLIST *, llist_op *);
void llist_destroy(LLIST *);
#endif
llist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "llist.h"
LLIST *llist_creat(int size){
LLIST *new;
new = malloc(sizeof(*new));
if(new == NULL){
return NULL;
}
new->size = size;
new->head.data = NULL;
new->head.prev = &new->head;
new->head.next = &new->head;
return new;
}
int llist_insert(LLIST *ptr, const void *data, unsigned char mode){
struct llist_node_st *newnode;
newnode = malloc(sizeof(*newnode));
if(newnode == NULL){
return -1;
}
newnode->data = malloc(ptr->size);
if(newnode->data == NULL){
return -2;
}
memcpy(newnode->data, data, ptr->size);
if(mode == LLIST_FORWARD){
newnode->prev = &ptr->head;
newnode->next = ptr->head.next;
}
else if(mode == LLIST_BACKWARD){
newnode->prev = ptr->head.prev;
newnode->next = &ptr->head;
}
else{
return -3;
}
newnode->next->prev = newnode;
newnode->prev->next = newnode;
return 0;
}
static struct llist_node_st *find_(LLIST *ptr, const void *key, llist_cmp *cmp){
struct llist_node_st *cur = NULL;
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){
return find_(ptr, key, cmp)->data;
}
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->data);
free(node);
return 0;
}
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;
if(node->data != NULL){
//memset(data, 0, ptr->size);
memcpy(data, node->data, ptr->size);
}
free(node->data);
free(node);
return 0;
}
void llist_travel(LLIST *ptr, llist_op *op){
struct llist_node_st *cur, *next;
for(cur = ptr->head.next; cur != &ptr->head; cur = cur->next){
op(cur->data);
}
}
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->data);
free(cur);
}
free(ptr);
ptr = NULL;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "llist.h"
#define NAMESIZE 32
typedef struct score_st SCORE;
struct score_st{
int id;
char name[NAMESIZE];
int math;
int chinese;
};
void print_s(const void *record){
const SCORE *r = record;
printf("%d %s %d %d\n", r->id, r->name, r->math, r->chinese);
}
static int id_cmp(const void *key, const void *record){
const int *k = key;
const SCORE *r = record;
return (*k - r->id);
}
static int name_cmp(const void *key, const void *record){
const char *k = key;
const SCORE *r = record;
return strcmp(k, r->name);
}
int main(){
LLIST *handler;
SCORE tmp, *data = NULL;
int ret, id = 3;
char *del_name = "stu6";
handler = llist_creat(sizeof(SCORE));
if(handler == NULL){
exit(-1);
}
for(int i = 0; i < 7; i++){
tmp.id = i;
snprintf(tmp.name, NAMESIZE, "stu%d", i);
tmp.math = rand() % 100;
tmp.chinese = rand() % 100;
ret = llist_insert(handler, &tmp, LLIST_BACKWARD);
if(ret){
exit(-1);
}
}
llist_travel(handler, print_s);
printf("\n\n");
data = llist_find(handler, &id, id_cmp);
if(data == NULL){
printf("Can not find!\n");
}
else{
print_s(data);
}
printf("\n\n");
ret = llist_delete(handler, del_name, name_cmp);
if(ret){
printf("llist_deleter failed!\n");
}
llist_travel(handler, print_s);
printf("\n\n");
data = malloc(sizeof(*data));
memset(data, 0, sizeof(*data));
llist_fetch(handler, &id, id_cmp, data);
if(data == NULL){
printf("llist_deleter failed!\n");
}
else{
print_s(data);
}
printf("\n\n");
llist_travel(handler, print_s);
llist_destroy(handler);
return 0;
}
测试结果
wangs7_@WangQ7:~/Cprogram/double/lib1$ ./llist
0 stu0 83 86
1 stu1 77 15
2 stu2 93 35
3 stu3 86 92
4 stu4 49 21
5 stu5 62 27
6 stu6 90 59
3 stu3 86 92
0 stu0 83 86
1 stu1 77 15
2 stu2 93 35
3 stu3 86 92
4 stu4 49 21
5 stu5 62 27
3 stu3 86 92
0 stu0 83 86
1 stu1 77 15
2 stu2 93 35
4 stu4 49 21
5 stu5 62 27