zoukankan      html  css  js  c++  java
  • 用循环链表实现约瑟夫环问题

    什么是约瑟夫环问题?

    而这实际上就是一个经典的数学问题:

    而用一个更生活化的例子来阐述:几个人围坐在一张圆桌上,然后开始数数,数到指定数则淘汰,然后再重1开始数,直到还剩最后一个人则为胜利者。

    而具体代码如何来实现呢?

    首先还是基于上次的那个链表进行扩展:

    接着构造一个循环链表,为了使代码更加的清晰,这里采用面向对象的方法来进行封装

    接下来就是去实现这个add方法,如何在这个方法中实现一个循环链表呢?下面用图来模拟下整个组建的一个过程从而形成一个实现思路:

    1、添加第一个元素“0”:

    由于目前里面只有一个元素,所以自身指向自已形成一个环,而tail变量是有用的,这个等下面就可以看出来。 

    2、添加第一个元素“1”

    将之前元素的下一个节点指向新建的结点,而新建结点的下一个节点指向tail的next,也就是node1,而将tail指向新建的结点。

    3、添加第一个元素“2”:

    同样的也是新建节点的next指向之前tail的next,tail的next指向新建的结点,而tail变更为指向新节点。

    而tail变量的作用也比较清楚了,就是最后可以用它来遍历,并且对于组成环也有比较重要的作用。

    通过上面三个步骤,可以总结点这个添加成环有两种情况:一个是添加第一个元素的时候;另一个则是非第一个元素,有了上面的思路之后下面看代码具体实现:

    上面的实现比较好理解,下面编写一个打印方法看否里面添加的元素都正常打印了,这时tail变量就发挥作用啦:

    编译运行:

    正确打印,接下来就到了最关键的步骤,开始实现数数淘汰的问题,这个首先先声明一个方法:

    那具体如何实现呢?还是先画图整理思路,假如是如下四个结点:

    这里以数3就淘汰的规则来整理【从node1开始数数】:

    1、首先判断边界条件:如果链表则空或链表只有一个元素时,则没必要进行数数了。

    2、首先数3-1=2下,为啥不数满3下呢?因为如果如图中所示,第一次要淘汰的是node3,也就是要删掉node3之前,得将node3这个元素获取出来,不然的话数满三下到了node3直接将其删掉会导致程序无法继续了,所以这里是数到第二下到node2这个节点就暂停。

    3、获得要淘汰的元素node3,并将node2.next=node2.next.next:

    4、在删除node3之前,有一种特珠情况需要注意,如图:

    那在删除node4之前,首先需要将tail指向p,也就是node2,不然到的把node4删掉了tail也为null了,这样整个状态就不对了,这是需要注意到的。

    5、删除要淘汰的无毒,而C++中则是将无用的内存delete掉既可。

    有了上面的思路之后,下面的具体实现就不难啦,具体如下:

    编译运行:

    那对于这个算法的时间复杂度是多少呢?下面来看一下:

    所以T(n) = (n - 1) * ((k-1) + c[假设常量级别用c表示]) 

    而将常量级别的c给忽略掉,则进一步换算T(n) = (n-1) * (k - 1) = nk - n - k + 1

    进一步将常量1给忽略掉,而T(n) = nk - n - k = nk - c0[加上一个系数]n - c1[加上一个系数]k 

    所以它的时间复杂度为:O(nk)

    其实对于约瑟夫环问题还可以用数组来更好的实现,而它的时间复杂度跟用链表实现是一样的,这个在下篇继续学习~

  • 相关阅读:
    easy ui 表单ajax和from两种提交数据方法
    easy ui 下拉级联效果 ,下拉框绑定数据select控件
    easy ui 下拉框绑定数据select控件
    easy ui 异步上传文件,跨域
    easy ui 菜单和按钮(Menu and Button)
    HTTP 错误 404.3
    EXTJS4.2 后台管理菜单栏
    HTML 背景图片自适应
    easy ui 表单元素input控件后面加说明(红色)
    EXTJS 4.2 添加滚动条
  • 原文地址:https://www.cnblogs.com/webor2006/p/7102568.html
Copyright © 2011-2022 走看看