public class RecycleQueue<Item> {
//尾节点也是当前节点(current)
Node last;
//队列中元素的个数
static int N;
//节点Node
private class Node<Item>{
//该节点的值
Item item;
//后节点
Node next;
public Node(Item item,Node next){
this.item = item;
this.next = next;
}
public Node(){
}
}
public RecycleQueue(Item item){
last = new Node(item,null);
//既是尾节点又是首节点,需要自己和自己建立关联
//这步很关键
//它记录了last的下一个节点(首节点)
last.next = last;
N = 1;
}
//void enqueue(Item item)
//入队
public void enqueue(Item item){
Node newNode = new Node(item,null);
//添加节点时尽量从新节点开始着手插入
//这里是 newNode.next = last.next 而不是newNode.next = last; 后者只能保存两个元素
newNode.next = last.next;
last.next = newNode;
//last节点既是尾节点又是当前节点,添加节点之后,last节点后移
last = last.next;
N++;
}
//Item dequeue()
//出队
public Item dequeue(){
Node del = last.next;
Item ret = (Item)del.item;
//根据队列的性质,出队元素为队首元素,即last后面的一个节点
last.next = last.next.next;
del = null;
N--;
return ret;
}
//boolean isEmpty()
//队列是否为空
public boolean isEmpty(){
return N == 0;
}
//int size()
//队列中元素的个数
public int size(){
return N;
}
//暴力方法实现
//反复遍历环形循环队列
public static void josephus(int Num,int M){
if(Num == 1) StdOut.println(0);
RecycleQueue rq = new RecycleQueue(0);
for(int i = 1;i < Num;i++){
rq.enqueue(i);
}
int count = 1;
RecycleQueue.Node pre = rq.new Node();
//这里结合单向环形队列的特性(只有一个last节点指向队列),
//我们需要在每次循环中删除一个指定的节点
//这个删除操作可以通过一个pre节点完成,如果引入curr(当前)节点则需要两个节点(pre,curr)
//所以这里直接可以巧妙的运用pre完成指针后移和节点删除
pre = rq.last;
while(!rq.isEmpty()){
if(count % M == 0){
//删除节点
Object item = pre.next.item;
pre.next = pre.next.next;
N--;
StdOut.println(item);
}else{
//刚开始写的是pre.next = pre.next.next 但是调试的时候发现这种写法是错误的
//想要完成pre指针后移通过pre = pre.next;
pre = pre.next;
}
count++;
}
}
public static void main(String[] args){
// RecycleQueue<String> rq = new RecycleQueue<>("whz");
/*StdOut.println(rq.dequeue());
StdOut.println(rq.dequeue());
StdOut.println(rq.dequeue());*/
/*while(!rq.isEmpty()){
StdOut.println(rq.dequeue());
}*/
josephus(7,2);
}
}
使用last节点完成一个单向循环队列
最新推荐文章于 2024-09-24 01:58:36 发布