工学1号馆

home

循环链表

By Wu Yudong on December 06, 2016

循环链表在单向链表的基础之上作了一进步的概念延伸,循环链表让链表操作变的更加灵活,单向链表的尾结点的next链域指向其头结点,本文使用C语言实现一个通用的单向循环链表

定义一个头文件clits.h

文件里面先定义一个循环链表的元素:

#ifndef CLIST_H
#define CLIST_H

#include <stdlib.h>
typedef struct CListElmt_ {
    void *data;
    struct CListElmt_ *next;
} CListElmt;

接着定义循环链表的结构体

typedef struct CList_ {
    int size;
    int (*match) (const void *key1, const void *key2);
    void (*destroy) (void *data);
    CListElmt *head;
} CList;

接着定义公共接口

void clist_init(CList *list, void (*destroy) (void *data));
void clist_destroy(CList *list);
int clist_ins_next(CList *list, CListElmt *element, const void *data);
int clist_rem_next(CList *list, CListElmt *element, void **data);

#define clist_size(list) ((list)->size)
#define clist_head(list) ((list)->head)
#define clist_data(element) ((element)->data)
#define clist_next(element) ((element)->next)

接下来是对应的实现文件clist.c

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

#include "clist.h"

//初始化链表
void clist_init(CList *list, void (*destroy) (void *data))
{
    list->size = 0;
    list->destroy = destroy;
    list->head = NULL;
    return;
}

//销毁链表
void clist_destroy(CList *list)
{
    void *data;

    //移除每一个元素
    while (clist_size(list) > 0) {
        if (clist_rem_next(list, list->head, (void **)&data) == 0 && list->destroy != NULL) {
            //调用一个用户调用的函数释放动态分配数据
            list->destroy(data);
        }
    }
    //现在不能进行任何操作,清除结构体作为预防
    memset(list, 0, sizeof(CList));
    return;
}

//在新元素插入到指定元素的后面
int clist_ins_next(CList *list, CListElmt *element, const void *data)
{
    CListElmt *new_element;

    //为元素分配存储空间
    if ((new_element = (CListElmt *)malloc(sizeof(CListElmt))) == NULL)
        return -1;

    //将新元素插入链表
    new_element->data = (void *)data;
    if (clist_size(list) == 0) {

        //当链表为空的时候处理插入
        new_element->next = new_element;
        list->head = new_element;
    } else {

        //链表非空的时候处理插入
        new_element->next = element->next;
        element->next = new_element;
    }
    list->size++; //插入元素后修改链表的size
    return 0;
}

//在指定元素的后面移除元素
int clist_rem_next(CList *list, CListElmt *element, void **data)
{
    CListElmt *old_element;

    //不允许在空链表移除元素
    if (clist_size(list) == 0)
        return -1;

    //从链表中移除元素
    *data = element->next->data;

    if (element->next == element) {

        //如果链表只剩下一个元素
        old_element = element->next;
        list->head = NULL;

    } else {
        old_element = element->next;
        element->next = element->next->next;
    }
    free(old_element); //释放已分配的抽象数据类型
    list->size--;    //删除元素后修改链表的size
    return 0;
}

最后的测试文件test.c

/*
    Copyright:wuyudong
    License: as you wish
    Author: wuyudong <codingwu@gmail.com>
    Date: 2016-12-06
    Blog: www.wuyudong.com
*/

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

#include "clist.h"

//打印链表
static void print_list(const CList *list)
{
    CListElmt *element;
    int *data, size, i;

    //显示循环链表
    fprintf(stdout, "List size is %d (circling twice)\n", clist_size(list));

    size = clist_size(list);
    element = clist_head(list);

    //重复两次遍历链表来验证是循环链表
    i = 0;
    while (i < size * 2) {
        data = clist_data(element);
        fprintf(stdout, "list[%03d]=%03d\n", (i % size), *data);
        element = clist_next(element);
        i++;
    }
    return;
}

int main(int argc, char **argv)
{
    CList list;
    CListElmt *element;
    int *data, i;

    clist_init(&list, free);    //初始化链表
    element = clist_head(&list); //执行一些循环链表的操作
    for (i = 0; i < 10; i++) {
        if ((data = (int *)malloc(sizeof(int))) == NULL)
            return 1;
        *data = i + 1;
        if (clist_ins_next(&list, element, data) != 0)
            return 1;
        if (element == NULL)
            element = clist_next(clist_head(&list));
        else
            element = clist_next(element);
    }
    print_list(&list);
    element = clist_head(&list);
    for (i = 0; i < 10; i++)
        element = clist_next(element);

    data = clist_data(element);
    fprintf(stdout, "Circling and removing an element after the one containing " "%03d\n", *data);

    if (clist_rem_next(&list, element, (void **)&data) != 0)
        return 1;

    free(data);
    print_list(&list);

    element = clist_head(&list);

    for (i = 0; i < 15; i++)
        element = clist_next(element);

    data = clist_data(element);
    fprintf(stdout, "Circling and inserting 011 after the element containing " "%03d\n", *data);

    if ((data = (int *)malloc(sizeof(int))) == NULL)
        return 1;
    *data = 11;
    if (clist_ins_next(&list, element, data) != 0)
        return 1;
    print_list(&list);
    fprintf(stdout, "Destroying the list\n");
    clist_destroy(&list);        //销毁循环链表

    return 0;
}

 

如果文章对您有帮助,欢迎点击下方按钮打赏作者

Comments

No comments yet.
To verify that you are human, please fill in "七"(required)