链表(LinkedList)
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点(链表中每一个元素称为节点)组成,节点可以在运行时动态生成。每个节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。
相比于线性表顺序结构,链表操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
链表分为单链表和双向链表。
1、单向链表(Single-Linked List)
单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,第一个部分也就是数据部分,保存关于节点的数据信息,另一个部分则存储下一个节点的地址。当然,最后一个节点存储地址的部分指向空值。
对于单向链表,我们只可以单方向进行遍历,也就是从头节点往后依次访问后面的节点,一直访问到需要的位置。而插入一个节点,则只能在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点可。删除一个节点,需要将该节点的上一个节点的next指向该节点的下一个节点。
public class SingleLinkedList {
private int size;//链表节点的个数
private Node head;//链表的头节点
//链表构造函数
public SingleLinkedList(){
size = 0;
head = null;
}
//链表的节点类
private class Node{
private Object data;//每个节点的数据
private Node next;//每个节点指向下一个节点的连接
public Node(Object data){
this.data = data;
}
}
//在链表头添加元素
public Object addHead(Object obj){
Node newHead = new Node(obj);
if(size == 0){
head = newHead;
}else{
newHead.next = head;
head = newHead;
}
size++;
return obj;
}
//在链表头删除元素
public Object deleteHead(){
Object obj = head.data;
head = head.next;
size--;
return obj;
}
//查找指定元素,找到了返回节点Node,找不到返回null
public Node find(Object obj){
Node current = head;
int tempSize = size;
while(tempSize > 0){
if(obj.equals(current.data)){
return current;
}else{
current = current.next;
}
tempSize--;
}
return null;
}
//删除指定的元素,删除成功返回true
public boolean delete(Object value){
if(size == 0){
return false;
}
Node current = head;
Node previous = head;
while(current.data != value){
if(current.next == null){
return false;
}else{
previous = current;
current = current.next;
}
}
//如果删除的节点是第一个节点
if(current == head){
head = current.next;
size--;
}else{ //如果删除的节点不是第一个节点
previous.next = current.next;
size--;
}
return true;
}
//判断链表是否为空
public boolean isEmpty(){
return (size == 0);
}
//显示节点信息
public void display(){
if(size >0){
Node node = head;
int tempSize = size;
if(tempSize == 1){//当前链表只有一个节点
System.out.println("["+node.data+"]");
return;
}
while(tempSize>0){
if(node.equals(head)){
System.out.print("["+node.data+"->");
}else if(node.next == null){
System.out.print(node.data+"]");
}else{
System.out.print(node.data+"->");
}
node = node.next;
tempSize--;
}
System.out.println();
}else{//如果链表一个节点都没有,直接打印[]
System.out.println("[]");
}
}
}
测试程序代码如下:
public static void SingleLinkedListTest(){
SingleLinkedList singleList = new SingleLinkedList();
singleList.addHead("1");
singleList.addHead("2");
singleList.addHead("3");
singleList.addHead("4");
//打印当前链表信息
singleList.display();
//删除3
singleList.delete("3");
singleList.display();
//查找4
System.out.println(singleList.find("4"));
}
用单向链表实现栈,其中栈的pop()方法和push()方法,分别可以用头部删除元素方法deleteHead()以及头部增加元素方法addHead()实现。
public class StackSingleLink {
private SingleLinkedList link;
public StackSingleLink() {
link = new SingleLinkedList();
}
// 添加元素
public void push(Object obj) {
link.addHead(obj);
}
// 移除栈顶元素
public Object pop() {
Object obj = link.deleteHead();
return obj;
}
// 判断是否为空
public boolean isEmpty() {
return link.isEmpty();
}
// 打印栈内元素信息
public void display() {
link.display();
}
}
测试程序代码:
private static void StackSingleLinkTest() {
StackSingleLink linklist=new StackSingleLink();
linklist.push("123");
System.out.println(linklist.isEmpty());
linklist.display();
linklist.pop();
System.out.println(linklist.isEmpty());
linklist.display();
}