数据结构④-链表

链表最大优势是插入删除比较方便

其实链表也是一种灵活的数据结构,没有想象的那么复杂

public class LinkList<T> {
	private Node first;
	
	private LinkList(){
		first = null;
	}
	class Node<T>{
		T data;
		Node next;
		
		public Node(){}
		public Node(T t){
			this.data = t;
		}
		
		public void display(){
			System.out.print(" " + data);
		}
	}
	
	boolean isEmpty(){
		return null == first;
	}
	
	//头插法
	public void insertFirst(T t){
		Node node = new Node(t);
		node.next = first;
		first = node;	
	}
	
	public Node deleteFirst(){
		Node node = first;
		first = first.next;
		return node;
	}
	
	//查找
	public Node find(T t){
		Node current = first;
		while(current.data != t){
			if(null == current)
				return null;
			
			current = current.next;
		}
		
		return current;
	}
	
	public void display(){
		if(isEmpty()){
			System.out.println("linkList is null.");
			return;
		}
		
		Node current = null;
		current = first;
		while(null != current){
			current.display();
			current = current.next;
		}
	}
	
	/**
	 * 逆序输出 面试题
	 * 从尾到头打印链表 使用递归(优雅)
	 * 递归的原理,其实就是一个栈(stack) “逐层递进”与“逐层回归”的过程!
	 * @param head
	 */
	public void reversePrint(Node head){
		if(null == head){
			return;
		}
		
		reversePrint(head.next);
		System.out.print(head.data + " ");
	}
	
	//插入一个节点,插到指定节点的后边
	public boolean insert(T t, Node newNode){
		boolean flag = false;
		LinkList.Node node = this.find(t);
		if(null != node){
			if(null != node.next){
				newNode.next = node.next;
			}
			node.next = newNode;
			flag = true;
		}
		
		return flag;
	}
	
	//删除指定节点
	public boolean delete(T t){
		boolean flag = false;
		LinkList.Node current = first;
		LinkList.Node prev = first;
		
		
		
		while(null != current && current.data != t){
			prev = current;
			current = current.next;
			
		}
		
		if(null == current){
			System.out.println("Not find target node.");
			return false;
		}
		
		
		if(first == current){
			first = current.next;
		}else if(null != current.next){
			//如果目标后继节点不为空
			prev.next = current.next;
		}else{
			prev.next = null;
		}
		
		flag = true;

		return flag;
	}
	
	public static void main(String[] args){
		LinkList list = new LinkList();
		list.insertFirst(22);
		list.insertFirst(33);
		list.insertFirst(55);
		list.insertFirst(66);
		list.insertFirst(88);
		
//		list.deleteFirst();
		
//		list.delete(55);
		
		list.display();
		System.out.println("");
		System.out.println("reverse List-->");
		list.reversePrint(list.first);
		
	}

}


【双向链表-2016】==============================================================================

package com.dataStruct.demo;

public class DLinkList {
	private DLinkNode first;
	private DLinkNode last;
	
	public boolean isEmpty(){
		if(null == first)
			return true;
		return false;
	}
	
	public void insertFirst(int id, String name){
		DLinkNode dLinkNode = new DLinkNode(id, name);
		if(isEmpty()){
			last = dLinkNode;
		}else{
			first.prev = dLinkNode;
		}
		
		dLinkNode.next = first;
		first = dLinkNode;
	}
	public void insertLast(int id, String name){
		DLinkNode dLinkNode = new DLinkNode(id, name);
		if(isEmpty()){
			first = dLinkNode;
		}else{
			last.next = dLinkNode;
			dLinkNode.prev = last;
		}
		last = dLinkNode;
	}
	public void delFirst(){
		if(isEmpty())
			return;
		if(first == last){
			first = null;
			last = null;
		}else{
			first = first.next;
			first.next.prev = null;
		}
	}
	public void delLast(){
		if(isEmpty())
			return;
		if(first == last){
			first = null;
			last = null;
		}else{
			last = last.prev;
			last.next = null;
		}
	}
	public boolean delete(int id){
		if(isEmpty()){
			System.out.println("DLinkNode is null!");
			return false;
		}

		DLinkNode current = first;
		while(null != current){
			if(current.id == id){
				if(first == last){
					first = null;
					last = null;
				}
				
				if(current == first){
					first = first.next;
				}else if(current == last){
					last = current.prev;
					current.prev.next = null;
				}else{
					current.prev.next = current.next;
					current.next.prev = current.prev;
					
				}
				
				return true;
			}

			current = current.next;
		}
			
		return false;
	}
	
	public void display(){
		DLinkNode current = first;
		if(isEmpty()){
			System.out.println("DLinkList is empty!!");
			return;
		}
		if(first == last){
			first.display();
			return;
		}
		while(null != current){
			current.display();
			current = current.next;
		}
	}
	
	public static void main(String[] args){
		DLinkList dl = new DLinkList();
		dl.insertFirst(1, "ZhangSan");
		dl.insertLast(2, "LiSi");
		dl.insertLast(3, "WangWu");
		
//		dl.delete(2);
//		dl.delFirst();
		dl.delLast();
		dl.display();
	}

}

小结

逆序 2017/12/22

通过递归把一个链表变成了栈结构,可以说肥肠牛逼

数据结构老手的惯用伎俩,实战中也有很广泛的用途

public void reverse(Node node){
		
		if(null == node)
			return;
		
		/*差之毫厘,谬以千里*/
//		node = node.next;
		
		reverse(node.next);
		
		System.out.println(node.data + " ");
		
	}


<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、付费专栏及课程。

余额充值