数据结构 线性循环列表(约瑟夫问题)

#ifndef _vzhangcirclelist
#define _vzhangcirclelist

typedef struct _LinkNode{
    struct _LinkNode *pnext;
}LinkNode;


typedef void CircleList;

//创建线性循环链表
_declspec(dllexport)
CircleList* CircleList_Create();

//销毁线性循环链表
_declspec(dllexport)
int CircleList_Destroy(CircleList** list);

//清空线性循环链表
_declspec(dllexport)
int CircleList_Clear(CircleList* list);

//获取线性循环链表长度
_declspec(dllexport)
int CircleList_Length(CircleList* list);

//线性链表指定位置插入元素
_declspec(dllexport)
int CircleList_Insert(CircleList* list, LinkNode* node, int pos);

//获取线性循环链表指定位置的元素
_declspec(dllexport)
LinkNode* CircleList_Get(CircleList* list, int pos);

//删除线性循环链表指定位置的元素
_declspec(dllexport)
LinkNode* CircleList_Delete(CircleList* list, int pos);

//add

//删除当前节点
_declspec(dllexport)
LinkNode* CircleList_DeleteNode(CircleList* list, LinkNode* node);

//游标重置
_declspec(dllexport)
LinkNode* CircleList_Reset(CircleList* list);

//获取当前游标节点
_declspec(dllexport)
LinkNode* CircleList_Current(CircleList* list);

//获取下一个元素节点
_declspec(dllexport)
LinkNode* CircleList_Next(CircleList* list);

#endif
//线性循环链表代码实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"circlelist.h"

//定义循环链表结构体
typedef struct _TCircleList{
    //定义一个头结点
    LinkNode node;
    //定义链表长度
    int length;
    //定义游标
    LinkNode *slider;
}TCircleList;

//创建线性循环链表
_declspec(dllexport)
CircleList* CircleList_Create(){
    //分配链表结构体内存
    TCircleList * tlist = (TCircleList *)malloc(sizeof(TCircleList));
    if (tlist==NULL)
    {
        printf("分配内存失败!
");
        return NULL;
    }
    tlist->node.pnext = NULL;
    tlist->length = 0;
    tlist->slider = NULL;
    return tlist;
}

//销毁线性循环链表
_declspec(dllexport)
int CircleList_Destroy(CircleList** list){
    int ERRO_MSG = 0;
    if (list==NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return ERRO_MSG;
    }
    TCircleList *tlist = (TCircleList *)*list;
    if (tlist!=NULL)
    {
        free(tlist);
        tlist = NULL;
    }
    *list = NULL;
    return ERRO_MSG;
}

//清空线性循环链表
_declspec(dllexport)
int CircleList_Clear(CircleList* list){
    int ERRO_MSG = 0;
    if (list == NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return ERRO_MSG;
    }
    TCircleList *tlist = (TCircleList *)list;
    tlist->node.pnext = NULL;
    tlist->length = 0;
    return ERRO_MSG;
}

//获取线性循环链表长度
_declspec(dllexport)
int CircleList_Length(CircleList* list){
    int ERRO_MSG = 0;
    if (list == NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return ERRO_MSG;
    }
    TCircleList *tlist = (TCircleList *)list;
    return tlist->length;
}

//线性链表指定位置插入元素
_declspec(dllexport)
int CircleList_Insert(CircleList* list, LinkNode* node, int pos){
    int ERRO_MSG = 0, i = 0;
    if (list == NULL || node==NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return ERRO_MSG;
    }
    TCircleList *tlist = (TCircleList *)list;
    //判断插入的位置
    if (pos<0 || pos>tlist->length)
    {
        //进行容错处理
        pos = tlist->length;
    }
    //此时current指向头结点
    //假设在0个位置插入  
    LinkNode * current = &tlist->node;
    for (i = 0; i < pos && (current->pnext!=NULL); i++)
    {
        current = current->pnext;
    }
    node->pnext = current->pnext;
    current->pnext = node;
    //元素个数+1
    tlist->length++;
    /*
    元素个数必须先加1  不然获取最后一个节点的数据不正确  lastnode的数据不正确
    */



    //闭合链表
    /*
    对于在尾部插入,上面算法就可以实现闭合  因为最后一个节点的pnext就指向第0个元素
    对于在第0个位置插入 那么就必须让尾部的pnext指向新插入的元素
    */
    if (tlist->node.pnext == node)
    {
        //如果插入节点的地址  等于  头结点的pnext的地址
        //获取尾部节点   
        //注意  获取最后一个节点是 tlist->length-1
        LinkNode * lastnode = CircleList_Get(list, tlist->length-1);
        lastnode->pnext = node;
    }
    //为游标赋值
    tlist->slider = node;
    return ERRO_MSG;
}

//获取线性循环链表指定位置的元素
_declspec(dllexport)
LinkNode* CircleList_Get(CircleList* list, int pos){
    int ERRO_MSG = 0, i = 0;
    if (list == NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    //循环链表不可以做位置上限限制
    if (pos<0)
    {
        ERRO_MSG = -2;
        printf("没有该位置的元素! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    TCircleList *tlist = (TCircleList *)list;
    //此时current指向第0个节点
    LinkNode * current = tlist->node.pnext;
    LinkNode * ret = NULL;
    for (i = 0; i < pos; i++)
    {
        current = current->pnext;
    }
    ret = current;
    return ret;
}

//删除线性循环链表指定位置的元素
_declspec(dllexport)
LinkNode* CircleList_Delete(CircleList* list, int pos){
    int ERRO_MSG = 0, i = 0;
    if (list == NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    TCircleList *tlist = (TCircleList *)list;
    //定义尾节点
    LinkNode * lastnode = NULL;
    //循环链表不可以做位置上限限制
    if (pos<0 || tlist->length<0)
    {
        ERRO_MSG = -2;
        printf("没有该位置的元素! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    //此时current指向头结点
    LinkNode * current = &tlist->node;
    LinkNode * ret = NULL;
    for (i = 0; i < pos; i++)
    {
        current = current->pnext;
    }
    //找到指定位置的上一个节点
    ret = current->pnext;
    //判断删除的是不是第0个节点
    if (ret == tlist->node.pnext)
    {
        //获取循环链表尾节点
        lastnode = CircleList_Get(list, tlist->length - 1);
    }
    current->pnext = ret->pnext;
    //元素个数-1
    tlist->length--;
    
    //如果最后的节点不是NULL  尾节点指向第0个节点
    /*
        强调:
        这个操作对于链表只有一个元素的情况下是错误的
        所以后面会对链表只有一个元素特别处理
    */
    if (lastnode!=NULL)
    {
        /*lastnode->pnext = tlist->node.pnext;*/
        /*
        以上代码错误 循环链表  头结点的node属性也必须发生变化
        */

        lastnode->pnext = ret->pnext;
        tlist->node.pnext = ret->pnext;
    }
    //如果游标正好是被删除的元素  后移一个元素
    //游标处理
    /*
        强调:
        这个操作对于链表只有一个元素的情况下是错误的
        所以后面会对链表只有一个元素特别处理
    */
    if (tlist->slider == ret)
    {
        tlist->slider = ret->pnext;
    }

    //如果链表元素个数为0   全部置空   ---对链表只有一个元素特别处理
    /*
        注意:这个条件必须放在最后   因为假设只有一个元素的时候  
        lastnode其实最后指向的是被删除的元素  此时lastnode也是不为空的  循环链表很特殊
    */
    if (tlist->length == 0)
    {
        tlist->node.pnext = NULL;
        tlist->slider = NULL;
    }
    return ret;
}

//删除当前节点
_declspec(dllexport)
LinkNode* CircleList_DeleteNode(CircleList* list, LinkNode* node){
    int ERRO_MSG = 0, i = 0;
    if (list == NULL || node==NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    TCircleList *tlist = (TCircleList *)list;
    //此时current指向头结点
    LinkNode * current = tlist->node.pnext;
    for (i = 0; i < tlist->length; i++)
    {
        //比较2元素的地址是否相等
        //单向链表只能通过上一个元素找到下一个  所以这里使用pPrior
        if (current == node)
        {
            break;
        }
        current = current->pnext;
    }
    //调用删除节点的函数(删除逻辑太复杂  不适合在这里写)
    return CircleList_Delete(list, i);
}

//游标重置
_declspec(dllexport)
LinkNode* CircleList_Reset(CircleList* list){
    int ERRO_MSG = 0;
    if (list == NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    TCircleList *tlist = (TCircleList *)list;
    tlist->slider = tlist->node.pnext;
    return tlist->slider;
}

//获取当前游标节点
_declspec(dllexport)
LinkNode* CircleList_Current(CircleList* list){
    int ERRO_MSG = 0;
    if (list == NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    TCircleList *tlist = (TCircleList *)list;
    return tlist->slider;
}

//获取下一个元素节点
_declspec(dllexport)
LinkNode* CircleList_Next(CircleList* list){
    int ERRO_MSG = 0;
    if (list == NULL)
    {
        ERRO_MSG = -1;
        printf("传入参数不可以为空! erro msg:%d
", ERRO_MSG);
        return NULL;
    }
    TCircleList *tlist = (TCircleList *)list;
    tlist->slider = tlist->slider->pnext;
    return tlist->slider;
}
//线性循环链表--约瑟夫问题
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"circlelist.h"

/*
约瑟夫环(约瑟夫问题)
是一个数学的应用问题:
已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。
从编号为k的人开始报数,
数到m的那个人出列;
他的下一个人又从1开始报数,
数到m的那个人又出列;
依此规律重复下去,直到圆桌周围的人全部出列
*/

typedef struct _Student{
    //必须加一个LinkNode节点
    LinkNode node;
    char name[30];
    int age;
}Student;

void Test(){
    Student s1, s2, s3, s4, s5, s6, s7, s8;
    Student * tempstu=NULL;
    int numx = 3, i = 0, ret = 0,index=0,j=0;
    //printf("请输入m的值:
");
    //scanf("%d", &numx);
    strcpy(s1.name, "小米");
    s1.age = 1;
    strcpy(s2.name, "小刚");
    s2.age = 2;
    strcpy(s3.name, "小红");
    s3.age = 3;
    strcpy(s4.name, "啸天");
    s4.age = 4;
    strcpy(s5.name, "莲华");
    s5.age = 5;
    strcpy(s6.name, "夏利");
    s6.age = 6;
    strcpy(s7.name, "小李");
    s7.age = 7;
    strcpy(s8.name, "阿凯");
    s8.age = 8;
    //线性循环链表指针
    CircleList *list = NULL;
    //创建线性循环链表
    list = CircleList_Create();
    //插入元素
    CircleList_Insert(list, (LinkNode *)&s1, CircleList_Length(list));
    CircleList_Insert(list, (LinkNode *)&s2, CircleList_Length(list));
    CircleList_Insert(list, (LinkNode *)&s3, CircleList_Length(list));
    CircleList_Insert(list, (LinkNode *)&s4, CircleList_Length(list));
    CircleList_Insert(list, (LinkNode *)&s5, CircleList_Length(list));
    CircleList_Insert(list, (LinkNode *)&s6, CircleList_Length(list));
    CircleList_Insert(list, (LinkNode *)&s7, CircleList_Length(list));
    CircleList_Insert(list, (LinkNode *)&s8, CircleList_Length(list));
    //重置游标
    tempstu = (Student *)CircleList_Reset(list);
    while (CircleList_Length(list) > 1){
        if (index == numx-1){
            index = 0;
            //删除当前元素
            tempstu = (Student *)CircleList_DeleteNode(list, (LinkNode*)tempstu);
            printf("被删除的是%s,年龄是%d!
", tempstu->name, tempstu->age);
            //在删除操作中  游标已经下移了
            continue;
        }
        index++;
        //游标下移
        tempstu = (Student *)CircleList_Next(list);
        //printf("当前元素的是%s,年龄是%d!
", tempstu->name, tempstu->age);
    }
    //销毁循环链表
    ret = CircleList_Destroy(&list);

}

void main(){
    Test();
    system("pause");
}
原文地址:https://www.cnblogs.com/zhanggaofeng/p/5686217.html