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


    #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");
    }
  • 相关阅读:
    预备作业02 : 体会做中学(Learning By Doing)
    7-1 货币转换
    秋季学校总结
    人生路上对我影响最大的三个老师
    自我介绍
    2019寒假作业3(抓老鼠啊~亏了还是赚了?)编程总结
    人生路上对我影响最大的三位老师
    自我介绍
    秋季学期学习总结
    7-1 抓老鼠啊~亏了还是赚了?
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/5686217.html
Copyright © 2020-2023  润新知