• 循环链表(约瑟夫问题)C_LinkedList


    //
    //  C_LinkedList.hpp
    //  test1
    //  循环链表
    //  Created by Zy on 2020/3/28.
    //  Copyright © 2020 Jovan. All rights reserved.
    //
    
    #ifndef C_LinkedList_hpp
    #define C_LinkedList_hpp
    #define OK 1
    #define ERROR 0
    #define OVERFLOW -1
    #include <memory.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    typedef int Status;
    typedef int ElemType;
    typedef struct node{
        ElemType data = 0;
        int index = 0;
        struct node *next = NULL;
        struct node *bf = NULL;
    }C_LinkedList;
    //初始化、构建实例->插入,删除,长度,读取—>清空循环链表
    C_LinkedList * InitList();
    void CreateList(C_LinkedList *);//尾插入构建list,实验中用的随机数构建也是用的尾插入法
    int GetLength(C_LinkedList *);
    C_LinkedList *Locate(C_LinkedList *, ElemType );//查找元素位置f,返回一个指针
    C_LinkedList *GetAt(C_LinkedList *,int);//查找,move为正代表向正向移动,否则向反向移动,为0不移动;返回移动后的指针。
    Status InsertElem(C_LinkedList *, ElemType);//按照指针位置插入元素(如果参数是头指针,则是首插入,可以通过p=p->next改变插入位置)
    Status InsertElemAt(C_LinkedList *, int, ElemType);//按序插入,距离该点d处插入值。如果d为0表示替换该点
    C_LinkedList *DeleteElem(C_LinkedList *,ElemType *);//删除指针位置的结点,并得到该点的值x,返回该指针所对应的下一个结点的指针
    Status DeleteElemAt(C_LinkedList *, int ,ElemType *);//按序删除
    void Erase(C_LinkedList *);
    void PrintList(C_LinkedList *);
    Status IsEmpty(C_LinkedList *);
    #endif /* C_LinkedList_hpp */
    //
    //  C_LinkedList.cpp
    //  test1
    //  循环链表
    //  Created by Zy on 2020/3/28.
    //  Copyright © 2020 Jovan. All rights reserved.
    //
    
    #include "C_LinkedList.hpp"
    C_LinkedList * InitList(){
        C_LinkedList *L;
           L = (C_LinkedList *)malloc(sizeof(C_LinkedList));
        L->next = L;
        L->bf = L;
        return L;
    } //构建空的循环链表
    void CreateList(C_LinkedList * L){
        C_LinkedList *rear = L,*p;
        int i,d,n,x;
        printf("输入循环链表的初始长度n:");
        scanf("%d",&n);
        printf("输入随机数范围d(代表密码范围在[-d,d]之间):");
        scanf("%d",&d);
        srand((int)time(0));
        for(i=0;i<n;i++)
        {   x = rand()%(2*d+1)-d;
            if(!x) x++; //不允许密码为0,要么正要么负。但是这样会导致出现1的概率增大,但是随着d的增大,概率会变小,所以尽量让d取大一点
            if(i==0) {rear->data = x;rear->index=1;}
            else {
                p = (C_LinkedList *)malloc(sizeof(C_LinkedList));
                p->data = x;
                p->index = rear->index+1;
                p->next = rear->next;
                p->bf = rear;
                rear->next = p;
                p->next->bf = p;
                rear=p;
            }
        }
    }
    Status IsEmpty(C_LinkedList *L){
        return L==L->next&&L->index==0;
    }
    C_LinkedList *DeleteElem(C_LinkedList *L,ElemType *x){
        if(L->index==0) {printf("空的循环链表!
    ");return NULL;}
        else if(L->next == L){*x = L->data;printf("%d ",L->index);L->index = 0;return L;}
        else {
            C_LinkedList *p = L->next;
            L->next->bf = L->bf;
            L->bf->next = L->next;
            *x = L->data;
            printf("%d ",L->index);
            free(L);
            if(*x>0) return p;
            else return p->bf; //必须用返回值更新L,不然L指针的值没有得到修改;或者用C++引用来实现函数内修改
        }
    }
    C_LinkedList *GetAt(C_LinkedList *L,int move){
        int i;
        C_LinkedList *p = L;
        if(move>0) for(i=0;i<move;i++) p = p->next;
        else if(move<0) for(i=0;i>move;i--) p = p->bf;
        return p;
    }
    void PrintList(C_LinkedList *L){
        if(!L||L->index==0) {printf("链表为空,无法打印。
    ");return;}
        C_LinkedList *p = L;
        printf("%d ",p->data);
        p = p->next;
           while(p!=L){
               printf("%d ",p->data);
               p = p->next;
           }
           printf("
    ");
    }
    int GetLength(C_LinkedList *L){
        C_LinkedList *p = L->next;
        int len = 1;
        while(p!=L){p = p->next;len++;}
        return len;
    }
    C_LinkedList *Locate(C_LinkedList *L, ElemType x){
        C_LinkedList *p = L;
        if(p->data == x) return L;
        p = p->next;
        while(p!=L&&p->data!=x){p = p->next;}
        if(p==L) return NULL;
        else return p;
    }
    Status InsertElem(C_LinkedList *L, ElemType x){
        if(L==NULL) return ERROR;
        if(L->index==0){L->data = x;L->index = 1;return OK;}
        C_LinkedList *p = (C_LinkedList *)malloc(sizeof(C_LinkedList));
        p->data = x;
        p->index = L->index+1;
        p->next = L->next;
        p->next->bf = p;
        p->bf = L;
        L->next = p;
        return OK;
    }
    Status InsertElemAt(C_LinkedList *L, int d, ElemType x){
        C_LinkedList *p = L;
        if(!L) return ERROR;
        if(!d) {L->data = x;return OK;} 
        d = d>0?d-1:d;
        p = GetAt(p, d);
        return InsertElem(p, x);
    }
    Status DeleteElemAt(C_LinkedList *L, int d,ElemType *x){
        C_LinkedList *p = L;
        if(!L) return ERROR;
        p = GetAt(p, d); DeleteElem(p, x);
        return OK;
    }
    void Erase(C_LinkedList * L){
        C_LinkedList *p = L->next, *temp;
        while(p!=L){temp = p->next; free(p); p=temp;}
        free(p);
        L->index = 0;
    }

    测试:

    #include <stdio.h>
    #include <stdlib.h>
    #include "C_LinkedList.hpp"
    int main()
    {
        int m;
        C_LinkedList *L = InitList();
        CreateList(L);
        printf("第一次:");
        PrintList(L);
        printf("输入初始报数上限值:");
        scanf("%d",&m);//m如果为正数从1开始报,如果m为负数,从-1开始报,正负只代表报数方向
        int next_move = m-1;
        while(!IsEmpty(L)){
            L = GetAt(L, next_move);
            L = DeleteElem(L, &next_move);//L处删除后L自动更新到删除点后一位处,next_move保存删除点的密码值
            next_move =next_move>0?next_move-1:next_move+1;
        }
        Erase(L);
        printf("
    ");
        PrintList(L);
    }

    输入循环链表的初始长度n:7

    输入随机数范围d(代表密码范围在[-d,d]之间):10

    第一次:-6 -10 -3 1 -6 10 10 

    输入初始报数上限值:6

    6 3 7 2 1 4 5 

    链表为空,无法打印。

    Program ended with exit code: 0

    ——————————————————————

    优化:根据循环链表长度可以通过取余来减少每次移动次数:即修改GetAt函数,和设置全局变量size

    修改后代码为:

    //
    //  C_LinkedList.hpp
    //  test1
    //  循环链表
    //  Created by Zy on 2020/3/28.
    //  Copyright © 2020 Jovan. All rights reserved.
    //
    
    #ifndef C_LinkedList_hpp
    #define C_LinkedList_hpp
    #define OK 1
    #define ERROR 0
    #define OVERFLOW -1
    #include <memory.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    typedef int Status;
    typedef int ElemType;
    typedef struct node{
        ElemType data = 0;
        int index = 0;
        struct node *next = NULL;
        struct node *bf = NULL;
    }C_LinkedList;
    extern int size;
    //初始化、构建实例->插入,删除,长度,读取—>清空循环链表
    C_LinkedList * InitList();
    void CreateList(C_LinkedList *);//尾插入构建list,实验中用的随机数构建也是用的尾插入法
    int GetLength(C_LinkedList *);
    C_LinkedList *Locate(C_LinkedList *, ElemType );//查找元素位置f,返回一个指针
    C_LinkedList *GetAt(C_LinkedList *,int);//查找,move为正代表向正向移动,否则向反向移动,为0不移动;返回移动后的指针。
    Status InsertElem(C_LinkedList *, ElemType);//按照指针位置插入元素(如果参数是头指针,则是首插入,可以通过p=p->next改变插入位置)
    Status InsertElemAt(C_LinkedList *, int, ElemType);//按序插入,距离该点d处插入值。如果d为0表示替换该点
    C_LinkedList *DeleteElem(C_LinkedList *,ElemType *);//删除指针位置的结点,并得到该点的值x,返回该指针所对应的下一个结点的指针
    Status DeleteElemAt(C_LinkedList *, int ,ElemType *);//按序删除
    void Erase(C_LinkedList *);
    void PrintList(C_LinkedList *);
    Status IsEmpty(C_LinkedList *);
    #endif /* C_LinkedList_hpp */

    其中size前面要加extern 表示全局变量声明而非定义,定义在cpp文件中。

    //
    //  C_LinkedList.cpp
    //  test1
    //  循环链表
    //  Created by Zy on 2020/3/28.
    //  Copyright © 2020 Jovan. All rights reserved.
    //
    
    #include "C_LinkedList.hpp"
    int size = 0;
    C_LinkedList * InitList(){
        C_LinkedList *L;
           L = (C_LinkedList *)malloc(sizeof(C_LinkedList));
        L->next = L;
        L->bf = L;
        return L;
    } //构建空的循环链表
    void CreateList(C_LinkedList * L){
        C_LinkedList *rear = L,*p;
        int i,d,n,x;
        printf("输入循环链表的初始长度n:");
        scanf("%d",&n);
        size = n;
        printf("输入随机数范围d(代表密码范围在[-d,d]之间):");
        scanf("%d",&d);
        srand((int)time(0));
        for(i=0;i<n;i++)
        {   x = rand()%(2*d+1)-d;
            if(!x) x++; //不允许密码为0,要么正要么负。但是这样会导致出现1的概率增大,但是随着d的增大,概率会变小,所以尽量让d取大一点
            if(i==0) {rear->data = x;rear->index=1;}
            else {
                p = (C_LinkedList *)malloc(sizeof(C_LinkedList));
                p->data = x;
                p->index = rear->index+1;
                p->next = rear->next;
                p->bf = rear;
                rear->next = p;
                p->next->bf = p;
                rear=p;
            }
        }
    }
    Status IsEmpty(C_LinkedList *L){
        return L==L->next&&L->index==0;
    }
    C_LinkedList *DeleteElem(C_LinkedList *L,ElemType *x){
        if(L->index==0) {printf("空的循环链表!
    ");return NULL;}
        else if(L->next == L){*x = L->data;printf("%d ",L->index);L->index = 0;return L;}
        else {
            C_LinkedList *p = L->next;
            L->next->bf = L->bf;
            L->bf->next = L->next;
            *x = L->data;
            printf("%d ",L->index);
            free(L);
            size--;
            if(*x>0) return p;
            else return p->bf; //必须用返回值更新L,不然L指针的值没有得到修改;或者用C++引用来实现函数内修改
        }
    }
    C_LinkedList *GetAt(C_LinkedList *L,int move){
        int i;
        move = move%size;
        C_LinkedList *p = L;
        if(move>0) for(i=0;i<move;i++) p = p->next;
        else if(move<0) for(i=0;i>move;i--) p = p->bf;
        return p;
    }
    void PrintList(C_LinkedList *L){
        if(!L||L->index==0) {printf("链表为空,无法打印。
    ");return;}
        C_LinkedList *p = L;
        printf("%d ",p->data);
        p = p->next;
           while(p!=L){
               printf("%d ",p->data);
               p = p->next;
           }
           printf("
    ");
    }
    int GetLength(C_LinkedList *L){
        C_LinkedList *p = L->next;
        int len = 1;
        while(p!=L){p = p->next;len++;}
        return len;//也可以用全局变量size
    }
    C_LinkedList *Locate(C_LinkedList *L, ElemType x){
        C_LinkedList *p = L;
        if(p->data == x) return L;
        p = p->next;
        while(p!=L&&p->data!=x){p = p->next;}
        if(p==L) return NULL;
        else return p;
    }
    Status InsertElem(C_LinkedList *L, ElemType x){
        if(L==NULL) return ERROR;
        if(L->index==0){L->data = x;L->index = 1;size++;return OK;}
        C_LinkedList *p = (C_LinkedList *)malloc(sizeof(C_LinkedList));
        p->data = x;
        p->index = L->index+1;
        p->next = L->next;
        p->next->bf = p;
        p->bf = L;
        L->next = p;
        size++;
        return OK;
    }
    Status InsertElemAt(C_LinkedList *L, int d, ElemType x){
        C_LinkedList *p = L;
        if(!L) return ERROR;
        if(!d) {L->data = x;size++;return OK;}
        d = d>0?d-1:d;
        p = GetAt(p, d);
        return InsertElem(p, x);
    }
    Status DeleteElemAt(C_LinkedList *L, int d,ElemType *x){
        C_LinkedList *p = L;
        if(!L) return ERROR;
        p = GetAt(p, d); DeleteElem(p, x);
        return OK;
    }
    void Erase(C_LinkedList * L){
        C_LinkedList *p = L->next, *temp;
        while(p!=L){temp = p->next; free(p); p=temp;}
        free(p);
        L->index = 0;
        size = 0;
    }
    #include <stdio.h>
    #include <stdlib.h>
    #include "C_LinkedList.hpp"
    int main()
    {
        int m;
        C_LinkedList *L = InitList();
        CreateList(L);
        printf("第一次:");
        PrintList(L);
        printf("输入初始报数上限值:");
        scanf("%d",&m);//m如果为正数从1开始报,如果m为负数,从-1开始报,正负只代表报数方向
        int next_move = m-1;
        while(!IsEmpty(L)){
            L = GetAt(L, next_move);
            L = DeleteElem(L, &next_move);//L处删除后L自动更新到删除点后一位处,next_move保存删除点的密码值
            next_move =next_move>0?next_move-1:next_move+1;
        }
        Erase(L);
        printf("
    ");
        PrintList(L);
        printf("size = %d
    ",size);
    }

    输入循环链表的初始长度n:7

    输入随机数范围d(代表密码范围在[-d,d]之间):5

    第一次:-5 5 1 5 1 5 2 

    输入初始报数上限值:6

    6 4 3 5 7 2 1 

    链表为空,无法打印。

    size = 0

    Program ended with exit code: 0

    通过实验计算时间复杂度===========================================================================================================================

    测试运算时间,通过测试每一种规模[n,m] (n<=30), 用10组数据算出运算时间的平均值,控制n不变,改变m;然后控制m不变改变n;m变化区间为[0,2n],步长设为1;

    #include <stdio.h>
    #include <stdlib.h>
    #include "C_LinkedList.hpp"
    #include <time.h>
    #define MAX 100
    #include <time.h>
    void my_delay(int delay_t)
    {
    clock_t start_time; //the start time
    start_time=clock();
    while((clock()-start_time)/CLOCKS_PER_SEC <delay_t);//delay_t表示延迟多少ms
    }
    typedef struct person{
        int code = 0;
        int isout = 0;
    }Person;
    int Inputcode[MAX]={};
    double Array_time[MAX]={};
    double CList_time[MAX]={};
    double Time[2][MAX]={};
    double average(double x[],int n){
        double sum = 0;
        for(int i=0;i<n;i++)
            sum += x[i];
        return sum/n;
    }
    int main()
    {   clock_t begin,end;
        double t1,t2;
        int n,m,d,i,x;
        int pointer,count,left;
        C_LinkedList *L = InitList();
        Person a[MAX];
        memset(a,0,sizeof(a));
        
       // printf("输入循环链表的初始长度n:");
         //  scanf("%d",&n);
        n = 20;
        printf("输入初始报数上限值:");
        scanf("%d",&m);//m如果为正数从1开始报,如果m为负数,从-1开始报,正负只代表报数方向
        printf("输入随机数范围d(代表密码范围在[-d,d]之间):");
        scanf("%d",&d);//范围设置的10
        for(d = 10;d<=100;d+=10){
            printf("
    >>>>>>>>>>>>>>>>>>n = %d, m = %d ,d = %d >>>>>>>>>>>>>>>>>",n,m,d);
            printf("start?Y or N:");
            getchar();getchar();
        for(int k = 1;k <= 10; k++)
        {
            my_delay(1);
        srand((int)time(0));
    /*================生成数据==================*/
        for(i=1;i<=n;i++){
        x = rand()%(2*d+1)-d;
        Inputcode[i]=x?x:1;//不允许密码为0,要么正要么负。但是这样会导致出现1的概率增大,但是随着d的增大,概率会变小,所以尽量让d取大一点
        }
        printf("
    第%d组数据:(n=%d,m=%d)
    ",k,n,m);
            for(i=1;i<=n;i++)
                printf("%d ",Inputcode[i]);
            printf("
    =============================
    ");
     /*================输入数据===================*/
            int j = 5;
            int temp = m;
            while(j--){
        pointer = count = 0;
        memset(a, 0, sizeof(a));
        for(i = 1;i<=n;i++)
        a[i].code = Inputcode[i];
        left = n;
        size = n;
        CreateList(L,Inputcode,n);//用Inputcode分别给循环链表和循环数组赋初值,保证测试数据一致。
        //PrintList(L);
    
    /*===============测试时间(每组数据测十次取平均值)===================*/
            begin = clock();
            do{
                if(temp>0)pointer++;
                else pointer--;
                if(pointer==n+1) pointer=1;
                else if(pointer==0)pointer=n;
                if(!a[pointer].isout){
                    if(temp>0) count++;
                    else count--;
                }
                if(count==temp){
                    count=0;
                    printf("%d ",pointer);
                    a[pointer].isout = 1;
                    temp = a[pointer].code;
                    left--;
                    if(!left) break;
                    if(!(temp%left)) temp = temp>0?-1:1;
                    else if(temp>left) temp = temp%left;
                    else if(temp<-left) temp = temp%left-left;
                }
            }while(1);
            end = clock();
            printf("
    ");
            Array_time[j] = (double)(end-begin)/CLOCKS_PER_SEC;
              //  printf("%lf",Array_time[j]);
        
                temp = m;
        int next_move = temp-1;
            begin = clock();
        while(!IsEmpty(L)){
            L = GetAt(L, next_move);
            L = DeleteElem(L, &next_move);//L处删除后L自动更新到删除点后一位处,next_move保存删除点的密码值
            next_move =next_move>0?next_move-1:next_move+1;
        }
                end = clock();
                printf("
    ");
                CList_time[j] = (double)(end-begin)/CLOCKS_PER_SEC;
        }
            Time[0][k] = average(Array_time, 5);
            Time[1][k] = average(CList_time, 5);
            printf("循环数组所花时间:%lfns
    ",1000000*Time[0][k]);
            printf("循环队列所花时间:%lfns
    ",1000000*Time[1][k]);
        }
            t1 = average(Time[0], 10);
            t2 = average(Time[1],10);
            printf("t1 = %lfns;
    t2 = %lfns",1000000*t1,1000000*t2);
        }
    }
  • 相关阅读:
    将new Date()的时间转换为常用时间格式
    封装通用的jsonp方式
    javascript实现手机震动API代码
    webstorm 2016.3.2 破解代码(免费)
    淘宝镜像在npm中执行的代码
    jQuery lazyload 懒加载
    uniapp小程序获取时间戳转换时间例子
    微信小程序解析HTML标签
    微信小程序之tab切换效果
    巧用weui.gallery(),点击图片后预览图片
  • 原文地址:https://www.cnblogs.com/raiuny/p/12589915.html
Copyright © 2020-2023  润新知