Java环形链表实现和应用(约瑟夫问题) -- 数据结构的学习

环形链表实现和应用

package algorithm.linkedlist;

/**
 * 约瑟夫环问题
 * N个人(1..N)从第K个人开始报数从1到M(1..M),报到M的那个人出列,直到全部退出
 * 幸运数字:最后那个人就是幸运数字
 * @author lenovo
 *
 */
public class CircleSingleLinkedListDemo {
	public static void main(String[] args) {
		
		CircleSingleLinkedList list = new CircleSingleLinkedList();
		//增
		list.createList(5);
		list.show();
		//删,注意删除的头结点的问题
		System.out.println("--------");
		list.del(2);
		list.show();
		//改,查
		Node node = list.find(2);
		System.out.println("node = " + node);
		list.update(5);
		list.show();
		
		//约瑟夫问题,幸运数字
		System.out.println("josephu-----------");
		int n = 5;
		int k = 2;
		int count = 3;
		josephu(n,k,count);
		josephu(2,2,1);
		
		
	}
	
	/**
	 * 约瑟夫问题
	 * @param n 总人数
	 * @param k 从第几个人开始
	 * @param count 数几个数
	 */
	private static void josephu(int n, int k, int count) {
		//判断参数
		if (n < 1 || k > n || count < 0 ) {
			System.out.println("参数错误");
			return;
		}
		//生成链表
		CircleSingleLinkedList list = new CircleSingleLinkedList();
		list.createList(n);
//		list.show();
		//指向头,尾指针 : 尾指针用来删除节点(删除需要找被删除节点的上一个节点)
		Node head = list.getHead();
		Node tail = head;
		while(tail.getNext() != head) {
			tail = tail.getNext();
		};
		//从第K个节点开始
		for (int i = 0; i < k -1; i++) {//移动次数 k-1次
			head = head.getNext();//指针后移,指向第K个节点
			tail = tail.getNext();//指针后移,指向头节点的上一个节点,删除使用
		}
		while(head != tail) {//头尾节点指向同一个节点,则环形链表只剩最后一个
			//每走count次,就删除当前节点
			for (int i = 0; i < count-1; i++) {
				head = head.getNext();
				tail = tail.getNext();
			}
			System.out.println(head + "出局");
			//删除操作
			head = head.getNext();
			tail.setNext(head);
		}
		System.out.println(head + "为幸运儿");	
	}
}


/**
 * 环形单链表(没有所谓的头结点,全部是有效节点)
 * 头结点:不含数据
 * @author lenovo
 *
 */
class CircleSingleLinkedList{
	//指针指向头head
	private Node head;
	
	
	public Node getHead() {
		return head;
	}

	public void setHead(Node head) {
		this.head = head;
	}

	/**
	 * 创建环形链表
	 * @param num 添加节点数目
	 */
	public void createList(int num) {
		
		if (num < 1) {
			System.out.println("参数错误");
			return;
		}
		//辅助指针,遍历时向后移动
		Node cur = head;//null
		for (int i = 1; i <= num; i++) {
			Node node = new Node(i, ""+i+i);
			//head指向第一个节点
			if (i == 1) {
				head = node;
				head.setNext(head);//环
				cur = head;
			}else {
				//当前节点next存放新添加的节点
				cur.setNext(node);
//				node.setNext(head);
//				cur = node;
				cur = cur.getNext();//指针后移
				cur.setNext(head);//新添加的节点next指向头,形成环      == node.setNext(head)
			}
		}
	}
	
	/**
	 * 显示(遍历)
	 */
	public void show() {
		if (head.getNext() == null) {
			System.out.println("空链表");
			return;
		}
		Node temp = head;
		while(true) {//temp.getNext() != head 不能这么写,丢失最后一个节点
			System.out.println(temp);
			if (temp.getNext() == head) {//遍历到链尾,注意先打印在退出,否则丢失最后一个节点。注意:删除头结点的问题导致此条件会用不成立
				break;
			}
			temp = temp.getNext();//指针后移
		}
	}
	/**
	 * 删除
	 * 和单链表删除原理一样,找被删节点的前一个节点
	 * @param no 删除的no
	 */
	public void del(int no) {
		
		if (head.getNext() == null) {
			System.out.println("空链表");//没有一个节点存在,单链表中时的空链表时表示没有一个有效节点存在
			return;
		}
		Node temp = head;//辅助指针,遍历使用
		boolean flag = false;//表示查找到指定节点  默认否
		/*while(true) {
			//第一次比较的是第二个有效节点
			if (temp.getNext().getNo() == no) {
				flag = true;
				break;
			}
			temp = temp.getNext();//指针后移,注意顺序
			
			if (temp == head) {//链尾,1.注意写的顺序,需要写在最后  2.不是temp.getNext() == head  因为第一次比较的第二个节点,最后比较的是头结点
				break;
			}
		}*/
		 do{ 
			  if (temp.getNext().getNo() == no) {
				  flag = true;
				  break;
		  		} 
			  temp = temp.getNext();//指针后移

		 }while(temp != head);
		 
		if (flag) {
			//找到要删除节点的前一个节点temp,注意 ,这里若是头结点,需要将head指针后移,让原先头结点的下一个节点作为头结点,否则遍历出现问题。原因:node.getNext() == head
			if (temp.getNext() == head) {
				head = temp.getNext().getNext();//将head指针后移,让原先头结点的下一个节点作为头结点
			}
			temp.setNext(temp.getNext().getNext());
		}else {
			System.out.println("delete未找到");
		}
	}
	
	
	
	/**
	 * 修改
	 * 找当前的节点进行比较
	 * @param no
	 */
	public void update(int no) {
		// TODO Auto-generated method stub
		if (head.getNext() == null) {
			System.out.println("空链表");//没有一个节点存在,单链表中时的空链表时表示没有一个有效节点存在
			return;
		}
		Node cur = head;//辅助指针,遍历使用
		boolean flag = false;//表示查找到指定节点  默认否
		while(true) {
			if (cur.getNo() == no) {
				flag = true;
				break;
			}
			if (cur.getNext() == head) {//遍历玩所有节点
				break;
			}
			cur = cur.getNext();
		}
		if (flag) {
			cur.setName("修改过");
		}else {
			System.out.println("update未找到");
		}
	}
	/**
	 * 查找
	 * @param no
	 * @return
	 */
	public Node find(int no) {
		if (head.getNext() == null) {
			System.out.println("空链表");//没有一个节点存在,单链表中时的空链表时表示没有一个有效节点存在
			return null;
		}
		Node cur = head;//辅助指针,遍历使用
		
		while(true) {
			if (cur.getNo() == no) {
				return cur;
			}
			if (cur.getNext() == head) {//遍历玩所有节点
				break;
			}
			cur = cur.getNext();
		}
		return null;
	}
	
}
/**
 * 节点
 * @author lenovo
 *
 */
class Node{
	
	private int no;
	private String name;
	private Node next;
	
	public Node getNext() {
		return next;
	}

	public void setNext(Node next) {
		this.next = next;
	}

	public Node(int no,String name) {
		this.no = no;
		this.name = name;
	}
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Node [no=" + no + ", name=" + name + ", next= "+ next.getNo()+"]";
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值