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.单向链表的缺点:查询、删除节点效率低