单链表的结构
单链表的存储原理图,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);
}
}