單鏈表的結構
單鏈表的存儲原理圖,head爲頭節點,他不存放任何的數據,只是充當一個指向鏈表中真正存放數據的第一個節點的作用,而每個節點中都有一個next引用,指向下一個節點,就這樣一節一節往下面記錄,直到最後一個節點,其中的next指向null。
代碼實現單鏈表
鏈表節點的定義
鏈表是由一個個節點連接形成的,先定義節點類,節點類主要分數據和next指針
public class ListNode {
public Object data;
public ListNode next = null;
ListNode(){
data = null;
}
ListNode(Object data) {
this.data = data;
}
}
import java.util.Stack;
public class LinkListDemo {
private ListNode head;//頭節點
private ListNode cur;//臨時節點,遊標
//初始化鏈表,生成一個無數據的頭節點
LinkListDemo() {
head = new ListNode();
}
public void addNode(Object data) {
ListNode node = new ListNode(data);
if (head == null) {
head = node;
} else {
cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
}
public int getListLength() {
int len = 0;
cur = head;
while (cur.next != null) {
cur = cur.next;
len++;
}
return len;
}
/**
* 增加節點到指定的位置
*
* @param index
* @param data
* @throws Exception
*/
public void addNodeByIndex(int index, Object data) throws Exception {
if (index < 1 || index > getListLength() + 1) {
throw new Exception("插入位置不合法");
}
int i = 1;
ListNode node = new ListNode(data);
cur = head;
while (cur.next != null) {
if (index == i) {
node.next = cur.next;
cur.next = node;
return;
}
i++;
cur = cur.next;
}
}
/**
* 刪除鏈表指定位置的節點
*
* @param index
* @throws Exception
*/
public void deleteByIndex(int index) throws Exception {
if (index < 1 || index > getListLength() + 1) {
throw new Exception("刪除位置不合法");
}
int i = 1;
cur = head;
while (cur.next != null) {
if (index == i) {
cur.next = cur.next.next;
return;
}
i++;
cur = cur.next;
}
}
/**
* 從頭到尾打印鏈表的數據
*/
public void printListFromHead() {
cur = head;
while (cur.next != null) {
System.out.print("{" + cur.next.data + "} ");
cur = cur.next;
}
System.out.println();
}
/**
* 從尾到頭打印鏈表的數據
* 利用棧的後進先出的存儲特點來實現
*/
public void printListFromTail() {
Stack<ListNode> stack = new Stack<>();
cur = head;
while (cur.next != null) {
stack.push(cur.next);
cur = cur.next;
}
while (!stack.empty()) {
System.out.print("{" + stack.pop().data + "} ");
}
System.out.println();
}
/**
* 反轉鏈表
* 1 → 2 → 3 → Ø,改成 Ø ← 1 ← 2 ← 3
* 記錄下一位,保留上一位元素
* 返回頭結點
*/
public ListNode reverseList() {
ListNode prev = null;
cur = head;
while (cur != null) {
//更改引用之前,需要另一個指針來存儲下一個節點
ListNode temp = cur.next;
cur.next = prev;
prev = cur;//節點沒有引用其上一個節點,因此先存儲當前元素
cur = temp;
}
return prev;
}
/**
* 遞歸反轉鏈表
* 邊界,遞歸入口,遞歸出口,返回新的頭引用
* @param head
* @return
*/
public ListNode recursiveList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p = recursiveList(head.next);
head.next.next = head;
head.next = null;
return p;
}
/**
* 判斷是否有環。快慢指針 或者 用哈希表結構判斷元素是否被訪問過(去重)
* @param head
* @return
*/
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return false;
}
ListNode stepOne = head.next;
ListNode stepTwo = head.next;
while (stepOne != null && stepTwo != null) {
stepTwo = stepTwo.next;
if (stepTwo == null) {
return false;
}
if (stepOne == stepTwo) {
return true;
}
stepOne = stepOne.next;
stepTwo = stepTwo.next;
}
return false;
}
/**
* 通用,可以打印無頭鏈表
* @param p
*/
public void printList(ListNode p) {
cur = p;
while (cur != null) {
System.out.print("{" + cur.data + "} ");
cur = cur.next;
}
System.out.println();
}
public static void main(String[] args) throws Exception {
LinkListDemo list = new LinkListDemo();
list.addNode(1);
list.addNode(2);
list.addNode(3);
list.addNode(4);
list.printListFromHead();
// list.addNodeByIndex(2, 3.3);
// list.printListFromHead();
// list.printListFromTail();
ListNode p = list.reverseList();
list.printList(p);
//ListNode p = list.recursiveList(list.head);
//list.printList(p);
}
}