08、数据结构与算法 - 实战:双向链表
概念
检索起点跟单向链表一样
每个节点有指向上一个节点、以及下一个节点的指针
双向链表 - 添加节点到尾部
代码实现
class DoubleLinkedList<T> {
// 链表头指针
Node<T> headPointer = new Node<T>();
public void add(T a) {
// 1. 添加的元素封装成一个节点
Node<T> newNode = new Node<T>(a);
// 2. 表示遍历到的节点
Node<T> temp = headPointer;
// 3. 寻找到 next=null的尾节点
while(temp.next != null) {
temp = temp.next;
}
// 4. 尾节点的next指向 新节点
temp.next = newNode;
// 5. 新节点的pre指向 尾节点
newNode.pre = temp;
}
@Override
public String toString() {
if(headPointer.next == null) {
return "";
}
Node<T> currentNode = headPointer.next;
StringBuilder sb = new StringBuilder();
while(currentNode != null) {
sb.append(currentNode.toString() + "\n");
currentNode = currentNode.next;
}
sb.delete(sb.lastIndexOf("\n"), sb.length());
return sb.toString();
}
private class Node<T> {
T data;
Node<T> pre;
Node<T> next;
Node() {
data = null;
pre = null;
next = null;
}
Node(T a) {
data = a;
pre = null;
next = null;
}
public String toString() {
return data.toString();
}
}
}
测试代码
需要添加到链表的类
class Emp {
int empno;
String ename;
Emp(int empno, String ename) {
this.empno = empno;
this.ename =ename;
}
@Override
public String toString() {
return "car [empno=" + empno + ", ename=" + ename + "]";
}
}
将上述元素添加到链表
public static void main(String[] args) {
Emp emp1 = new Emp(32, "lrc");
Emp emp2 = new Emp(16, "rwe");
Emp emp3 = new Emp(79, "bcv");
DoubleLinkedList<Emp> dll = new DoubleLinkedList<Emp>();
dll.add(emp1);
dll.add(emp2);
dll.add(emp3);
System.out.println(dll);
}
}
运行结果
双向链表 - 删除节点
代码实现
public void delete(T a) {
// 1. 指代当前遍历到的节点
Node<T> currentNode = headPointer.next;
// 2. 当前遍历的节点不为空
while(currentNode != null) {
// 3., 一旦遇到 需要删除的节点,结束完以下操作,立即停止遍历
if(currentNode.data.equals(a)) {
// 3.1 需要删除节点的前一个节点的next指针,指向需要删除节点的下一个节点
currentNode.pre.next = currentNode.next;
// 3.2 如果删除节点的后面还有节点则 其下一个节点的pre指针指向 删除节点的前一个节点
if(currentNode.next != null) {
currentNode.next.pre = currentNode.pre;
}
// 3.3 结束循环
break;
}
// 4. 当前节点不符合要求,遍历移动到下一个节点
currentNode = currentNode.next;
}
}
测试代码
public static void main(String[] args) {
Emp emp1 = new Emp(32, "lrc");
Emp emp2 = new Emp(16, "rwe");
Emp emp3 = new Emp(79, "bcv");
DoubleLinkedList<Emp> dll = new DoubleLinkedList<Emp>();
// 添加节点,并打印出来
dll.add(emp1);
dll.add(emp2);
dll.add(emp3);
System.out.println(dll);
System.out.println("\n-------------------\n");
// 删除一个节点,并打印链表存在的节点
dll.delete(new Emp(79,"bcv"));
System.out.println(dll);
}
运行结果
双向链表 - 逻辑有序添加到链表
public void addOrder(T a) {
// 1. 封装添加的元素为数组
Node<T> newNode = new Node<T>(a);
// 判断当前链表是否有有效元素,无,则直接在头指针向后加即可
if (headPointer.next == null) {
headPointer.next = newNode;
newNode.pre = headPointer;
return;
}
// 加一个标志位,看是否有元素添加成功
boolean flag = false;
Node<T> currentNode = headPointer;
while(currentNode.next != null) {
// 代表当前遍历到的元素
currentNode = currentNode.next;
// 如果遍历的元素大于添加的元素,则把添加的元素插入在当前元素前面
if(currentNode.data.hashCode() > newNode.data.hashCode()) {
flag = true;
currentNode.pre.next = newNode;
newNode.next = currentNode;
currentNode.pre = newNode;
newNode.pre = currentNode.pre;
break;
}
}
// 如果整个链表遍历完毕,依然未找到大于添加元素的值,则直接将添加元素放入链表尾部
if(!flag) {
currentNode.next = newNode;
newNode.pre = currentNode;
}
}
测试代码
public static void main(String[] args) {
Emp emp1 = new Emp(32, "lrc");
Emp emp2 = new Emp(16, "rwe");
Emp emp4 = new Emp(16, "rwetfgdg");
Emp emp3 = new Emp(79, "bcv");
DoubleLinkedList<Emp> dll = new DoubleLinkedList<Emp>();
dll.addOrder(emp1);
dll.addOrder(emp2);
dll.addOrder(emp4);
dll.addOrder(emp3);
System.out.println(dll);
}
运行结果