前面的单向链表练习发现:单向链表只能一个方向查找,并且删除元素时需要借助临时节点来存储数据链。
通过在节点类中加入一个 pre 指针指向前一个元素的方式就可以改变上面的劣势,实现自我删除。
双向链表节点类
//双向链表节点
class DNode<T> {
private int no; // 序号
private T data; // data 域
private DNode<T> pre; // pre 域
private DNode<T> next; // next 域
//是否有下个元素
public boolean hasNext() {
return next != null;
}
@Override
public String toString() {
return "DNode{" +
"no=" + no +
", data=" + data +
", name='" + name + '\'' +
'}';
}
private String name; //辅助名
public DNode(DNode<T> dNode) {
this.data = dNode.getData();
this.no = dNode.getNo();
this.name = dNode.getName();
}
public DNode(T data, int no, String name) {
this.data = data;
this.no = no;
this.name = name;
}
//getter、setter
}
链表类
class DLinkedList<T> {
private final DNode<T> head =
new DNode<>(null, -1, null); //首节点
private DNode<T> rear; //尾节点
private DNode<T> temp; //临时节点
//打印
public void list() {
if (!head.hasNext()) {
System.out.println("链表空");
return;
}
temp = head.getNext();
while (temp != null) {
System.out.println(temp);
temp = temp.getNext();
}
}
//反打
public void revList(){
if (rear==null){
System.out.println("链表空");
return;
}
while (rear!=null&&rear!=head){
System.out.println(rear);
rear = rear.getPre();
}
}
}
增
//增
public void add(T data, int no, String name) {
DNode<T> node = new DNode<>(data, no, name);
//空链表直接加
if (!head.hasNext()) {
head.setNext(node);
rear = node;
return;
}
//否则在尾部加 node 然后 rear 指向 node
rear.setNext(node);
node.setPre(rear);
rear = node;
}
//按序增
public void addByNo(T data, int no, String name){
DNode<T> node = new DNode<>(data, no, name);
//空链表直接加
if (!head.hasNext()) {
head.setNext(node);
rear = node;
return;
}
//找到 no 位置
DNode<T> temp = head.getNext();
while (temp.getNo()<no){
if (temp.getNo()==no){
System.out.println("重复的 no: " + no);
return;
}
temp = temp.getNext();
}
node.setPre(temp.getPre());
node.setNext(temp);
temp.getPre().setNext(node);
temp.setPre(node);
}
删
//删
public T popByNo(int no) {
if (!head.hasNext()) {
System.out.println("链表空");
return null;
}
T r = null; //存放弹出删除节点的数据 data 的辅助变量
temp = head.getNext();
while (temp != null) {
if (temp.getNo() == no) { //找到后自我删除
temp.getNext().setPre(temp.getPre());
temp.getPre().setNext(temp.getNext());
r = temp.getData();
break;
}
temp = temp.getNext();
}
return r;
}
改
//改
public void update(T data, int no, String name) {
if (!head.hasNext()) {
System.out.println("链表空");
return;
}
temp = head.getNext();
while (temp != null) {
if (temp.getNo() == no) {
temp.setData(data);
temp.setName(name);
break;
}
temp = temp.getNext();
}
}
查
//查
public DNode<T> getByNo(int no) {
if (!head.hasNext()) {
System.out.println("链表空");
return null;
}
temp = head.getNext();
while (temp != null) {
if (temp.getNo() == no) {
return new DNode<>(temp);
}
temp = temp.getNext();
}
return null;
}
测试主方法
public static void main(String[] args) {
DLinkedList<LocalDateTime> list = new DLinkedList<>();
list.add(LocalDateTime.now(), 1, "孙悟空");
list.add(LocalDateTime.now(), 3, "唐僧");
list.add(LocalDateTime.now(), 5, "猪八戒");
list.add(LocalDateTime.now(), 9, "屠夫");
System.out.println("----------list----------");
list.list();
System.out.println("----------remove----------");
System.out.println("pop: " + list.popByNo(3));
list.list();
System.out.println("----------get----------");
System.out.println("get: " + list.getByNo(5));
System.out.println("----------insert----------");
list.addByNo(LocalDateTime.now(),3,"不古井");
list.list();
System.out.println("----------revList----------");
list.revList();
}