單鏈表的實現,判斷是否有環和環的入口,找到鏈表的中間節點和倒數第k個節點

單鏈表的核心是頭節點,定義一個next指針指向下一個節點的位置java

package cn.chinotan.linkedList;

public class LinkList {

	private Node head;

	public Node getHead() {
		return head;
	}

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

	// 插入
	public void insert(int msg) {
		Node node = new Node(msg);
		if (head == null) {
			head = node;
		} else {
			Node cNode = head;
			while (cNode.next != null) {
				cNode = cNode.next;
			}
			cNode.next = node;
		}
	}

	// 遍歷當前鏈表
	public void printLink() {
		Node cNode = head;
		while (cNode != null) {
			System.out.println(cNode.msg);
			cNode = cNode.next;
		}
	}

	// 刪除某個節點(根據索引號)
	public void delete(int index) {
		if (index < 0 || index > (len() - 1)) {
			return;
		}
		if (index == 0) {
			head = head.next;
			return;
		}
		Node pNode = head;
		Node cNode = pNode.next;
		int i = 1;
		while (cNode != null) {
			if (i == index) {
				pNode.next = cNode.next;
			}
			pNode = cNode;
			cNode = cNode.next;
			i++;
		}
	}

	// 刪除某個節點(根據節點刪除)
	public void delete(Node dNode) {
		if (dNode == null) {
			return;
		}

		dNode.msg = dNode.next.msg;
		dNode.next = dNode.next.next;
	}

	// 統計鏈表長度
	public int len() {
		Node cNode = head;
		int count = 0;
		while (cNode != null) {
			count++;
			cNode = cNode.next;
		}
		return count;
	}

	// 翻轉鏈表輸出(採用遞歸)
	public void reverseLink(Node node) {
		if (node != null) {
			reverseLink(node.next);
			System.out.println(node.msg);
		}
	}

	// 查找最中間的節點(採用快慢指針,快指針一下走兩步,慢指針一下走一步,當快指針走完時,慢指針正好走到中間點,此時慢指針的位置就是要求的位置)
	public void midLink() {
		Node slow = head;
		Node fast = head;
		while (fast != null && fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}

		System.out.println("中間節點爲:" + slow.msg);
	}

	// 查找倒數第k節點(採用快慢指針,快指針一下走一步,慢指針一下走一步,快指針先走k步,以後慢指針和快指針一塊兒走,當快指針到終點時,滿指針的位置即所求點)
	public void findElem(int i) {
		int k = i;
		if (k < 1 || k > len()) {
			return;
		}
		Node slow = head;
		Node fast = head;

		for (; k != 0; k--) {
			fast = fast.next;
		}

		while (fast != null) {
			fast = fast.next;
			slow = slow.next;
		}
		System.out.println("倒數第" + i + "個節點爲" + slow.msg);
	}

	// 判斷鏈表是否有環(採用快慢指針,快指針一下走兩步,慢指針一下走一步,當沒有遍歷完時,快指針和慢指針遇到後就說明鏈表有環)
	public Boolean isLoop() {
		Node slow = head;
		Node fast = head;
		while (fast != null && fast.next != null) {
			fast = fast.next.next;
			slow = slow.next;
			if (fast == slow) {
				System.out.println("該列表有環");
				return true;
			}
		}
		System.out.println("該列表沒有環");
		return false;
	}

	// 找到鏈表的環的入口(採用快慢指針,記住頭節點到環的入口所走過的路和快慢指針相遇點到環的入口所走過的路是同樣的)
	public void findLoopPort() {
		Node slow = head;
		Node fast = head;

		while (fast != null && fast.next != null) {
			fast = fast.next.next;
			slow = slow.next;

			if (fast == slow) {
				break;
			}
		}

		if (fast == null) {
			return;
		}

		slow = head;
		while (fast != slow) {
			slow = slow.next;
			fast = fast.next;
		}

		System.out.println("環的入口爲:" + slow.msg);
	}

	public static void main(String[] args) {
		int[] is = { 0, 2, 5, 7, 88, 2, 1, 66, 99 };
		LinkList linkList = new LinkList();
		for (int i : is) {
			linkList.insert(i);
		}
		System.out.println("原長度" + linkList.len());
		linkList.printLink();
		linkList.delete(3);
		System.out.println("刪除後的長度" + linkList.len());
		System.out.println("刪除後的值:");
		linkList.printLink();
		linkList.delete(linkList.head.next);
		System.out.println("刪除後的長度" + linkList.len());
		System.out.println("刪除後的值:");
		linkList.printLink();
		System.out.println("翻轉鏈表:");
		linkList.reverseLink(linkList.head);
		linkList.midLink();
		linkList.findElem(4);

		// 環鏈表生成
		Node cNode = linkList.head;
		while (cNode.next != null) {
			cNode = cNode.next;
		}
		cNode.next = linkList.head.next;
		linkList.isLoop();
		linkList.findLoopPort();
	}

	class Node {

		int msg;

		Node next;

		public Node(int msg) {
			this.msg = msg;
		}
	}

}
相關文章
相關標籤/搜索