zoukankan      html  css  js  c++  java
  • 循环链表(约瑟夫问题)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);
        }
    }
  • 相关阅读:
    Visual Studio 2010使用Visual Assist X的方法
    SQL Server 2000 评估版 升级到 SQL Server 2000 零售版
    双网卡多网络单主机同时访问
    开发即过程!立此纪念一个IT新名词的诞生
    delphi dxBarManager1 目录遍历 转为RzCheckTree2树
    5320 软件集合
    delphi tree 从一个表复制到另一个表
    DELPHI 排课系统课表
    长沙金思维 出现在GOOGLE的 金思维 相关搜索里啦!!
    如何在DBGrid的每一行前加一个单选框?
  • 原文地址:https://www.cnblogs.com/raiuny/p/12589915.html
Copyright © 2011-2022 走看看