• 数据结构(五)-环形链表及约瑟夫问题


    一、单向环形链表的应用场景(约瑟夫问题)

    Josephu 问题为:设编号为1,2, ... n 的 n 个人坐成一圈,约定从编号为 k(n≥k≥1) 的人开始报数,数到 m 的那个人出列,她的下一位又从 1 开始报数,数到 m 的那个人又出列,以此类推,直到所有人出圈为止,因此形成一个出圈编号的序列

    二、单向链表的示意图

    三、创建环形链表图解

    创建环形链表代码实现

    // 创建单向环形链表
    class SingleCircularLinkedList{
    	
    	// 初始化一个头节点
    	Girl first = null;
    	
    	// 添加数据到链表中
    	public void add(int num) {
    		// 校验参数
    		if(num < 1) {
    			System.out.println("您输入的小孩个数小于1,不能创建环形链表");
    		}
    		// 定义临时指针
    		Girl curGirl = first;
    		for(int i = 1; i <= num; i++) {
    			Girl girl = new Girl(i);
    			
    			if(i == 1) { // 说明是第一个节点
    				first = girl;
    				first.setNext(first);
    				curGirl = first;
    			}else {
    				curGirl.setNext(girl);
    				curGirl = girl; // curGirl 后移
    				curGirl.setNext(first); // 形成闭环
    			}
    		}
    	}
    	
    	// 遍历链表
    	public void list() {
    		// 判断链表是否为空
    		if(first == null) {
    			System.out.println("当前链表为空");
    			return;
    		}
    		// 定义临时指针
    		Girl curGirl = first;
    		while(true) {
    			System.out.printf("小孩编号为 %d 
    ", curGirl.getNo());
    			if(curGirl.getNext() == first) {
    				break;
    			}
    			curGirl = curGirl.getNext();
    		}
    	}
    }
    
    // 创建节点类
    class Girl {
    
    	private int no;
    	private Girl next;
    
    	public Girl(int no) {
    		super();
    		this.no = no;
    	}
    
    	public int getNo() {
    		return no;
    	}
    
    	public void setNo(int no) {
    		this.no = no;
    	}
    
    	public Girl getNext() {
    		return next;
    	}
    
    	public void setNext(Girl next) {
    		this.next = next;
    	}
    }
    

    四、约瑟夫问题图解

    补充,设置 helper 节点的思路来源于单向链表删除节点时,指针始终指在当前节点的前一位,cur.next = cur.next.next
    代码实现

    	// 约瑟夫问题
    	public void joseph(int startNo, int countNum, int nums) {
    		// 参数校验
    		if(startNo < 1 || countNum > nums || nums < 1) {
    			System.out.println("输入的参数有误");
    			return;
    		}
    		// 定义临时指针
    		Girl helper = first;
    		// 让helper移动到first的上一个节点的位置,让first指针移动到startNo处(移动startNo - 1次)
    		while(true) {
    			if(helper.getNext() == first) {
    				break;
    			}
    			helper = helper.getNext();
    		}
    		
    		for(int i = 0; i < startNo - 1; i++) {
    
    			first = first.getNext();
    			helper = helper.getNext();
    		}
    		
    		// 让first和helper同时移动countNum - 1次,小孩出圈
    		while(true) {
    			if(helper == first) { // 条件成立说明圈中只有一个小孩
    				break;
    			}
    			for(int i = 0; i < countNum - 1; i++) {
    				first = first.getNext();
    				helper = helper.getNext();
    			}
    			// 小孩出圈操作
    			System.out.printf("出圈的小孩为  %d 号
    ", first.getNo());
    			first = first.getNext();
    			helper.setNext(first);
    		}
    		// 输出圈中留下的lucky girl
    		System.out.printf("留在圈中的 lucky girl 为  %d 号
    ", first.getNo());
    	}
    
  • 相关阅读:
    关于WebBrowser(浏览器)控件的调用
    SQLite3.0 beta & ADO.NET Data Provider for SQLite 0.18发布了!
    特别推荐:纯VB.NET代码直接生成Excel文件(不需要Excel)
    关于ASP.NET中独立页面设置身份认证等问题
    关于实时网站资源监控
    关于SQLite.org网站给黑...
    .NET中调用COM的一些问题
    关于数据库空字段和DEFAULT值等问题
    关于软件保护的矛与盾
    (转贴) 微软面试100题——要想成为盖茨就来试试!
  • 原文地址:https://www.cnblogs.com/wsilj/p/13689060.html
Copyright © 2020-2023  润新知