用循环链表解决约瑟夫环问题

        在数据结构实验课上遇到这个问题,最开始的想法是用一个数组来存储数据,通过对数组长度取模的 方式来循环访问数组中的元素,但是问题是,已经出列元素的删除用普通数组不好实现(平白無故增加了o(n)的时间复杂度,于是就想到建立一个结构体(多加了一个bool,用来判断该元素是否已经出队);

 /*用数组实现的难题是,元素的删除问题,某个元素出列以后,
         *它仍然会占据数组空间;index取模访问元素时,可能会
         *访问到已经出列的元素,考虑考虑用一个数组来存储已经出列的
         *元素的下标,通过for循环来找到,下一个index,但是,问题是,
         *太麻烦了,,时间复杂度也比较高*/

是否可以用vector来实现?

        *vector是否可以实现随机删除?

                貌似是可以,,但是,还是比较麻烦,而且数组的删除还是会增加时间复杂度,即使这个操作已经被实现;要不,这个坑先留在这儿,有时间再填;

 

              用数组不行,那很自然的就想到了循环链表;这里比较坑的是循环链表的删除问题,

1、删除首尾针所指的节点时要注意更新首尾指针的位置;

2、只剩一个节点(即head = head->next) 的时候,要特别处理;

而添加尾指针是为了插入方便,添加头指针是为了删除方便;如果只有尾指针,那么当删除的节点是尾指针所指节点时, 需要再遍历整个链表,找到尾指针的前驱节点,比较麻烦;

而普通的单链表一般是设立head节点,不需要考虑head删除以后,循环链表首尾断开的问题;

其删除操作如下:

https://blog.csdn.net/weixin_43484734/article/details/83302294

#include <iostream>
#include <vector>
using namespace std;
typedef struct Single{
    int passwd;
    int order;
    bool leave;
    Single* next;
}Single,*List ;

void Init(List& tail, List& head);/*List& tail,尾插法,设立尾指针,时间复杂度为o(1)*/
void Insert(List& tail,List& head, Single*& data);
void del(List& tail,List& head,List& work);//从尾节点开始查找,
void test01();
void test02();
void CountNum(Single* &passwd, int nodeNum, int m);
/*用环形链表实现比较方便一点*/
void CountNum2(List& tail, List& head,vector<int>& sout,int NodeNum, int m);
void Println(vector<int>& sout);
int main() {
    test02();
    return 0;
}

void test01() {
    int a, n, m;
    int nodeNum = 0;
    cin>>a;
    /*if(ab.leave == false){
        cout<<"嗯,怎么不算呢?"<<endl;
    };*/
    Single *pwd = NULL;
    for (int i = 0; i < a; ++i) {
        cin>>n;
        pwd = new Single[10];
        for (int j = 0; j < n; ++j) {
            cin>>pwd[i].passwd;
        }
        cin>>m;
        nodeNum = n;

    }
}

void test02() {
    int a, n, m;
    int nodeNum = 0;
    vector<int> sout;
    cin>>a;
    List Head,tailor;
    Init(tailor,Head);
    for (int i = 0; i < a; ++i) {
        cin>>n;
        for (int j = 0; j < n; ++j) {
            int temp = 0;
            cin>>temp;
            Single * data = new Single ;
            data->passwd = temp;
            data->order = j+1;
            Insert(tailor,Head,data);
            data = NULL;//避免出现野指针;
        }
        cin>>m;
        CountNum2(tailor,Head,sout,n,m);
        Println(sout);
//        sout.swap(vector<int>());
        if(i != a-1) {
            cout<<endl;
        }
    }
}

void Insert( List& tail, List& head,Single*& data){
    Single* temp = data ;
    if(tail == NULL) {
        head = tail = temp;
        tail->next = head;
    } else{
        List back = tail->next;
        tail->next = temp;
        tail = tail->next;
        tail->next = back;
        head = back;
    }
    temp = NULL;
}

void Init(List& tail,List& head) {
   tail = NULL;   head = NULL;
}
void del(List& tail,List& head,List& work) {
    bool del_flag = false;
    List pre = tail;
    List temp  = head;
    if(head != NULL) {
        while (!del_flag) {
                /*删除尾结点该如何解决
                 * 1、添加一个pre指针
                 * 2、那要是删的是pre指针,?*/
            if (temp == temp->next) {/*只剩一个节点*/
                /*temp = temp->next,我是sb,*/
                delete temp;
                temp = NULL;
                head = NULL, tail = NULL;
                del_flag = true;
            } else if(work == temp) {
                List del = temp;
                pre->next = temp->next;
                temp = temp->next;
                if(work == head) {
                    head = temp;
                }else if(work == tail) {
                    tail = pre;
                }
                delete del;
                del_flag = true;
            }else {
                temp = temp->next;
                pre = pre->next;
            }
        }
    }
    /*SIGSEGV (Segmentation fault) 出现这个错误的原因是,删除的时候
     * 忽略了头尾指针,头尾指针不会移动;或者只需要尾指针?
     * */
    work = temp;
}

void CountNum(Single* &passwd, int nodeNum, int m) {
    int index = 0, contrast = 0,count = 0;
    int arrLength = nodeNum;
    while(nodeNum != 0) {
        if(m / nodeNum  != 0) {
            contrast = m % nodeNum;
        }else{
            contrast = m;
        }
        count++;
        index++;
        /*用数组实现的难题是,元素的删除问题,某个元素出列以后,
         *它仍然会占据数组空间;index取模访问元素时,可能会
         *访问到已经出列的元素,考虑考虑用一个数组来存储已经出列的
         *元素的下标,通过for循环来找到,下一个index,但是,问题是,
         *太麻烦了,,时间复杂度也比较高*/
        if(count == contrast) {

        }
    }
}

void CountNum2(List& tail, List& head,vector<int>& sout,int NodeNum, int m) {
    int index = 0, contrast = 0,count = 0;

    List work = head;
    while (NodeNum != 0) {/*work != NULL迭代条件不是这个;但是,如何判断循环链表是否为空呢*/
        if(m % NodeNum == 0) {
            contrast = NodeNum;
        }else {
            contrast = m % NodeNum;
        }
        count++;
        if(count == contrast) {
            sout.push_back(work->order);
            m = work->passwd;
            del(tail,head,work);
            count = 0;
            NodeNum--;
        } else {
            work = work->next;
        }
    }
   /* if(work == NULL) {
        cout<<"亲爱的旅人啊"<<endl;
    }else {
        cout<<"思维惰性"<<endl;
    }*/
}

void Println(vector<int>& sout) {
    /*2、输出结果*/
    //cout<<sout.size()<<endl;
    if(!sout.empty()) {
        for (int i = 0; i < sout.size(); ++i) {
            cout<<sout[i];
            if(i != sout.size() - 1) {
                cout<<" ";
            }
        }
    }
    sout.clear();
    /*cout<<sout.size()<<endl;*/
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值