上一篇单向链表
1、 双向链表介绍
上一节介绍了单向链表,理解了单向链表,双向链表就简单对了。双向链表每个节点有两个连接:一个指向前一个节点,(当此“连接”为第一个“连接”时,指向空值或者空列表);而另一个指向下一个节点。
下图是一个带有头节点的双向链表逻辑示意图:
提示:头结点是为了操作的统一与方便而设立的,放在第一个元素结点之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等)。是否带有头节点可根据实际需求而定。
2、双向链表增删改思路
2.1 在链表的最后添加节点
种情况的添加,只需要找到链表中的最后一个节点,将此节点的next
域指向新节点,然后将新节点的pre
域指向当前节点。
2.3 将节点插入到指定的位置
- 首先找到新节点要添加的位置 的前一个节点
temp
- 将新节点的
next
域指向当前节点(temp
)的next
域 :newNode.next=temp.next
- 将新节点的
pre
域指向当前节点(temp
) :newNode.pre=temp
- 当前节点(
temp
)的下一个节点的pre
域指向新节点:temp.next.pre=newNode
- 当前节点(
temp
)的next域指向新节点:temp.next=newNode
逻辑示意图如下。
简单总结一下就是,将新节点的前一个节点和后一个节点,next和pre域重新指向
2.3 删除节点
- 找到要删除的节点
cur
。 - 将当前待删除节点(
cur
)的上一个(pre
)节点的next
域,指向当前节点的next域:cur.pre.next=cur.next
- 将当前待删除节点(
cur
)的下一个节点(next)的pre域指向当前节点的pre:cur.next.pre=cur.pre
逻辑示意图如下。
2.4、节点更新
节点的更新比较简单,直接找到对应的节点,更新对应的数据即可。
3、代码实现
通过上面的分析,使用代码实现就比较简单了。这里使用java实现一个编程语言排名的双向链表。
定义一个节点类ProgramLanguageNode
class ProgramLanguageNode{
/**
* 排名
*/
public int no;
/**
* 名称
*/
public String name;
//下一个节点
public ProgramLanguageNode next;
//上一个节点
public ProgramLanguageNode pre;
public ProgramLanguageNode(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "ProgramLanguageNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
双向链表实现
class DoubleLinkedList{
//定义一个头节点
private ProgramLanguageNode head;
public DoubleLinkedList(){
head=new ProgramLanguageNode(-1,null);
}
/**
* 在链表最后添加
*/
public void add(ProgramLanguageNode node){
ProgramLanguageNode temp=head;
while (temp.next!=null){
temp=temp.next;
}
temp.next=node;
node.pre=temp;
}
/**
* 按照排名顺序添加
* @param node
*/
public void addByOrder(ProgramLanguageNode node){
ProgramLanguageNode temp=head;
while (temp.next!=null){
if (temp.next.no>=node.no){
break;
}
temp=temp.next;
}
node.next=temp.next;
node.pre=temp;
if (temp.next!=null){
temp.next.pre=node;
}
temp.next=node;
}
/**
* 根据编号删除
* @param no
*/
public void del(int no){
ProgramLanguageNode cur=head.next;
//是否找到要删除的接口
boolean flag=false;
while (cur.next!=null){
if (cur.no==no){
flag=true;
break;
}
cur=cur.next;
}
if (flag){
//当前待删除接点的上一个节点的next指向待删除接的下一个节点
cur.pre.next=cur.next;
if (cur.next!=null){
//当前待删除的上一个节点,指向待删除接点的上一个节点
cur.next.pre=cur.pre;
}
}else {
System.out.println("未能找到要删除的节点");
}
}
/**
* 更新
* @param newNode
*/
public void update(ProgramLanguageNode newNode){
if (head.next==null){
System.out.println("链表为空,没有数据!");
}
ProgramLanguageNode cur=head.next;
//是否找到要更新的数据
boolean flag=false;
while (cur!=null){
if (cur.no==newNode.no){
flag=true;
break;
}
cur=cur.next;
}
if (flag){
cur.name=newNode.name;
}else {
System.out.println("没有找到节点!");
}
}
/**
* 节点遍历
*/
public void list(){
if (head.next==null){
System.out.println("链表为空,没有数据!");
}
ProgramLanguageNode tmp=head;
while (true){
if (tmp.next==null){
break;
}
System.out.println(tmp.next.toString());
tmp=tmp.next;
}
}
}
测试
public static void main(String[] args) {
DoubleLinkedList doubleLinkedList=new DoubleLinkedList();
doubleLinkedList.addByOrder(new ProgramLanguageNode(1,"C"));
doubleLinkedList.addByOrder(new ProgramLanguageNode(2,"JAVA"));
doubleLinkedList.addByOrder(new ProgramLanguageNode(4,"C#"));
doubleLinkedList.addByOrder(new ProgramLanguageNode(3,"JavaScript"));
doubleLinkedList.addByOrder(new ProgramLanguageNode(5,"Python"));
System.out.println("原链表数据~~~~");
doubleLinkedList.list();
System.out.println("删除后链表数据~~~~");
doubleLinkedList.del(2);
doubleLinkedList.list();
}