Java实现链表
单向链表:单向链表是最简单、最基础的链表,它的一个结点(node)分两部分,第一部分存储结点的数据信息(data),第二部分存储指向下一结点的地址(next)信息。最后一个结点(链尾)指向一个空地址(null)。单向链表一般只在链表表头(链头)结点的位置插入元素,这样每次新加入的元素都会在链头位置,而最先加入的元素会在链尾位置。删除操作时,如果在链头位置删除,只需要把头结点指向其下一个结点即可;如果是在中间位置删除,只需要将其前一个结点指向其下一个结点即可。单向链表示意图如下图所示:
代码实现:
import java.util.Stack;
public class LinkedListOnePoint {
private Node head; //头结点
private int size; //链表长度,即链表中结点数量
public LinkedListOnePoint(){
head = null;
size = 0;
}
//私有内部类,代表链表每个结点
private class Node{
private Object data; //链表结点的值
private Node next; //指向的下一个结点
public Node(Object data){
this.data = data;
}
}
//判断链表是否为空
public boolean isEmpty(){
return size==0?true:false;
}
//返回链表长度
public int size(){
return size;
}
//查看链表头结点,不移除
public Object headNode(){
if(size == 0) return null;
return head.data;
}
//在链表表头插入一个结点(入栈)
public void insertInHead(Object obj){
Node newNode = new Node(obj);
if(size == 0){
head = newNode;
}else{
newNode.next = head;
head = newNode;
}
size++;
}
//删除链表表头结点(出栈)
public Object deleteHeadNode(){
if(size == 0) return null;
Object obj = head.data;
if(head.next == null){
head = null; //只有一个结点
}else{
head = head.next;
}
size--;
return obj;
}
//链表查找:判断链表中是否包含某个元素
public boolean containObject(Object obj){
if(size == 0) return false;
Node n = head;
while(n != null){
if(n.data == obj) return true;
else n = n.next;
}
return false;
}
//删除链表中的指定结点(如果包含多个指定结点,只会删除第一个)
public boolean deleteNode(Object obj){
if(size == 0){
System.out.println("链表为空!");
return false;
}
//先在链表中查询是否包含该结点,找到之后获取该结点和其前一个结点
Node previous = null; //前一个结点
Node current = head; //当前结点
while(current.data != obj){
if(current.next == null){
System.out.println("没有找到该结点!");
return false;
}
previous = current;
current = current.next;
}
if(current == head){
this.deleteHeadNode();
}else{
previous.next = current.next;
size--;
}
return true;
}
//正向打印链表
public void display(){
if(size == 0) System.out.println("链表为空!");
Node n = head;
while(n != null){
System.out.print("<-"+n.data);
n = n.next;
}
System.out.println();
}
//反向打印链表(用栈)
public void printListFromTailToHead(Node node){
if(node == null) System.out.println("链表为空!");
Stack<Integer> sta = new Stack<Integer>();
while(node != null){
sta.push((Integer) node.data); //先将链表压入栈中
node = node.next;
}
while(!sta.empty()){
System.out.print(sta.pop()+"<-"); //出栈
}
System.out.println();
}
//反向打印链表(递归)
public void printListFromTailToHeadDiGui(Node node){
if(node == null){
System.out.println("链表为空!");
}else{
if(node.next != null){
printListFromTailToHeadDiGui(node.next);
}
System.out.print(node.data+"<-");
}
}
public static void main(String[] args) {
LinkedListOnePoint list = new LinkedListOnePoint();
System.out.println(list.isEmpty()); //true
System.out.println(list.size()); //0
list.display(); //链表为空!
list.printListFromTailToHead(list.head); //链表为空!
list.insertInHead(0);
list.insertInHead(1);
list.insertInHead(2);
list.insertInHead(3);
list.display(); //<-3<-2<-1<-0
list.printListFromTailToHead(list.head); //0<-1<-2<-3<-
list.printListFromTailToHeadDiGui(list.head); //0<-1<-2<-3<-
System.out.println(list.isEmpty()); //false
System.out.println(list.size()); //4
System.out.println(list.containObject(1)); //true
}
}
双向链表:前面的几种链表只能从头结点遍历到尾结点这一个方向,每个结点都只能指向其下一个结点。而双向链表的每个结点既能指向下一个结点,又能指向前一个结点,双向链表既能从头结点向尾结点遍历,又能从尾结点向头结点遍历,既有一个头结点,又有一个尾结点。
代码实现:
/*
* 双向链表
* 单向链表只可向一个方向遍历,一般查找一个结点的时候需要从第一个结点开始每次访问下一个结点,一直访问到需要的位置。
* 双向链表的每个结点都有指向的前一个结点和后一个节点,既有链表表头又有表尾,即可从链头向链尾遍历,又可从链尾向链头遍历。
* LinkedList中的私有静态内部类Node实际上就是一个双向链表,<E>代表泛型,指明结点的数据类型
* private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
*/
public class LinkedListTwoDirections {
private Node head; //头结点
private Node tail; //尾结点
private int size; //链表长度,即链表中结点数量
public LinkedListTwoDirections(){
head = null;
tail = null;
size = 0;
}
//私有内部类,代表链表每个结点
private class Node{
private Object data; //链表结点的值
private Node previous; //当前结点指向的前一个结点
private Node next; //当前结点指向的下一个结点
public Node(Object data){
this.data = data;
}
}
//判断链表是否为空
public boolean isEmpty(){
return size==0?true:false;
}
//返回链表长度
public int size(){
return size;
}
//查看链表头结点,不移除
public Object headNode(){
if(size == 0) return null;
return head.data;
}
//查看链表尾结点,不移除
public Object tailNode(){
if(size == 0) return null;
return tail.data;
}
//在链表表头插入一个结点
public void insertInHead(Object obj){
Node newNode = new Node(obj);
if(size == 0){
head = newNode;
tail = newNode;
}else{
newNode.next = head;
head.previous = newNode;
head = newNode;
}
size++;
}
//在链表表尾插入一个结点
public void insertInTail(Object obj){
Node newNode = new Node(obj);
if(size == 0){
head = newNode;
tail = newNode;
}else{
newNode.previous = tail;
tail.next = newNode;
tail = newNode;
}
size++;
}
//删除链表表头结点
public Object deleteHeadNode(){
if(size == 0) return null;
Object obj = head.data;
if(head.next == null){ //只有一个结点
head = null;
tail = null;
}else{
head = head.next;
head.previous = null;
}
size--;
return obj;
}
//删除链表表尾结点
public Object deleteTailNode(){
if(size == 0) return null;
Object obj = tail.data;
if(tail.previous == null){ //只有一个结点
head = null;
tail = null;
}else{
tail = tail.previous;
tail.next = null;
}
size--;
return obj;
}
//正向打印链表
public void display(){
if(size == 0) System.out.println("链表为空!");
Node n = head;
while(n != null){
System.out.print("<-"+n.data);
n = n.next;
}
System.out.println();
}
public static void main(String[] args) {
LinkedListTwoDirections list = new LinkedListTwoDirections();
System.out.println(list.isEmpty()); //true
System.out.println(list.size()); //0
list.display(); //链表为空!
list.insertInHead(0);
list.insertInHead(1);
list.insertInHead(2);
list.insertInHead(3);
list.display(); //<-3<-2<-1<-0
System.out.println(list.deleteHeadNode()); //3
list.insertInTail(1);
list.insertInTail(2);
list.display(); //<-2<-1<-0<-1<-2
}
}