双向链表的插入操作

双向链表的插入操作

转载于:https://www.cnblogs.com/LoveFishC/archive/2012/12/20/3846814.html

<think>我们正在讨论双向链表插入操作双向链表每个节点包含数据域和两个指针域,分别指向前驱节点和后继节点。插入操作需要考虑在链表的不同位置插入节点的情况,如头部、尾部或中间节点之后。根据引用内容,我们可以总结双向链表插入操作的一般步骤(以在指定节点后插入为例):1.创建新节点,并设置其数据域。2.找到要插入位置的前一个节点(假设为temp)。3.调整新节点的指针:新节点的前驱指向temp,新节点的后继指向temp的后继节点。4.调整原链表中节点的指针:将temp的后继节点的前驱指向新节点(如果temp不是最后一个节点),然后将temp的后继指向新节点。注意:如果是在头部插入(头插法)或尾部插入,步骤稍有不同,但基本原理一致。下面我们用Java语言实现一个双向链表,并实现插入操作(包括在指定节点后插入、头插法和尾插法)。由于引用中提供了部分代码示例,我们将参考这些示例进行编写。首先,定义双向链表的节点类:*/class Node{int data;Node prev; //前驱指针Node next; //后继指针publicNode(intdata){this.data= data;this.prev= null;this.next= null;} }//然后,定义双向链表类,包含插入操作的方法:classDoublyLinkedList {Nodehead;//头节点//在链表末尾插入节点(尾插法)publicvoid append(int data) {NodenewNode =new Node(data);if(head== null) {head= newNode;return;}Nodelast =head;while(last.next !=null){last =last.next;}last.next= newNode;newNode.prev= last;}//在链表头部插入节点(头插法)publicvoid push(int data) {NodenewNode =new Node(data);newNode.next =head;newNode.prev =null;//如果原链表非空,则设置原头节点的前驱为新节点if (head !=null){head.prev= newNode;}head =newNode;}//在指定节点后插入新节点public voidinsertAfter(Node prevNode,int data) {if(prevNode ==null){System.out.println("给定的前一个节点不能为空");return;}Node newNode= newNode(data);newNode.next= prevNode.next;newNode.prev= prevNode;//如果指定节点不是最后一个节点,则调整后继节点的前驱指针if(prevNode.next!= null) {prevNode.next.prev =newNode;}prevNode.next= newNode;}//打印链表public voidprintList() {Nodecurrent =head;while(current!= null) {System.out.print(current.data+ "");current =current.next;}System.out.println();}} /*代码说明:1. `append`方法实现尾插法:遍历到链表末尾,然后插入新节点。2.`push`方法实现头插法:新节点插入链表头部,并更新头节点。3. `insertAfter`方法在指定节点后插入新节点。需要处理四个指针的修改:-新节点的前驱指向指定节点(prevNode)-新节点的后继指向指定节点的后继-指定节点的后继的前驱(如果存在)指向新节点-指定节点的后继指向新节点注意:在双向链表插入节点时,要特别注意指针修改的顺序,避免链表断裂。同时,要处理边界情况(如链表为空、插入到头节点前、尾节点后等)。测试代码: */public classMain {publicstatic voidmain(String[] args) {DoublyLinkedListlist =new DoublyLinkedList();//尾插法插入节点list.append(1);list.append(2);list.append(3);System.out.println("尾插法后的链表:");list.printList(); //输出:123//头插法插入节点list.push(0);System.out.println("头插法插入0后的链表:");list.printList(); //输出:0123//在第二个节点(值为1的节点)后插入4Node node1 =list.head.next;//第二个节点(头节点是0,第二个是1)list.insertAfter(node1,4);System.out.println("在节点1后插入4后的链表:");list.printList();//输出:01423}} /*运行结果预期:尾插法后的链表:123头插法插入0后的链表:0123在节点1后插入4后的链表:01423以上代码实现了双向链表的三种插入方式:头插法、尾插法和在指定节点后插入。在实际应用中,可以根据需求选择合适的插入方法。引用说明: [^1]提供了双向链表初始化和插入的示例,但未详细展示插入操作的具体实现。[^2]提供了双循环链表插入操作的四个步骤,我们参考了这些步骤。[^3]提供了C语言头插法的代码,我们借鉴了头插法的思路。 [^4]提供了在指定节点后插入节点的关键步骤:调整新节点和相邻节点的指针。因此,我们综合了这些引用的内容,给出了完整的双向链表插入操作的实现。§§相关问题§§1.双向链表单向链表插入操作上有什么主要区别? 2.双向链表的删除操作如何实现?3.双向链表在哪些场景下比单向链表更有优势?*/</think>### 双向链表插入操作详解 #### 一、实现原理 双向链表每个节点包含三个部分: 1. 数据域(存储数据) 2. 前驱指针(`prev`,指向前一节点) 3. 后继指针(`next`,指向后一节点) 插入操作的核心步骤(以节点`a`后插入新节点`c`为例): 1. **创建新节点**:分配内存并初始化数据 2. **指针重定向**(四步关键操作): ```markdown a → b 变为 a → c → b a ← b 变为 a ← c ← b ``` - ① `c.prev = a`(新节点前驱指向`a`) - ② `c.next = a.next`(新节点后继指向`a`的后继`b`) - ③ `a.next.prev = c`(`b`的前驱指向新节点`c`) - ④ `a.next = c`(`a`的后继指向新节点`c`) ![双向链表插入示意图](https://algorithms.tutorialhorizon.com/files/2015/12/DLL-Add-Middle.png) *(图示:在节点X后插入新节点)* #### 二、代码示例(Java实现) ```java class Node { int data; Node prev; Node next; public Node(int data) { this.data = data; } } class DoublyLinkedList { Node head; // 在指定节点后插入新节点 public void insertAfter(Node prevNode, int data) { if (prevNode == null) { System.out.println("指定节点不能为空"); return; } // 1. 创建新节点 Node newNode = new Node(data); // 2. 核心四步指针操作 newNode.next = prevNode.next; // 新节点指向原后继 newNode.prev = prevNode; // 新节点前驱指向指定节点 if (prevNode.next != null) { prevNode.next.prev = newNode; // 原后继的前驱指向新节点 } prevNode.next = newNode; // 指定节点后继指向新节点 } // 测试代码 public static void main(String[] args) { DoublyLinkedList list = new DoublyLinkedList(); // 创建基础节点 1 → 3 Node node1 = new Node(1); Node node3 = new Node(3); node1.next = node3; node3.prev = node1; list.head = node1; // 在节点1后插入2 → 得到 1 → 2 → 3 list.insertAfter(node1, 2); // 验证结果 Node current = list.head; while (current != null) { System.out.print(current.data + " "); current = current.next; } // 输出:1 2 3 } } ``` #### 三、关键注意事项 1. **边界处理**: - 插入位置是尾部时:`prevNode.next`为`null`,跳过步骤③ - 空链表插入:需特殊处理头指针 2. **指针顺序**: 必须按固定顺序操作指针,避免链表断裂(推荐顺序:新节点指针 → 后继指针 → 前驱指针) 3. **时间复杂度**:$O(1)$(已知插入位置时),若需查找位置则为$O(n)$ #### 四、三种插入场景 1. **头插法**(插入头节点前): ```java public void insertFront(int data) { Node newNode = new Node(data); newNode.next = head; if (head != null) head.prev = newNode; head = newNode; } ``` 2. **尾插法**(插入链表末尾): ```java public void append(int data) { Node newNode = new Node(data); if (head == null) { head = newNode; return; } Node last = head; while (last.next != null) last = last.next; last.next = newNode; newNode.prev = last; } ``` > 引用说明:插入操作的指针调整逻辑参考了双向链表的标准实现方式[^2][^4],代码结构借鉴了Java双向链表的实现范式[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值