Java单链表实现
- 单链表各位置插入结点
- 单链表各位置删除结点
- 单链表正逆向遍历结点
单链表是实现栈、队列、哈希表等多种数据结构的基础,在此总结一下Java单链表中不同位置插入节点、不同位置删除结点、正逆向遍历结点的方法,以备以后复习时用。本人菜鸟一枚,如有错误请各位大佬批评指正。
-
单链表插入结点,根据插入位置不同可以分为:
- 在头结点处插入结点,时间复杂度o(1),addFirst(int val)
- 在尾结点处插入结点,时间复杂度o(n),addLast(int val)
- 在任意位置插入结点,时间复杂度o(n),add(int index,int val) 单链表删除结点,根据插入位置不同可以分为:
- 在头结点处删除结点,时间复杂度o(1),deleteFirst()
- 在尾结点处删除结点,时间复杂度o(n),deleteLast()
- 在任意位置删除结点,时间复杂度o(n),delete(int index,int val) 单链表的遍历:
- 正向遍历,display()
- 逆向遍历,displayFromTail()
采用单链表实现栈(先入后出)的功能,可以采用addFirst()和deleteLast()方法封装为push()和pop()方法;
采用单链表实现队列(先入先出)的功能,可以采用addFirst()和deleteFirst()方法封装为enqueue()和dequeue()方法;
代码如下:
package chapter.two.bean;
public class ListNode {
/***
* 结点内部类
* @author Janet
*
*/
private class Node{
int val;
Node next;
Node(int val) {
this.val = val;
}
}
//私有字段
private Node first = null;
private int N = 0;
/***
* 判断链表是否为空
* @return
*/
public boolean isEmpty() {
return N==0;
}
/**
* 返回链表结点数
* @return
*/
public int size() {
return N;
}
/***
* 在头结点处添加元素,时间复杂度o(1)
* @param val
*/
public void addFirst(int val) {
if( isEmpty() ) {
first = new Node(val);
first.next = null;
} else {
Node newFirst = new Node(val);
newFirst.next = first;
first = newFirst;
}
N++;
}
/***
* 在链表结尾处添加元素,时间复杂度o(n)
* @param val
*/
public void addLast(int val) {
if( isEmpty() ) {
first = new Node(val);
first.next = null;
} else {
Node p = first;
while( p.next != null ) {
p = p.next;
}
//p为尾结点
p.next = new Node(val);
p.next.next = null;
}
N++;
}
/***
* 在任意位置添加元素,时间复杂度o(n)
* @param index
* @param val
* @throws Exception
*/
public void add(int index,int val) throws Exception {
if( index>=size() || index<0 ) {
throw new Exception("链表不存在该位置");
} else {
if( index==0 ) {
addFirst(val);
return;
}
Node p = first;
for (int i = 1; i < index; i++) {
p = p.next;
}
//在p处添加新节点
Node q = new Node(val);
q.next = p.next;
p.next = q;
N++;
}
}
/***
* 删除头结点并返回,时间复杂度o(1)
* @return
*/
public Node deleteFirst() {
Node result = first;
first = first.next;
N--;
return result;
}
/***
* 删除最后一个结点并返回,时间复杂度o(1)
* @return
*/
public Node deleteLast() {
Node p = first;
while( p.next.next != null ) {
p = p.next;
}
//要删除p.next
Node result = p.next;
p.next = null;
N--;
return result;
}
/***
* 删除任意位置的结点并返回,时间复杂度o(n)
* @param index
* @return
* @throws Exception
*/
public Node delete(int index) throws Exception {
if( index<0 || index>=size() ) {
throw new Exception("链表不存在该位置");
} else {
if( index==0 ) {
N--;
return deleteFirst();
} else {
Node p = first;
for (int i = 1; i < index-1; i++) {
p = p.next;
}
//p.next(q)为要删除的结点
Node q = p.next;
p.next = q.next;
q.next = null;
N--;
return q;
}
}
}
/***
* 正向遍历链表
*/
public void display() {
for (Node temp = first; temp!=null; temp=temp.next)
System.out.println(temp.val);
}
/***
* 逆向遍历链表
*/
public void displayFromTail() {
displayFromTail(first);
}
private void displayFromTail(Node p) {
if( p != null ) {
if( p.next != null ) {
displayFromTail(p.next);
}
System.out.println(p.val);
}
}
}
-
ListNode链表类中定义了私有字段
- Node first:头结点
- N:链表中结点个数,通过方法size()获取
在任意位置的插入删除中,约定链表的位置(index)从0开始
-
关于逆向遍历链表
-
参考剑指offer面试题5:从尾到头打印链表
要逆向遍历链表,可以考虑正向遍历链表,并依次把结点元素存到栈中,由于栈是递归的一种形式,可以由此想到用递归来解决。如果结点p有next域,就递归调用displayFromTail(p.next)即可。