【数据结构】带有头节点的双向循环链表

1. double_list.h

#ifndef __DOUBLE_LIST_H__
#define __DOUBLE_LIST_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct list_node_s {
    char *data;
    int data_count;
} list_node_t;

typedef struct double_list_s {
    struct double_list_s *prev;
    struct double_list_s *next;
    list_node_t *node;
} double_list_t;

double_list_t *init_list();
int is_list_empty(const double_list_t *head);
int get_list_size(const double_list_t *head);
void print_list_info(const double_list_t *head);
void push_front(double_list_t *head, const char *data);
void push_back(double_list_t *head, const char *data);
void insert(double_list_t *pos, const char *data);
void pop_front(double_list_t *head);
void pop_back(double_list_t *head);
void erase(double_list_t *pos);
void remove_list_by_data(double_list_t *head, const char *data);
void remove_list_by_all_data(double_list_t *head, const char *data);
void destroy_list(double_list_t *head);

#ifdef __cplusplus
}
#endif

#endif // __DOUBLE_LIST_H__

2. double_list.c

#include "double_list.h"

static int s_list_size = 0;

static double_list_t *create_list_node(const char *data)
{
    double_list_t *new_list = NULL;

    do {
        new_list = (double_list_t *)calloc(1, sizeof(double_list_t));
        if (NULL == new_list) {
            perror("calloc new_list fail");
            break;
        }

        list_node_t *new_node = NULL;
        new_node = (list_node_t *)calloc(1, sizeof(list_node_t));
        if (NULL == new_node) {
            perror("calloc new_node fail");
            if (new_list) {
                free(new_list);
                new_list = NULL;
            }

            break;
        }

        new_node->data = (char *)calloc(1, strlen(data) + 1);
        if (NULL == new_node->data) {
            perror("calloc new_node->data fail");
            if (new_node) {
                free(new_node);
                new_node = NULL;
            }
            if (new_list) {
                free(new_list);
                new_list = NULL;
            }

            break;
        }

        new_node->data_count = ++s_list_size;
        strcpy(new_node->data, data);
        new_list->node = new_node;
        new_list->prev = NULL;
        new_list->next = NULL;
    } while (0);

    return new_list;
}

// 返回 double_list_t *,可以避免 传入 二级指针
double_list_t *init_list()
{
    char *null_data = "null_data";
 
    // 头结点存储的数据无效,这里暂用 "null_data" 表示
    double_list_t *head = create_list_node(null_data);
    head->prev = head;
    head->next = head;

    return head;
}

int is_list_empty(const double_list_t *head)
{
    if (NULL == head) {
        return 1;
    }

    double_list_t *prev_list = head->prev;
    double_list_t *next_list = head->next;
    return head == prev_list && head == next_list;
}

int get_list_size(const double_list_t *head)
{
    int list_size = 0;

    if (head && head->next && head->next->node) {
        list_size = head->next->node->data_count;
    }

    return list_size;
}

void print_list_info(const double_list_t *head)
{
    if (NULL == head) {
        return;
    }

    if (head->node) {
        printf("\t%-s -> ", head->node->data);
    }

    const double_list_t *cur = head;
    for (cur = head->next; cur != head; cur = cur->next) {
        if (cur->node) {
            printf("%-s -> ", cur->node->data);
        }
    }

    if (cur->node) {
        printf("%-s\n", cur->node->data);
    }
}

void push_front(double_list_t *head, const char *data)
{
#ifndef USE_INTERNEL
    double_list_t *new_list = create_list_node(data);
    if (NULL == new_list || NULL == head) {
        return;
    }

    // 找到头节点的下一个节点
    double_list_t *next_list = head->next;
    head->next = new_list;
    new_list->prev = head;
    new_list->next = next_list;
    next_list->prev = new_list;
#else
    insert(head->next, data);
#endif /// USE_INTERNEL
}

// 这里使用一级指针即可,因为不需要修改头结点指针。
void push_back(double_list_t *head, const char *data)
{
#ifndef USE_INTERNEL
    double_list_t *new_list = create_list_node(data);
    if (NULL == new_list || NULL == head) {
        return;
    }

    // 找到尾结点,实际上就是 头结点的 prev
    double_list_t *tail_list = head->prev;
    tail_list->next = new_list;
    new_list->prev = tail_list;
    new_list->next = head;
    head->prev = new_list;
#else
    insert(head->prev, data);
#endif /// USE_INTERNEL
}

// 在 pos 前插入节点
void insert(double_list_t *pos, const char *data)
{
    double_list_t *new_list = create_list_node(data);
    if (NULL == new_list || NULL == pos) {
        return;
    }

    double_list_t *pos_prev_list = pos->prev;
    pos_prev_list->next = new_list;
    new_list->prev = pos_prev_list;
    new_list->next = pos;
    pos->prev = new_list;
}

static double_list_t *find_list_by_data(double_list_t *head, const char *data)
{
    if (is_list_empty(head) || NULL == data) {
        return NULL;
    }

    double_list_t *cur = head;
    for (cur = head->next; head != cur; cur = cur->next) {
        if (cur->node) {
            if (0 == strcmp(cur->node->data, data)) {
                return cur;
            }
        }
    }

    return NULL;
}

static void free_list_node(double_list_t *pos)
{
    if (NULL == pos) {
        return;
    }

    if (pos->node && pos->node->data) {
        pos->node->data_count -= 1;
        free(pos->node->data);
        pos->node->data = NULL;
        free(pos->node);
        pos->node = NULL;
    }

    free(pos);
    pos = NULL;
}

void pop_front(double_list_t *head)
{
    if (NULL == head || is_list_empty(head)) {
        return;
    }

#ifndef USE_INTERNEL
    double_list_t *next_list = head->next;
    double_list_t *next_next_list = next_list->next;
    head->next = next_next_list;
    next_next_list->prev = head;
    free_list_node(next_list);
#else
    erase(head->next);
#endif /// USE_INTERNEL
}

void pop_back(double_list_t *head)
{
    if (NULL == head || is_list_empty(head)) {
        return;
    }

#ifndef USE_INTERNEL
    double_list_t *tail_list = head->prev;
    double_list_t *tail_prev_list = tail_list->prev;
    tail_prev_list->next = head;
    head->prev = tail_prev_list;

    free_list_node(tail_list);
#else
    erase(head->prev);
#endif /// USE_INTERNEL
}

void erase(double_list_t *pos)
{
    if (NULL == pos) {
        return;
    }

    double_list_t *pos_prev_list = pos->prev;
    double_list_t *pos_next_list = pos->next;
    pos_prev_list->next = pos_next_list;
    pos_next_list->prev = pos_prev_list;

    free_list_node(pos);
}

void remove_list_by_data(double_list_t *head, const char *data)
{
    double_list_t *pos = find_list_by_data(head, data);
    erase(pos);
}

void remove_list_by_all_data(double_list_t *head, const char *data)
{
    if (NULL == head || NULL == data) {
        return;
    }

    double_list_t *cur = head->next;
    double_list_t *next_list = NULL;
    double_list_t *prev_list = NULL;

    while (head != cur) {
        next_list = cur->next;
        if (cur->node && 0 == strcmp(cur->node->data, data)) {
            prev_list = cur->prev;
            prev_list->next = next_list;
            next_list->prev = prev_list;
            free_list_node(cur);
        }

        cur = next_list;
    }
}

static void clear_list(double_list_t *head)
{
    if (NULL == head) {
        return;
    }

    double_list_t *cur = head->next;
    double_list_t *next_list = NULL;

    // 先释放第一个节点后面的节点
    for (; head != cur; cur = next_list) {
        next_list = cur->next;
        free_list_node(cur);
    }

    // 释放第一个节点
    free_list_node(cur);
}

void destroy_list(double_list_t *head)
{
    clear_list(head);
}

3. test_double_list.c

#include "double_list.h"

void test()
{
    printf("init list\n");
    // 带有头节点的双向循环链表
    double_list_t *list_head = init_list();

    printf("list size : %d\n", get_list_size(list_head));
    printf("\nlist info :\n");
    print_list_info(list_head);
    if (is_list_empty(list_head)) {
        printf("\nlist is empty\n");
    } else {
        printf("\nlist is not empty\n");
    }

    printf("\npush_front hello\n");
    push_front(list_head, "hello");
    printf("\nlist info :\n");
    print_list_info(list_head);
    printf("\npush_back world\n");
    push_back(list_head, "world");
    printf("\nlist info :\n");
    print_list_info(list_head);

    printf("\ninsert list_head hi\n");
    insert(list_head, "hi");
    printf("\nlist info :\n");
    print_list_info(list_head);
    printf("\ninsert list_head->next->next emo\n");
    insert(list_head->next->next, "emo");
    printf("\nlist info :\n");
    print_list_info(list_head);
    printf("\ninsert list_head->next orz\n");
    insert(list_head->next, "orz");
    printf("\nlist info :\n");
    print_list_info(list_head);

    printf("\npush_front emo\n");
    push_front(list_head, "emo");
    printf("\nlist info :\n");
    print_list_info(list_head);
    printf("\npush_front emo\n");
    push_front(list_head, "emo");
    printf("\nlist info :\n");
    print_list_info(list_head);

    if (is_list_empty(list_head)) {
        printf("\nlist is empty\n");
    } else {
        printf("\nlist is not empty\n");
    }

    printf("list size : %d\n", get_list_size(list_head));

    printf("\nremove_list_by_data emo\n");
    remove_list_by_data(list_head, "emo");
    printf("\nlist info :\n");
    print_list_info(list_head);

    printf("\nremove_list_by_all_data emo\n");
    remove_list_by_all_data(list_head, "emo");
    printf("\nlist info :\n");
    print_list_info(list_head);

    printf("\npop_front\n");
    pop_front(list_head);
    printf("\nlist info :\n");
    print_list_info(list_head);
    printf("\npop_back\n");
    pop_back(list_head);
    printf("\nlist info :\n");
    print_list_info(list_head);

    if (!is_list_empty(list_head)) {
        printf("\nerase list_head->next\n");
        erase(list_head->next);
        printf("\nlist info :\n");
        print_list_info(list_head);
    }

    printf("\ndestroy list\n");
    destroy_list(list_head);
    list_head = NULL;
    printf("list size : %d\n", get_list_size(list_head));
    printf("\nlist info :\n");
    print_list_info(list_head);

    if (is_list_empty(list_head)) {
        printf("\nlist is empty\n");
    } else {
        printf("\nlist is not empty\n");
    }
}

int main(void)
{
    test();

    return 0;
}

4. Makefile

.PHONY: clean

CC = gcc
CFLAGS = -g -Wall -DDEBUG
EXTRA_FLAGS = -DUSE_INTERNEL

# match *.c
SOURCE = $(wildcard ./*.c)
# replace * with *.c
BIN = $(patsubst %.c, %, $(notdir $(SOURCE)))

$(BIN): $(SOURCE)
	$(CC) $(CFLAGS) $(EXTRA_FLAGS) $(SOURCE) -o $@

clean:
	rm -rf $(BIN)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值