zoukankan      html  css  js  c++  java
  • 大话数据结构五:线性表的链式存储结构(双向链表)

    1. 双向链表:在单链表的每个结点中,再设置一个指向其前驱结点的指针域,那么在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。


    2. 单链表和双向链表比较:

    单链表:总是要从头到尾找结点,只能正遍历,不能反遍历。

    双向链表: 可以从头找到尾,也可以从尾找到头,即正反遍历都可以,可以有效提高算法的时间性能,但由于每个结点需要记录两份指针,所以在空间占用上略多一点,这就是通过空间来换时间。


    3. Java实现双向链表:

    // 双向链表
    public class DoubleLinkedList<E> {
    	private Node<E> head; // 头结点
    	private int size; // 链表长度
    
    	// 建立一个空链表
    	public DoubleLinkedList() {
    		head = null;
    		size = 0;
    	}
    	
    	// 在头结点前插入
    	public boolean addBeforeHead(E data){
    		Node<E> newNode = new Node<E>(data);
    		if(isEmpty()){
    			head = newNode;
    		}else{
    			head.setPrev(newNode);
    			newNode.setNext(head);
    			head = newNode;
    		}
    		size++;
    		return true;
    	}
    	
    	// 在链表尾部插入
    	public boolean addAfterTail(E data){
    		Node<E> newNode = new Node<E>(data);
    		if(isEmpty()){
    			head = newNode;
    		}else{
    			Node<E> tail = get(size);
    			tail.setNext(newNode);
    			newNode.setPrev(tail); // 设置新结点的上一结点
    		}
    		size++;
    		return true;
    	}
    
    	// 插入指定位置的结点
    	public boolean insert(int position, E data) {
    		if(position >= 1 && (position <= size + 1)){
    			Node<E> newNode = new Node<E>(data);
    			if(isEmpty() || position == 1){ // 链表为空或在头结点前插入
    				addBeforeHead(data);
    			}else if(position == size + 1){ // 在尾结点后插入
    				Node<E> preNode = get(position - 1);
    				newNode.setPrev(preNode);
    				preNode.setNext(newNode);
    			}else{ // 在其他位置插入
    				Node<E> preNode = get(position - 1); // 获取position的前一结点
    				Node<E> afterNode = preNode.getNext(); // 获取未插入结点时position位置对应结点 
    				newNode.setPrev(preNode); // ①
    				newNode.setNext(afterNode); // ②
    				afterNode.setPrev(newNode); // ③
    				preNode.setNext(newNode); // ④
    			}
    			size++;
    			return true;
    		}
    		return false;
    	}
    
    	// 删除指定位置的结点
    	public E delete(int position) { 
    		E result = null;
    		if(position >= 1 && position <= size){
    			if(position == 1){ // 删除头结点
    				result = head.getData();
    				Node<E> afterHead = head.getNext();
    				afterHead.setPrev(null);
    				head.setNext(null);
    				head = afterHead; 
    			}else if(position == size){ // 删除尾结点
    				Node<E> preNode = get(position - 1); // 获取待删除结点的前一结点
    				Node<E> delNode = preNode.getNext(); // 获取待删除结点
    				result = delNode.getData();
    				preNode.setNext(null);
    			}else{ // 删除其他结点
    				Node<E> preNode = get(position - 1); // 获取待删除结点的前一结点
    				Node<E> delNode = preNode.getNext(); // 获取待删除结点
    				result = delNode.getData();
    				Node<E> nextNode = delNode.getNext();// 获取待删除结点的下一结点
    				preNode.setNext(nextNode); // ①
    				nextNode.setPrev(preNode); // ②
    			}
    			size--;
    		}
    		return result;
    	}
    	
    	// 获取某个位置的结点(正序遍历)
    	public Node<E> get(int position){
    		Node<E> targetNode = null;
    		if(!isEmpty() && position >= 1 && position <= size){ 
    			targetNode = head;
    			for(int i = 1; i < position ; i++){
    				targetNode = targetNode.getNext(); // 循环获取对应位置的结点
    			}
    		}
    		return targetNode;
    	}
    	
    	// 获取链表的长度
    	public int getSize(){
    		return size;
    	}
    	
    	// 判断链表是否为空
    	public boolean isEmpty(){
    		return size == 0;
    	}
    	
    	// 打印链表数据
    	public void display(){
    		Node<E> node = head;
    		System.out.print("双向链表: ");
    		for(int i = 0; i < size; i++){
    			System.out.print(" " + node.getData());
    			node = node.getNext();
    		}
    		System.out.println("");
    	}
    }
    //结点类,包含结点的数据和指向下一个节点的引用
    public class Node<E> {
    	private E data; // 数据域
    	private Node<E> next; // 指针域保存着下一节点的引用
    	private Node<E> prev; // 指针域保存着上一节点的引用 (相比单链表,双向链表多了这个指针)
    	
    	public Node() {
    	}
    
    	public Node(E data) {
    		this.data = data;
    	}
    
    	public Node(E data, Node<E> next, Node<E> prev) {
    		this.data = data;
    		this.next = next;
    		this.prev = prev;
    	}
    
    	public E getData() {
    		return data;
    	}
    
    	public void setData(E data) {
    		this.data = data;
    	}
    
    	public Node<E> getNext() {
    		return next;
    	}
    
    	public void setNext(Node<E> next) {
    		this.next = next;
    	}
    
    	public Node<E> getPrev() {
    		return prev;
    	}
    
    	public void setPrev(Node<E> prev) {
    		this.prev = prev;
    	}
    }
    public class Main {
    	public static void main(String[] args) {
    		DoubleLinkedList<Integer> dll = new DoubleLinkedList<Integer>();
    		dll.addBeforeHead(2);
    		dll.addAfterTail(3);
    		dll.addBeforeHead(1);
    		dll.display();
    		dll.insert(4,4);
    		dll.insert(5,5);
    		dll.insert(6,6);
    		dll.display();
    		dll.delete(6);
    		dll.delete(3);
    		dll.delete(1);
    		dll.display();
    		System.out.println("双向链表的长度为:  " + dll.getSize());
    	}
    }


  • 相关阅读:
    【转载】使用IntelliJ IDEA创建Maven聚合工程、创建resources文件夹、ssm框架整合、项目运行一体化
    【转载】使用IntelliJ IDEA 配置Maven(入门)
    谈谈JS中的高级函数
    js中typeof和instanceof用法区别
    javascript “||”、“&&”的灵活运用
    前端资源教程合集
    使用Flexible实现手淘H5页面的终端适配
    H5实现的手机摇一摇
    html5移动端页面分辨率设置及相应字体大小设置的靠谱使用方式
    优化RequireJS项目(合并与压缩)
  • 原文地址:https://www.cnblogs.com/pangblog/p/3357886.html
Copyright © 2011-2022 走看看