1.链表接口定义
package com.ncs.datastructure.linklist; public interface ILinkList { /** * 链表是否为空 * @return */ public abstract boolean isEmpty(); /** * 在链表的第一个节点前插入节点 * @param data */ public abstract void addToHead(Object data); /** * 在链表的最后一个节点追加节点 * @param data */ public abstract void addToTail(Object data); /** * 删除链表中的第一个节点 * @return */ public abstract Object deleteFromHead(); /** * 删除链表中的最后一个节点 * @return */ public abstract Object deleteFromTail(); /** * 链表中是否存在指定的节点 * @param data * @return */ public abstract boolean isContains(Object data); /** * 删除指定的节点 * @param data */ public abstract void deleteNode(Object data); }
2.单向链表的简单实现
package com.ncs.datastructure.linklist; import java.io.Serializable; /** * 单向链表 * @author yuanli * */ public class SingleLinkList { /** * 之所以定义为内部类,是因为用户并不关心链表节点的结构,而只关心链表存储的数据 * @author yuanli * */ public class Node implements Serializable { private static final long serialVersionUID = -1413226342863254391L; public Object data;//数据域(用户关心的内容) public Node next;//引用域(指向下一个节点)(用户不关心的内容) public Node(Object data) { this(data,null); } public Node(Object data, Node next) { super(); this.data = data; this.next = next; } } //表示链表的第一个节点 protected Node head; //表示链表的最后一个节点 protected Node tail; /** * 链表是否为空 * @return */ public boolean isEmpty() { return (head == null || tail == null); } /** * 在链表的第一个节点前插入节点 * @param data */ public void addToHead(Object data) { this.head = new Node(data,this.head); if (this.tail == null) this.tail = this.head; } /** * 在链表的最后一个节点追加节点 * @param data */ public void addToTail(Object data) { if (!this.isEmpty()) { this.tail.next = new Node(data); this.tail = this.tail.next; } else { this.head = this.tail = new Node(data); } } /** * 删除链表中的第一个节点 * @return */ public Object deleteFromHead() { Node current_head_node = this.head; if (this.head == this.tail) { this.head = this.tail = null; } else { this.head = this.head.next; } return current_head_node.data; } /** * 删除链表中的最后一个节点 * @return */ public Object deleteFromTail() { Node current_tail_node = this.tail; if (this.tail == this.head) { this.head = this.tail = null; } else { //若想删除最后一个节点,则必须先找到倒数第二个节点,并将其next设为null //如何确定倒数第二个节点呢?如果那个节点的next指向的是tail,则说明是 Node temp = this.head; for (; temp.next != this.tail; temp = temp.next); this.tail = temp; this.tail.next = null; } return current_tail_node.data; } /** * 链表中是否存在指定的节点 * @param data * @return */ public boolean isContains(Object data) { Node temp = this.head; for (; temp != null; temp = temp.next) { if (temp.data.equals(data)) return true; } return false; } /** * 删除指定的节点 * @param data */ public void deleteNode(Object data) { if (!isEmpty()) { //如果只有一个节点 if (this.head == this.tail && this.head.data .equals(data)) { this.head = this.tail = null; return; } //如果删除的是第一个节点 if (this.head.data.equals(data)) { this.deleteFromHead(); return; } //如果删除的是最后一个节点 if (this.tail.data.equals(data)) { this.deleteFromTail(); return; } //否则 Node temp = this.head; for (; temp != null; temp = temp.next) { if (temp.next.data.equals(data)) { temp.next = temp.next.next; break; } } } } /** * 遍历链表的所有节点,并打印出节点数据信息 */ public void printAll() { Node temp = this.head; for (; temp != null; temp = temp.next) { System.out.println("node data is " + temp.data); } } public Node getHead() { return head; } public void setHead(Node head) { this.head = head; } public Node getTail() { return tail; } public void setTail(Node tail) { this.tail = tail; } /** * @param args */ public static void main(String[] args) { //实例化一个单向链表对象 SingleLinkList sll = new SingleLinkList(); //向单向链表中添加节点 sll.addToHead("node1"); sll.addToTail("node2"); sll.addToTail("node3"); sll.addToTail("node4"); //输出所有节点数据 sll.printAll(); //删除第一个节点 sll.deleteFromHead(); //删除最后一个节点 sll.deleteFromTail(); //输出所有节点数据 sll.printAll(); //链表中是否包含指定的节点 boolean isExsist = sll.isContains("node11"); System.out.println(isExsist); //删除指定的节点 sll.deleteNode("node3"); sll.printAll(); } }
总结:
1.单向链表的优点:插入节点效率高
2.单向链表的缺点:查询、删除节点效率低