线性表(List)---链式存储(循环链表)

循环链表的设计与实现

循环链表定义: 将单链表中最后一个数据元素中的next指针指向第一个元素。
循环链表定义

循环链表的设计

定义一个结构体用来存储指针与指针之间的关系:

typedef struct _tag_CircleListNode
{
    struct _tag_CircleListNode *next;

}CircleListNode;

定义一个头结点用来存储链表:

typedef struct _tag_CircleList
{
    CircleListNode header;
    CircleListNode *slider; //游标
    int length;
}TCircleList;

数据元素定义实例:

struct Value
{
    CircleListNode node;
    int v;
};

循环链表新增功能: 游标

游标的意义: 在循环链表中,可以定义”当前指针”。这个指针通过游标来遍历链表中的所有元素。

循环链表新增的操作
(1)获取当前游标指向的数据元素;
(2)将游标重置指向到链表第一元素;
(3)将游标移动到链表中的下一个数据元素;
(4)将游标移动到链表中的下一个数据元素。


循环链表重要算法

  • 循环链表的插入算法
    • 第一个位置插入元素
      第一个位置插入元素
    • 普通位置插入元素
      普通位置插入元素
    • 添加第一个元素(第一次插入)
      添加第一个元素
    • 最后一个位置插入元素
      最后一个位置插入元素
  • 循环链表的删除算法
    • 普通位置(包含末尾)删除
      普通位置(包含末尾)删除
    • 删除第一个元素
      删除第一个元素

循环链表优点、缺点与应用

优点:
(1)循环链表在单链表的基础上做了一个增强;
(2)循环链表可以完全取代单链表的使用;
(3)循环链表的Next和Current操作可以更高效地遍历链表中的所有元素。
缺点: 代码复杂度提高了。
应用:
约瑟夫问题: n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报到第 m 个人,再令其出列,…,如此下去,求出列顺序。
约瑟夫问题


循环链表的实现

  • CircleList.h
#ifndef _CIRCLELIST_H_
#define _CIRCLELIST_H_

typedef void CircleList;

typedef struct _tag_CircleListNode
{
    struct _tag_CircleListNode *next;

}CircleListNode;

//创建链表
CircleList * CircleList_Create();

//销毁链表
void CircleList_Destroy(CircleList *list);

//获取链表长度
int CircleList_Length(CircleList *list);

//清空链表
void CircleList_Clear(CircleList *list);

//获取pos个位置的元素的操作
CircleListNode * CircleList_Get(CircleList *list, int pos);

//插入元素到位置pos
int CircleList_Insert(CircleList* list, CircleListNode *node, int pos);

//删除位置pos处的元素
CircleListNode * CircleList_Delete(CircleList *list, int pos);

//add
//获取当前游标指向的数据元素
CircleListNode * CircleList_Current(CircleList *list);

//将游标重置指向到链表中的第一个元素
CircleListNode * CircleList_Reset(CircleList *list);

//将游标移动到链表中的下一个元素的位置
CircleListNode * CircleList_Next(CircleList *list);

//直接指定删除链表中某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList *list, CircleListNode * node);

#endif
  • CircleList.c
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "CircleList.h"

typedef struct _tag_CircleList
{
    CircleListNode header;
    CircleListNode *slider; //游标
    int length;
}TCircleList;

//创建链表
CircleList * CircleList_Create()//O(1)
{
    TCircleList* ret = (TCircleList*)malloc(sizeof(TCircleList));
    if (ret == NULL)
    {
        return NULL;
    }

    ret->length = 0;
    ret->slider = NULL;
    ret->header.next = NULL;

    return ret;
}

//销毁链表
void CircleList_Destroy(CircleList *list)//O(1)
{
    if (list == NULL)
    {
        return;
    }
    free(list);
    return ;
}

//获取链表长度
int CircleList_Length(CircleList *list)//O(1)
{

    TCircleList *tList = (TCircleList *)list;
    int ret = -1;

    if (list == NULL)
    {
        return ret;
    }
    ret = tList->length;

    return ret;
}

//清空链表
void CircleList_Clear(CircleList *list)//O(1)
{
    TCircleList *sList = (TCircleList *)list;
    if (sList == NULL)
    {
        return;
    }

    sList->length = 0;
    sList->slider = NULL;
    sList->header.next = NULL;

    return ;
}

//获取pos个位置的元素的操作
CircleListNode * CircleList_Get(CircleList *list, int pos)//O(n)
{
    TCircleList * sList = (TCircleList *)list;
    CircleListNode *ret = NULL;
    int i = 0;
    if (list == NULL || pos < 0)
    {
        return NULL;
    }

    CircleListNode *current = (CircleListNode *)sList;
    for (i = 0;i < pos;i++)
    {
        current = current->next;
    }
    ret = current->next;

    return ret;
}

//插入元素到位置pos
int CircleList_Insert(CircleList* list, CircleListNode *node, int pos)//O(n)
{
    int ret = 0, i = 0;
    TCircleList *sList = (TCircleList *)list;
    if (list == NULL || node == NULL || pos < 0)
    {
        return -1;
    }

    CircleListNode *current = (CircleListNode *)sList;
    for (i = 0;(i < pos) && (current->next != NULL);i++)
    {
        current = current->next;
    }

    //current->next 0号结点的地址
    node->next = current->next;//1
    current->next = node;//2


    //若第一次插入结点
    if (sList->length == 0)
    {
        sList->slider = node;
    }
    sList->length++;

    //若头插法 current 仍然指向头部
    //(原因是: 跳0步,没有跳走)
    if (current == (CircleListNode *)sList)
    {
        //获取最后一个元素
        CircleListNode *last = CircleList_Get(sList, sList->length - 1);
        last->next = current->next;//3
    }

    return ret;
}



//删除位置pos处的元素
CircleListNode * CircleList_Delete(CircleList *list, int pos)//O(n)
{
    TCircleList *sList = (TCircleList *)list;
    CircleListNode *ret = NULL;
    int i = 0;
    if ((sList != NULL) && (pos >= 0) && (sList->length > 0))
    {
    //  CircleListNode * current = (CircleListNode *)(&(sList->header));
        CircleListNode * current = (CircleListNode *)sList;
        CircleListNode * last = NULL;


        for (i = 0;i < pos;i++)
        {
            current = current->next;
        }

        //若删除的是第一个元素(头结点)
        if (current == (CircleListNode *)sList)
        {
            last = (CircleListNode *)CircleList_Get(sList, sList->length - 1);
        }

        //求要删除的元素
        ret = current->next;
        current->next = ret->next;//1

        sList->length--;

        //判断链表是否为空
        if (last != NULL)
        {
            sList->header.next = ret->next;
            last->next = ret->next;//2
        }

        //若删除的元素 为游标所指的元素
        if (sList->slider == ret)
        {
            sList->slider = ret->next;
        }

        //若删除元素后,链表的长度为0
        if (sList->length == 0)
        {
            sList->header.next = NULL;
            sList->slider = NULL;
        }
    }

    return ret;
}

//add
//获取当前游标指向的数据元素
CircleListNode * CircleList_Current(CircleList *list)//O(1)
{
    TCircleList *sList = (TCircleList *)list;
    CircleListNode *ret = NULL;
    if (sList != NULL)
    {
        ret = sList->slider;
    }
    return ret;
}

//将游标重置指向到链表中的第一个元素
CircleListNode * CircleList_Reset(CircleList *list)//O(1)
{
    TCircleList *sList = (TCircleList *)list;
    CircleListNode *ret = NULL;
    if (sList != NULL)
    {
        sList->slider = sList->header.next;
        ret = sList->slider;
    }
    return ret;
}

//将游标移动到链表中的下一个元素的位置
CircleListNode * CircleList_Next(CircleList *list)//O(1)
{
    TCircleList *sList = (TCircleList *)list;
    CircleListNode *ret = NULL;
    if ((sList != NULL) && (sList->slider != NULL))
    {
        ret = sList->slider;
        sList->slider = ret->next;
    }
    return ret;
}

//直接指定删除链表中某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList *list, CircleListNode * node)//O(n)
{
    TCircleList *sList = (TCircleList *)list;
    CircleListNode *ret = NULL;
    int i = 0;
    if (sList != NULL)
    {
        CircleListNode *current = (CircleListNode *)sList;

        //查找node在循环链表中的位置
        for (i = 0;i < sList->length;i++)
        {
            if (current->next == node)
            {
                ret = current->next;
                break;
            }
            current = current->next;
        }

        //如果ret找到,根据i去删除
        if (ret != NULL)
        {
            CircleList_Delete(sList, i);
        }
    }
    return ret;
}
  • 循环链表求解约瑟夫问题
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "CircleList.h"


struct Value
{
    CircleListNode node;
    int v;
};

void main()
{
    int i = 0;

    CircleList * list = CircleList_Create();

    struct Value v1, v2, v3, v4, v5, v6, v7, v8;

    v1.v = 1;
    v2.v = 2;
    v3.v = 3;
    v4.v = 4;
    v5.v = 5;
    v6.v = 6;
    v7.v = 7;
    v8.v = 8;


    CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));
    CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));
    CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));
    CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));
    CircleList_Insert(list, (CircleListNode*)&v5, CircleList_Length(list));
    CircleList_Insert(list, (CircleListNode*)&v6, CircleList_Length(list));
    CircleList_Insert(list, (CircleListNode*)&v7, CircleList_Length(list));
    CircleList_Insert(list, (CircleListNode*)&v8, CircleList_Length(list));

    printf("获取元素:");
    for (i = 0;i < CircleList_Length(list);i++)
    {
        //获取游标所指所元素,然后游标下移
        struct Value *tmp = (struct Value *)CircleList_Next(list);
        printf("%d\t", tmp->v);
    }

    printf("\n");

    //重置游标
    CircleList_Reset(list);

    while (CircleList_Length(list)>0)
    {
        struct Value * tmp = NULL;

        for (i = 1;i < 3;i++)
        {
            CircleList_Next(list);
        }
        tmp = (struct Value *)CircleList_Current(list);
        printf(" 删除%d\t", tmp->v);
        CircleList_DeleteNode(list, (CircleListNode *)tmp);
    }
    CircleList_Destroy(list);
    printf("\n");
    system("pause");
    return;
}
  • 约瑟夫问题求解结果
    约瑟夫结果
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值