单链表的缺点分析:
- 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找;
- 单项链表不能自我删除,需要靠辅助节点辅助删除,而双向链表可以实现自我删除
在双向链表中,每个节点不仅存放了下一个节点的地址,还存放了上一个节点的地址,因此,在双向链表中,不仅可以实现顺序遍历,还可以实现逆序遍历。
双向链表的操作:
首先创建一个节点类,包含以下属性:
(1)节点值:num
(2)前驱节点:pre
(3)后继节点:next
//定义一个Node,每个Node对象就是一个节点
class Node2{
public int num;
public Node2 next; //后继节点:指向下一个节点
public Node2 pre; //前驱节点:指向前一个节点
public Node2(int num) {
this.num = num;
}
public int getNum() {
return num;
}
}
其次,我们需要一个双向链表类,链表类先初始化一个头节点,并提供获取头节点的方法
//创建一个双线链表的类
class DoubleLinkedList{
//先初始化一个头节点,头节点一般不要动,因为头节点是为了指示链表的最顶端,如果不存在就无法找到整个链表
private Node2 head = new Node2(0); //不存放具体的数据
//返回头节点
public Node2 getHead() {
return head;
}
}
定义完毕后,我们就能开始编写双向链表的操作功能了:
- 1.添加
思路:
(1)先找到双向链表的最后这个节点
(2)将最后一个节点的next指向新的节点
(3)将新节点的pre指向原链表的最后一个节点
//添加节点,按序添加(不允许添加重复元素)
public void addNode(Node2 node){
Node2 cur = head; //令一个辅助节点从头开始向后遍历
while (true) {
if (cur.next == null) { //当这个节点的下一个节点为null,说明走到了链表的最后,
node.pre = cur; //当前节点是链表的最后一个节点,那么将新节点插入链表的最后即可
cur.next = node;
break; //插入完成退出方法
}
else if(cur.next.num > node.getNum()){ //当某个节点的值大于新插入的节点的值时,将新节点插入
node.pre = cur; //将新节点的pre指向当前节点
node.next = cur.next; //新节点的next指向当前节点的下一个节点
cur.next.pre = node; //将当前节点的下一个节点的pre指向新插入的节点
cur.next = node; //将当前节点的next指向新插入的节点
break; //插入完成退出方法
}
else if (cur.next.num == node.getNum()){
System.out.println(node.getNum()+"已存在!");
break;
}
cur = cur.next;
}
}
- 2、遍历
思路:遍历的方式和单项链表一样,既可以向前查找,也可以向后查找。
//遍历双向链表的方法
public void getList(Node2 head){
if (head.next==null){
System.out.println("链表空!");
return;
}
Node2 cur = head.next;
while (cur!=null){
System.out.println(cur.getNum());
cur = cur.next;
}
}
- 3.删除
思路:
(1)直接找到要删除的这个节点,
(2)将这个要被删除节点的前一个节点的next指向被删除节点的next;
- (cur.pre.next = cur.next)
(3)将被删除节点的下一个节点的pre指向被删除节点的前一个节点,
- (cur.next.pre = cur.pre)
但是需要注意一点,
如果要删除的是最后一个节点,就不能再对最后一个节点的下一个节点的前驱进行赋值,否则会引起空指针异常,最后一个节点不需要这一步操作
。
//删除节点
public void delNode(int no){
//判断当前链表是否为空
if (head.next == null){
System.out.println("链表空!");
return;
}
Node2 cur = head.next; //辅助节点,单项链表中,先找待删除节点的前一个节点才能再做删除,双向链表可以自删除
while (true){
if (cur == null){
System.out.println("未找到值为"+no+"的节点!");
return;
}
if (cur.num == no){
cur.pre.next = cur.next;
if(cur.next != null) {
//此段代码不能做最后一个节点的判断,最后一个节点的下一个节点为null,会引起空指针异常,因此最后一个节点就不需要执行以下判断
cur.next.pre = cur.pre;
}
return;
}
cur = cur.next;
}
}
测试代码:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
DoubleLinkedList list = new DoubleLinkedList();
//添加元素:
for (int i = 0; i < 10; i++) {
int count = new Random().nextInt(10);
System.out.println("添加第"+i+1+"个元素:"+count);
list.addNode(new Node2(count));
}
//遍历链表所有数据
System.out.println("链表展示:");
list.getList(list.getHead());
//删除节点
System.out.println("输入你要删除的节点:");
list.delNode(sc.nextInt());
//遍历链表所有数据
System.out.println("链表展示:");
list.getList(list.getHead());
}
到此一个双向链表的基本功能就完成了。