目录
目录
使用java操作链表,节点的定义是一个Node类,类的属性有val (存储数据) 和next (Node类,用于指向节点 )。链表结构和增删操作如下:
package com.yugutou.charpter1_linklist.level1;
/**
* 构造链表,使用静态内部类定表示结点,实现增加和删除元素的功能
*
*/
public class BasicLinkList {
static class Node {
final int data;
Node next;
public Node(int data) {
this.data = data;
}
}
public static void main(String[] args) {
// 头部添加节点1
Node head = new Node(1);
System.out.println("头部添加节点1:" + BasicLinkList.toString(head));
System.out.println("链表长度为:" + getLength(head));
// 尾部添加节点2
Node node = new Node(2);
head = BasicLinkList.insertNode(head, node, 2);
System.out.println("尾部添加节点2:" + BasicLinkList.toString(head));
System.out.println("链表长度为:" + getLength(head));
// 中间添加节点3
node = new Node(3);
head = BasicLinkList.insertNode(head, node, 2);
System.out.println("中间添加节点3:" + BasicLinkList.toString(head));
// 删除中间节点2
head = BasicLinkList.deleteNode(head, 2);
System.out.println("删除中间节点3:" + BasicLinkList.toString(head));
// 删除头部节点1
head = BasicLinkList.deleteNode(head, 1);
System.out.println("删除头部节点1:" + BasicLinkList.toString(head));
}
/**
* 获取链表长度
*
* @param head 链表头节点
* @return 链表长度
*/
public static int getLength(Node head) {
int length = 0;
Node node = head;
while (node != null) {
length++;
node = node.next;
}
return length;
}
/**
* 链表插入
*
* @param head 链表头节点
* @param nodeInsert 待插入节点
* @param position 待插入位置,取值从2开始
* @return 插入后得到的链表头节点
*/
public static Node insertNode(Node head, Node nodeInsert, int position) {
// 需要判空,否则后面可能会有空指针异常
if (head == null) {
return nodeInsert;
}
//越界判断
int size = getLength(head);
if (position > size + 1 || position < 1) {
System.out.println("位置参数越界");
return head;
}
//在链表开头插入
if (position == 1) {
nodeInsert.next = head;
// return nodeInsert;
//上面return还可以这么写:
head = nodeInsert;
return head;
}
Node pNode = head;
int count = 1;
while (count < position - 1) {
pNode = pNode.next;
count++;
}
nodeInsert.next = pNode.next;
pNode.next = nodeInsert;
return head;
}
/**
* 删除节点
*
* @param head 链表头节点
* @param position 删除节点位置,取值从1开始
* @return 删除后的链表头节点
*/
public static Node deleteNode(Node head, int position) {
if (head == null) {
return null;
}
int size = getLength(head);
//思考一下,这里为什么是size,而不是size+1
if (position > size || position <1) {
System.out.println("输入的参数有误");
return head;
}
if (position == 1) {
//curNode就是链表的新head
return head.next;
} else {
Node cur = head;
int count = 1;
while (count < position - 1) {
cur = cur.next;
count++;
}
Node curNode = cur.next;
cur.next = curNode.next;
}
return head;
}
/**
* 输出链表
*
* @param head 头节点
*/
public static String toString(Node head) {
Node current = head;
StringBuilder sb = new StringBuilder();
while (current != null) {
sb.append(current.data).append("\t");
current = current.next;
}
return sb.toString();
}
}
单链表
目录
变量传递
java中的方法变量都是存在栈中的,而node节点实例是存储在堆中,每调用一个方法就会开一个新的栈空间,方法之间的相互调用参数传递都是形参指向,互不干扰。
如main方法里调用 insertNode(head, node, 2) 方法,在 insertNode 方法里的head变量无论怎么改变,都不会影响main方法里的head变量。所以在设计上,对链表插入或删除操作(考虑到表头改变了的话),都会返回一个新的表头给main方法里的head变量。
链表插入
表头插入的话,插入的位置是1:直接将InsertNode的next指向原来的head节点,返回InsertNode节点
插入的位置是中间或表尾:逻辑都是一样的:拿到插入位置的前一个节点(preNode),将要插入的节点(InsertNode)指向preNode的next节点,然后将preNode的next指向InsertNode就好了。
链表删除
删除表头,删除的位置是1:直接将head指向head的next,返回head节点。原来的head节点不可到达,会被JVM自动回收
删除中间元素和表尾元素:找到删除位置的前一个节点(preNode),然后将preNode的next指向preNode的next的next,中间的节点无法到达,会被JVM回收
双向链表
在节点类Node里多了一个last (Node) 变量,指向前一个节点。单向链表只能从前往后遍历,而双向链表能双向遍历,从表上任意一个节点开始找,能找到任意一个节点。插入和删除基本逻辑和单链表差不多,但要同时改变节点 next 和 last 的指向。
package com.yugutou.charpter1_linklist.level1;
/**
* 构造链表,使用静态内部类定表示结点,实现增加和删除元素的功能
*
*/
public class BasicLinkList {
static class Node {
final int data;
Node next;
Node last;
public Node(int data) {
this.data = data;
}
}
public static void main(String[] args) {
// 头部添加节点1
Node head = new Node(1);
System.out.println("头部添加节点1:" + BasicLinkList.toString(head));
System.out.println("链表长度为:" + getLength(head));
// 尾部添加节点2
Node node = new Node(2);
head = BasicLinkList.insertNode(head, node, 2);
System.out.println("尾部添加节点2:" + BasicLinkList.toString(head));
System.out.println("链表长度为:" + getLength(head));
// 中间添加节点3
node = new Node(3);
head = BasicLinkList.insertNode(head, node, 2);
System.out.println("中间添加节点3:" + BasicLinkList.toString(head));
// 删除中间节点2
head = BasicLinkList.deleteNode(head, 2);
System.out.println("删除中间节点3:" + BasicLinkList.toString(head));
// 删除头部节点1
head = BasicLinkList.deleteNode(head, 1);
System.out.println("删除头部节点1:" + BasicLinkList.toString(head));
}
/**
* 获取链表长度
*
* @param head 链表头节点
* @return 链表长度
*/
public static int getLength(Node head) {
int length = 0;
Node node = head;
while (node != null) {
length++;
node = node.next;
}
return length;
}
/**
* 链表插入
*
* @param head 链表头节点
* @param nodeInsert 待插入节点
* @param position 待插入位置,取值从2开始
* @return 插入后得到的链表头节点
*/
public static Node insertNode(Node head, Node nodeInsert, int position) {
// 需要判空,否则后面可能会有空指针异常
if (head == null) {
return nodeInsert;
}
//越界判断
int size = getLength(head);
if (position > size + 1 || position < 1) {
System.out.println("位置参数越界");
return head;
}
//在链表开头插入
if (position == 1) {
nodeInsert.next = head;
head.last = nodeInsert;
// return nodeInsert;
//上面return还可以这么写:
head = nodeInsert;
return head;
}
Node pNode = head;
int count = 1;
while (count < position - 1) {
pNode = pNode.next;
count++;
}
nodeInsert.next = pNode.next;
pNode.next = nodeInsert;
//如果插入的不是尾部,要把下一个节点的last指向InsertNode
if (nodeInsert.next != null){
nodeInsert.next.last = nodeInsert;
}
nodeInsert.last = pNode;
return head;
}
/**
* 删除节点
*
* @param head 链表头节点
* @param position 删除节点位置,取值从1开始
* @return 删除后的链表头节点
*/
public static Node deleteNode(Node head, int position) {
if (head == null) {
return null;
}
int size = getLength(head);
//思考一下,这里为什么是size,而不是size+1
if (position > size || position <1) {
System.out.println("输入的参数有误");
return head;
}
if (position == 1) {
//curNode就是链表的新head
head.next.last = null;
Node newHead = head.next;
head.next = null;
return newHead;
} else {
Node cur = head;
int count = 1;
while (count < position - 1) {
cur = cur.next;
count++;
}
Node curNode = cur.next;
cur.next = curNode.next;
curNode.next.last = curNode.last;
curNode.next = null;
curNode.last = null;
}
return head;
}
/**
* 输出链表
*
* @param head 头节点
*/
public static String toString(Node head) {
Node current = head;
StringBuilder sb = new StringBuilder();
//检查next指针
// while (current != null) {
// sb.append(current.data).append("\t");
// current = current.next;
// }
//检查last指针,从尾部遍历
while (current.next != null) {
current = current.next;
}
while (current != null){
sb.append(current.data).append("\t");
current = current.last;
}
return sb.toString();
}
}