目录

单向链表(Single Linked List)

双端链表(HeadTailLinkedList)

双向链表(DoubleLinkedList)

总结


链表(Linked List)是一种物理存储单元上非连续、非顺序的存储结构,它既可以表示线性结构,也可以用于表示非线性结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表由一系列结点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。


Node类:

package yrwan06;

public class Node {
	public int data;// 数据域
	public Node next;// 指针域:指向下一个结点
	public Node prev;// 指针域:指向前一个结点

	public Node(int data) {
		this.data = data;
	}
	
	public void display(){
		System.out.print(data + " ");
	}
}

单向链表(Single Linked List)

         单向链表是链表中结构最简单的。一个单向链表的结点(Node)分为两个部分,第一个部分保存结点的数据,另一个部分存储下一个结点的地址。

  单向链表只可沿一个方向遍历,一般查找一个结点的时要从第一个结点开始顺次遍历,直至访问到所需位置。插入一个结点,在这里只提供在表头插入,只需将当待插入结点设为头结点,将其next指向原头结点即可。删除一个结点时,将该结点的上一个结点的next指向该结点的下一个结点即可。

实现代码:

package yrwan06;

/**
 * 单向链表,只能在表头插入
 * 
 * @author Wyran
 *
 */
public class SingleLinkedList {
	private int size;
	private Node head;

	public SingleLinkedList() {
		size = 0;
		head = null;
	}

	/**
	 * 在表头添加元素
	 * 
	 * @param value 待插入元素
	 */
	public void insertHead(int value) {
		Node newHead = new Node(value);
		if (size == 0) {
			head = newHead;
		} else {
			newHead.next = head;
			head = newHead;
		}
		size++;
	}

	/**
	 * 删除表头
	 * 
	 * @return 所删除的结点
	 */
	public Node deleteHead() {
		Node temp = head;
		if (size == 1) {
			head = null;
		} else {
			head = head.next;
		}
		size--;
		return temp;
	}

	/**
	 * 根据传入的值删除结点
	 * 
	 * @param value 待删除的值
	 * @return 所删除的结点
	 */
	public Node delete(int value) {
		Node current = head;
		Node previous = head;
		while (current.data != value) {
			if (current.next == null) {
				return null;
			} else {
				previous = current;
				current = current.next;
			}
		}
		// 如果删除的结点是第一个结点
		if (current == head) {
			head = head.next;
		} else {// 删除的结点不是第一个结点
			previous.next = current.next;
		}
		size--;
		return current;
	}

	/**
	 * 查找指定元素
	 * 
	 * @param value 待查找元素
	 * @return 找到了返回该结点,找不到返回null
	 */
	public Node find(int value) {
		Node current = head;
		while (current.data != value) {
			if (current.next == null) {
				return null;
			}
			current = current.next;
		}
		return current;
	}

	// 判断链表是否为空
	public boolean isEmpty() {
		return (size == 0);
	}

	// 遍历显示
	public void display() {
		Node temp = head;
		while (temp != null) {
			temp.display();
			temp = temp.next;
		}
	}
}

测试类为:

package yrwan06;

public class SingleLinkedListTest {
	public static void main(String[] args) {
		SingleLinkedList sll = new SingleLinkedList();
		sll.insertHead(1);
		sll.insertHead(2);
		sll.insertHead(3);
		sll.insertHead(4);
		sll.insertHead(5);
		sll.insertHead(6);
		sll.display();
		System.out.println("-------------");
		sll.deleteHead();
		sll.display();
		System.out.println("-------------");
		sll.find(3).display();
		System.out.println("-------------");
		sll.delete(5).display();
		System.out.println("-------------");
		sll.display();
	}
}

结果为:

6 5 4 3 2 1 -------------
5 4 3 2 1 -------------
3 -------------
5 -------------
4 3 2 1

双端链表(HeadTailLinkedList)

在单链表的基础上,增加对尾结点的引用,可以很方便的在链表尾部增加数据

实现代码:

package yrwan06;

/**
 * 双端链表,可在表头、表尾插入
 * 
 * @author Wyran
 *
 */
public class HeadTailLinkedList {
	private int size;
	private Node head;
	private Node tail;

	public HeadTailLinkedList() {
		size = 0;
		head = null;
		tail = null;
	}

	/**
	 * 在表头添加元素
	 * 
	 * @param value 待插入元素
	 */
	public void insertHead(int value) {
		Node newHead = new Node(value);
		if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
			head = newHead;
			tail = newHead;
		} else {
			newHead.next = head;
			head = newHead;
		}
		size++;
	}

	/**
	 * 在表尾添加元素
	 * 
	 * @param value 待插入元素
	 */
	public void insertTail(int value) {
		Node newTail = new Node(value);
		if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
			head = newTail;
			tail = newTail;
		} else {
			tail.next = newTail;
			tail = newTail;
		}
		size++;
	}

	/**
	 * 删除表头
	 * 
	 * @return 所删除的结点
	 */
	public Node deleteHead() {
		Node temp = head;
		if (size == 1) {
			head = null;
			tail = null;
		} else {
			head = head.next;
		}
		size--;
		return temp;
	}

	/**
	 * 根据传入的值删除结点
	 * 
	 * @param value 待删除的值
	 * @return 所删除的结点
	 */
	public Node delete(int value) {
		Node current = head;
		Node previous = head;
		while (current.data != value) {
			if (current.next == null) {
				return null;
			} else {
				previous = current;
				current = current.next;
			}
		}
		// 如果删除的结点是第一个结点
		if (current == head) {
			head = head.next;
		} else {// 删除的结点不是第一个结点
			previous.next = current.next;
		}
		size--;
		return current;
	}

	/**
	 * 查找指定元素
	 * 
	 * @param value 待查找元素
	 * @return 找到了返回该结点,找不到返回null
	 */
	public Node find(int value) {
		Node current = head;
		while (current.data != value) {
			if (current.next == null) {
				return null;
			}
			current = current.next;
		}
		return current;
	}

	// 判断链表是否为空
	public boolean isEmpty() {
		return (size == 0);
	}

	// 遍历显示
	public void display() {
		Node temp = head;
		while (temp != null) {
			temp.display();
			temp = temp.next;
		}
	}
}

测试类:

package yrwan06;

public class HeadTailLinkedListTest {
	public static void main(String[] args) {
		HeadTailLinkedList htll = new HeadTailLinkedList();
		htll.insertHead(1);
		htll.insertHead(2);
		htll.insertHead(3);
		htll.insertTail(4);
		htll.insertTail(5);
		htll.insertTail(6);
		htll.display();
		System.out.println("-------------");
		htll.deleteHead();
		htll.display();
		System.out.println("-------------");
		htll.find(4).display();
		System.out.println("-------------");
		htll.delete(5).display();
		System.out.println("-------------");
		htll.display();
	}
}

 结果为:

3 2 1 4 5 6 -------------
2 1 4 5 6 -------------
4 -------------
5 -------------
2 1 4 6

双向链表(DoubleLinkedList)

构造一个链表,其每个结点除了保存对下一个结点的引用,还保存了对上一个结点的引用,使之在头部尾部都可以增删数据,并且可以从两个方向遍历。

实现代码:

package yrwan06;

/**
 * 双向链表,可在表头、表尾插入删除,可从两个方向遍历
 * 
 * @author Wyran
 *
 */
public class DoubleLinkedList {
	private int size;
	private Node head;
	private Node tail;

	public DoubleLinkedList() {
		size = 0;
		head = null;
		tail = null;
	}

	/**
	 * 在表头添加元素
	 * 
	 * @param value 待插入元素
	 */
	public void insertHead(int value) {
		Node newHead = new Node(value);
		if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
			head = newHead;
			tail = newHead;
		} else {
			head.prev = newHead;
			newHead.next = head;
			head = newHead;
		}
		size++;
	}

	/**
	 * 在表尾添加元素
	 * 
	 * @param value 待插入元素
	 */
	public void insertTail(int value) {
		Node newTail = new Node(value);
		if (size == 0) {// 如果链表为空,那么头、尾结点都是该新增结点
			head = newTail;
			tail = newTail;
		} else {
			tail.next = newTail;
			newTail.prev = tail;
			tail = newTail;
		}
		size++;
	}

	/**
	 * 删除表头
	 * 
	 * @return 所删除的结点
	 */
	public Node deleteHead() {
		Node temp = head;
		if (size == 1) {
			head = null;
			tail = null;
		} else {
			head = head.next;
			head.prev = null;
		}
		size--;
		return temp;
	}

	/**
	 * 删除表尾
	 * 
	 * @return 所删除的结点
	 */
	public Node deleteTail() {
		Node temp = tail;
		if (size == 1) {
			head = null;
			tail = null;
		} else {
			tail = tail.prev;
			tail.next = null;
		}
		size--;
		return temp;
	}

	/**
	 * 根据传入的值删除结点
	 * 
	 * @param value 待删除的值
	 * @return 所删除的结点
	 */
	public Node delete(int value) {
		Node current = head;
		while (current.data != value) {
			if (current.next == null) {
				return null;
			} else {
				current = current.next;
			}
		}
		// 如果删除的结点是第一个结点
		if (current == head) {
			head = head.next;
			head.prev = null;
		} else {// 删除的结点不是第一个结点
			current.prev.next = current.next;
			current.next.prev = current.prev;
		}
		size--;
		return current;
	}

	/**
	 * 查找指定元素
	 * 
	 * @param value 待查找元素
	 * @return 找到了返回该结点,找不到返回null
	 */
	public Node find(int value) {
		Node current = head;
		while (current.data != value) {
			if (current.next == null) {
				return null;
			}
			current = current.next;
		}
		return current;
	}

	// 判断链表是否为空
	public boolean isEmpty() {
		return (size == 0);
	}

	// 遍历显示
	public void display() {
		Node temp = head;
		while (temp != null) {
			temp.display();
			temp = temp.next;
		}
	}
}

测试类:

package yrwan06;

public class DoubleLinkedListTest {
	public static void main(String[] args) {
		DoubleLinkedList dld = new DoubleLinkedList();
		dld.insertHead(1);
		dld.insertHead(2);
		dld.insertHead(3);
		dld.insertTail(4);
		dld.insertTail(5);
		dld.insertTail(6);
		dld.display();
		System.out.println("-------------");

		while (!dld.isEmpty()) {
			dld.deleteHead();
			dld.display();
			System.out.println();
		}

//		while (!dld.isEmpty()) {
//			dld.deleteTail();
//			dld.display();
//			System.out.println();
//		}
	}
}

结果为:

3 2 1 4 5 6 -------------
2 1 4 5 6 
1 4 5 6 
4 5 6 
5 6 
6

总结

每个链表都一个LinikedList对象和许多Node对象组成,LinkedList对象通常包含头和尾结点的引用,分别指向链表的第一个结点和最后一个结点。而每个结点对象通常包含数据部分data,以及对上一个结点的引用prev和下一个结点的引用next,只有下一个结点的引用称为单向链表,两个都有的称为双向链表。

next值为null则说明是链表的结尾,如果想找到某个结点,必须从第一个结点开始遍历,不断通过next找到下一个结点,直到找到所需要的。

栈和队列都是ADT,可以用数组来实现,也可以用链表实现。