双向链表是链表中的一种,java中的LinkedList实现的就是双向链表。双向链表与单链表相比,多了一个前驱指针,使得链表的操纵更为方便。
到双向链表这,用包菜来比喻链表已经是不合适了。在我的理解中双向链表是的节点是一个小球,这个小球有前后两个环,一个环是前驱指针 Node pre;一个环是后向指针 Node next,如果有新的元素加入链表,那么这个小球的next环就会勾住新进来的球,而新进来的pre环则会勾住原来的球。
有了小理解则继续思考双链表需要的方法以及实现思路:
1、首先写个节点Node,与单链表的相似,多定义一个前驱指针;双链表的类中需要定义一个头结点head和尾节点end,还要有计算链表大小的size
2、接下来是链表元素的增加,a、如果头结点为空,则新元素直接赋给头结点。b、如果尾节点为空则新元素赋给尾节点,并且尾节点的pre指向头结点,头结点的next指向尾节点;c、建一个临时节点存储尾节点,将新节点接在尾节点后,并且让新节点成为尾节点。要记得size++。
3、可以插入,找到对应的节点,在其后的插入,并类似以上的的c步骤
4、删除:先判断索引是否在范围内,如果在索引内,判断距离头结点还是尾节点近,距离近的一端开始搜索,找到后将它的pre节点与next节点连接起来
5、查找:与删除的前一部分类似,先判断距离哪端近,再近端开始搜索,找到并返回
步骤结束。
package linklist;
/**
* 定义动态集合上的基本操作
* @author zhengwei lastmodified 2017年3月16日
*
*/
public interface ICollection {
/**
* 根据关键字搜索出对应对象
*
* @param key
* @return
*/
Object search(Object key);
/**
* 元素个数
*
* @return
*/
int size();
/**
* 集合是否为空
*
* @return
*/
boolean isEmpty();
/**
* 集合是否包含某个关键字元素
*
* @param o
* @return
*/
boolean contains(Object key);
/**
* 在集合中新增一个元素
*
* @param e
* @return
*/
void add(Object e);
/**
* 按关键字移除元素
*
* @param o
* @return
*/
void remove(Object key);
}
package linklist;
/**
* 顺序表
* @author zhengwei
*
*/
public interface IList extends ICollection {
/**
* 求指定元素的下标,没有这个元素就返回-1
* @param e
* @return
*/
int indexOf(Object e);
/**
* 获取指定下标处的元素
* @param index
* @return
*/
Object get(int index);
/**
* 在指定下标处插入元素
* @param e
* @param index
*/
void add(Object e,int index);
/**
* 删除指定下标处的元素
* @param index
* @return
*/
Object delete(int index);
}
package list.linklist;
/**
*
* @author chenkaixin
*
* @param
*/
public class DoublyLink implements IList {
/**
* 头结点
*/
private Node head;
/**
* 尾节点
*/
private Node end;
/**
* 链表的大小
*/
private int size = 0;
@Override
public T search(T key) {
Node tmp = head;
if ((tmp.data == null || key == null)) {
return null;
}
while (tmp != null) {
if (tmp.data.equals(key)) {
return tmp.data;
} else {
tmp = tmp.next;
}
}
return null;
}
@Override
public int size() {
return this.size;
}
@Override
public boolean isEmpty() {
boolean b = true;
if (this.size == 0) {
b = false;
}
return b;
}
@Override
public boolean contains(Object key) {
boolean b = false;
Node tem = head;
while (tem != null) {
if (tem.data == key) {
b = true;
}
}
return b;
}
@Override
public void add(T e) {
if (head == null) {
head = new Node(e);
} else if (end == null) {
end = new Node(e);
end.pre = head;
head.next = end;
} else {
Node tem = new Node(e);
tem.pre = end;
end.next = tem;
end = tem;
}
this.size++;
}
@Override
public void remove(T key) {
Node tem = head;
while (true) {
if (tem.data.equals(key)) {
delExcege(tem);
this.size--;
System.out.println(tem.data);
break;
}
tem = tem.next;
}
}
@Override
public int indexOf(T e) {
Node tem = head;
int index = 0;
while (tem != null) {
if (tem.data.equals(e)) {
return index;
}
tem = tem.next;
index++;
}
return -1;
}
@Override
public T get(int index) {
int i = 0;
Node tem = head;
if (index > 0 && index < this.size) {
while (tem != null) {
if (i == index) {
return tem.data;
}
tem = tem.next;
i++;
}
}
return null;
}
@Override
public void add(T e, int index) {
Node newNode = new Node(e);
int i;
if (0 < index && index < this.size) {
if (index < size / 2) {
Node tem = head;
i = 0;
while (tem != null) {
if (i == index) {
addExcege(newNode, tem);
}
tem = tem.next;
i++;
}
} else {
Node tem = end;
i = this.size-1;
while (tem != null) {
if (i == index) {
addExcege(newNode, tem);
}
tem = tem.pre;
i--;
}
}
}
}
@Override
public Object delete(int index) {
Node tem = head;
Object result = null;
int i;
if (0 < index && index < this.size) {
if (index < size / 2) {
i = 0;
while (tem != null) {
if (i == index) {
delExcege(tem);
result = tem.data;
}
tem = tem.next;
i++;
}
} else {
while (tem != null) {
i = this.size - 1;
if (i == index) {
delExcege(tem);
result = tem.data;
}
tem = tem.pre;
i--;
}
}
}
return result;
}
private void addExcege(Node newNode, Node tem) {
newNode.next = tem.next;
tem.next.pre = newNode;
tem.next = newNode;
newNode.pre = tem;
}
private void delExcege(Node tem) {
tem.pre.next = tem.next;
tem.next.pre = tem.pre;
}
private class Node {
Node next;
Node pre;
T data;
public Node(T data) {
this.data = data;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (this.getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
return true;
}
private DoublyLink getOuterType() {
return DoublyLink.this;
}
@Override
public String toString() {
return this.data.toString();
}
}
@Override
public String toString() {
Node e = head;
StringBuilder sb = new StringBuilder("[");
while (e != null) {
sb.append(e.data.toString()).append(",");
e = e.next;
}
sb.deleteCharAt(sb.lastIndexOf(",")).append("]");
return sb.toString();
}
public static void main(String[] args) {
DoublyLink dl = new DoublyLink();
dl.add('3');
dl.add('9');
dl.add('4');
dl.add('6');
dl.add('8');
dl.add('b');
dl.add('p');
System.out.println(dl.indexOf('9'));
System.out.println(dl.size());
System.out.println(dl.toString());
System.out.println("=======================================");
dl.remove('9');
System.out.println(dl.get(3));
System.out.println(dl.size());
System.out.println(dl.toString());
System.out.println("=================================");
dl.add('a', 2);
System.out.println(dl.toString());
System.out.println("=================================");
dl.delete(4);
System.out.println(dl.search('a'));
System.out.println(dl.toString());
System.out.println("==================================");
}
}