数据结构C语言——双向链表及其实现

双向链表

双向环链(非环连只需将尾部与头节点断开即可)

组成:每个节点主要包含三个部分,数据域、前驱指针、后继指针。

分类:带头结点的和无头结点的。

  • 带头结点的双向环链

实现目的,写一个针对不同数据的双向的库。

链表指针操作小贴士:假设链表节点内有三部分组成,数据域,前驱指针,后继指针三部分,现在在双向链表中有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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值