数据的存储一般分线性存储结构和链式存储结构两种。前者是一种顺序的存储方式,在内存中用一块连续的内存空间存储数据,即逻辑上相连的物理位置相邻,比较常见的就是数组;后者是一种链式存储方式,不保证顺序性,逻辑上相邻的元素之间用指针所指定,它不是用一块连续的内存存储,逻辑上相连的物理位置不一定相邻。本篇主要介绍链式存储结构基于链表的实现,使用的语言为Java。
链表是一种递归的数据结构,它要么为空(null),要么指向是指向一个结点(node)的引用,该节点含有一个泛型元素(该泛型元素可以是任意数据类型),和一个指向另一个链表的引用。链表有很多种,下面主要介绍单向链表、双端链表、有序链表、双向链表。
单向链表:单向链表是最简单、最基础的链表,它的一个结点(node)分两部分,第一部分存储结点的数据信息(data),第二部分存储指向下一结点的地址(next)信息。最后一个结点(链尾)指向一个空地址(null)。单向链表一般只在链表表头(链头)结点的位置插入元素,这样每次新加入的元素都会在链头位置,而最先加入的元素会在链尾位置。删除操作时,如果在链头位置删除,只需要把头结点指向其下一个结点即可;如果是在中间位置删除,只需要将其前一个结点指向其下一个结点即可。单向链表示意图如下图所示:
单向链表的Java代码实现:
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 } }