链表的节点

一个链表的节点(Node)分为两部分,第一部data分保存节点本身的数据,第二部分存储下一个节点地址。
最后一个节点存储的下一个节点的地址为空。单向链表,只提供从链表头插入节点。

使用内部类构造节点

private class Node{//使用内部类构造节点
		private Object val;//节点数据
		private Node next;//节点指针,指向下一个节点
		public Node(Object val) {//构造方法赋值
			this.val = val;
		}
	}

单向链表

  • 链表的操作
  • 1、插入节点
  • 2、删除节点
  • 如果是第一个节点,head指向后面一个节点
  • 如果是最后一个节点,前一个节点的地址,改为null
  • 如果是中间的节点,前一个节点地址,指向后一个节点。 
public class SingleLinkedList {
	
	private int size;//节点个数
	private Node head;//头指针
	
	private class Node{//使用内部类构造节点
		private Object val;//节点数据
		private Node next;//节点指针,指向下一个节点
		public Node(Object val) {//构造方法赋值
			this.val = val;
		}
	}
	
	
	public Object addHead(int val) {//在链表头部添加新节点
		Node node = new  Node(val);//新建节点
		if(head==null) {//如果头结点为空
			head = node;//新节点就是头结点
		}else {
			node.next = head;//新节点的指针指向头结点
			head = node;//新节点赋给头结点
		}
		size++;
		return node.val;
	}
	
	public Object delHead() {
		Object val = head.val;//存储头结点的值
		head = head.next;//删除头结点
		size--;
		return val;
	}
	
	public Object find(Object obj) {
		Node cur = head;
		while(cur!=null) {
			//如果当前节点不为空,并且不能要检索的值,一直向后遍历
			if(obj.equals(cur.val)) {
				return obj;
			}else {
				cur = cur.next;
			}
		}
		return null;
	}
	
	public boolean delVal(Object val) {	
		Node delNode = head;//要删除的节点
//		Node pre = head;//要删除节点的前一个节点
		if(delNode==null) {//如果链表为空,返回false
			return false;
		}
		while(delNode.next!=null) {//从第二个节点遍历
			if(delNode.next.val==val) {
				delNode.next = delNode.next.next;//删除节点
				return true;
			}else {
				delNode = delNode.next;
				if(delNode == null) {
					break;
				}
			}
		}
		if(head.val==val) {//判断第一个节点,如果相等,删除
			head = head.next;
			return true;
		}
		return false;
	}
	
	public void print() {//打印链表
		while(head!=null) {
			System.out.print(head.val+",");
			head = head.next;
		}
	}
}

双向链表

  • 单向链表只能从一个方向遍历,双向链表可以从两个方向遍历。
  • 双向链表的节点由三分部分组成:第一部分保存节点本身的数据,第二部分保存下一个节点的地址,第三部分保存上一个节点的地址。
public class DoubleLinkList {
	/**
	 * 双向链表和单链表相似,只是多了一个后继指针
	 * 相比于单链表,只需要考虑链表为空时,头尾如何相连。
	 */
	private Node head;
	private Node tail;
	private int size;
	
	class Node{
		private Object val;//数据域
		private Node prev;//前驱
		private Node next;//后继
		
		public Node(Object val) {
			this.val = val;
		}
	}
	
	public Object addHead(Object val) {
		Node node = new Node(val);
		if(head==null) {//如果头为空
			tail = node;//将新节点赋给尾结点
		}else {
			head.prev = node;
			node.next = head;
		}
		head = node;//头节点等于尾结点
		return node.val;
	}
	
	public Object addTail(Object val) {
		Node node = new Node(val);
		if(head==null) {//如果链表为空
			head = node;//将新节点赋给头结点
		}else {
			tail.next =node;
			node.prev =tail;
		}
		tail = node;//尾结点等于头结点
		return node.val;
	}
	
	public Object delHead() {
		head = head.next;
		return head.prev.val;
	}
	
	public Object delTail() {
		tail = tail.prev;
		return tail.next.val;
	}
	
	public void display() {
		while(head!=null) {
			System.out.println(head.val);
		}
	}
}

测试用例

public void display() {
		while(head!=null) {
			System.out.println(head.val);
		}
	}
	public static void main(String[] args) {
		DoubleLinkedList list = new DoubleLinkedList();
		list.addHead(1);
		list.addHead(2);
		list.addHead(3);
		list.addTail(4);
		list.addTail(5);
		list.addTail(6);
		list.delHead();
		list.delTail();
		list.display();
	}

总结:链表插入、删除效率特别高,主要应用于需要大量删除、插入的场景中。虽然相比于数组,占用空间稍大,但相比于数组存储数据需要一块连续的内存空间,链表可以利用碎片空间。怎么说那,各有各的优点和缺点吧。