07、数据结构与算法 - 实战:单向环形链表

单向环形链表 - 无头指针

 

测试类

class Student2 {
	private int id;
	private String name;
	public Student2(int id, String name) {
		this.id = id;
		this.name = name;
	}
	@Override
	public String toString() {
		return "Student2 [id=" + id + ", name=" + name + "]";
	}
}

增加元素、遍历链表

代码实现 - 增加元素

class SingleCircularLinkedList<T> {
	private Node<T> firstNode = null;
	// 向尾部增加一个节点
	public void add(T t) {
		// 1.将添加的元素封装成节点
		Node<T> newNode = new Node<T>(t);
		// 2.1 如果链表为空则直接单元素环形链表
		if (firstNode == null) {
			firstNode = newNode;
			firstNode.next = firstNode;
			return;
			// 2.2 如果链表中有一个元素
		} else if (firstNode == firstNode.next) {
			firstNode.next = newNode;
			newNode.next = firstNode;
			return;
			// 2.3 链表中存在2个或以上的元素
		} else {
			// 当前遍历到的节点
			Node<T> temp = firstNode;
			// 遍历获取到最后一个节点
			while (temp.next != firstNode) {
				temp = temp.next;
			}
			temp.next = newNode;
			newNode.next = firstNode;
		}
	}
	private class Node<T> {
		T date;
		Node<T> next;
		Node(T date) {
			this.date = date;
		}
		@Override
		public String toString() {
			return date.toString();
		}
	}
}

代码实现 - 遍历节点

@Override
public String toString() {
    // 头节点为null
    if (firstNode == null) {
        return null;
    }
    StringBuilder sb = new StringBuilder();
    // 遍历到的当前节点
    Node<T> temp = firstNode;
    while (true) {
        sb.append(temp.toString() + "\n");
        if (temp.next == firstNode) {
            break;
        }
        temp = temp.next;
    }
    sb.delete(sb.lastIndexOf("\n"), sb.length());
    return sb.toString();
}

测试代码

public static void main(String[] args) {
    Student2 stu1 = new Student2(1, "lrc");
    Student2 stu2 = new Student2(2, "glw");
    Student2 stu3 = new Student2(3, "yte");
    SingleCircularLinkedList<Student2> scll = new SingleCircularLinkedList<Student2>();
    scll.add(stu1);
    scll.add(stu2);
    scll.add(stu3);
    System.out.println(scll);
}

测试结果
 

约瑟夫出队 – 需改变链表结构

 
 


 


 

代码实现

/**
 * 
 * @Description
 * @param k 开始从第几个节点开始报数
 * @param m 每次报数起,数多少次
 */
public void JosephOut(int k, int m) {
    // 1. 链表必须有元素
    if(length() == 0) {
        System.out.println("链表中无元素");
        return;
        // 2. 开始从第几个节点数,必须小于 链表的长度
    }else if(length() < k || k < 0 ) {
        System.out.println("参数K不符合输入要求");
        return;
    }else {
        // 3.1 需要两个指针, -个是准备出队的那个节点指针,另一个是firstPointer节点后面那个节点
        Node<T> firstPointer = firstNode;
        Node<T> secondPointer = firstNode; 
        // 3.2 需要到从第K个节点开始遍历出队的指针
        for(int i = 1; i < k; i++) {
            firstPointer = firstPointer.next;
            if(i >= 2) {
                secondPointer = secondPointer.next;
            }
        }
        // 3.3 需要一个标志位来判断 firstPointer.secondPointer节点是否是前后关系
        boolean flag = false;
        // 3.4 开始遍历出队
        while(true) {
            // 3.4.1 有元素出队后,需要重新遍历查找下一个出队的节点 - 移动m-1次
            for(int i = 0; i<m-1; i++) {
                if(k == 1 && i == 0 && flag == false) {
                    firstPointer = firstPointer.next;
                    flag = true;
                    continue;
                }else {
                    firstPointer = firstPointer.next;
                    secondPointer = secondPointer.next;
                }
            }
            // 3.4.2 打印出队元素,并且调整链表中的节点
            System.out.println(firstPointer);
            firstPointer = firstPointer.next;
            secondPointer.next = firstPointer;
            // 如果最后整个单向环形链表只有一个元素,则直接退出循环
            if(secondPointer.next == secondPointer) {
                break;
            }
        }
        // 4. 打印链表最后一个节点
        System.out.println(secondPointer);
        // 5. 将链表置空
        firstNode = null;
    }
}	

约瑟夫问题

 

代码测试

public static void main(String[] args) {
    // 1. 定义、初始化6个人
    Student2 stu1 = new Student2(1, "lrc");
    Student2 stu2 = new Student2(2, "glw");
    Student2 stu3 = new Student2(3, "yte");
    Student2 stu4 = new Student2(4, "erw");
    Student2 stu5 = new Student2(5, "ghb");
    Student2 stu6 = new Student2(6, "fgh");
    SingleCircularLinkedList<Student2> scll = new SingleCircularLinkedList<Student2>();
    // 2. 将6个人添加到链表里面
    scll.add(stu1);
    scll.add(stu2);
    scll.add(stu3);
    scll.add(stu4);
    scll.add(stu5);
    scll.add(stu6);
    System.out.println("人数N = " + scll.length());
    int M = 5; int K = 1;
    // 3. 约瑟夫出列
    scll.JosephOut(K, M);
}

运行结果