ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

双向链表实现

2021-12-15 13:34:39  阅读:132  来源: 互联网

标签:index 实现 list next 链表 双向 newNode 节点


1.1 基本介绍

1、单向链表优缺点

  • 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
  • 单向链表不能自我删除,需要靠辅助节点 ,而双向链表则可以自我删除。

2、双向链表基本介绍

双向链表也叫双向表,是链表的一种,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域(data)用来存储数据其中一个指针域(next)用来指向其后继结点,另一个指针域用来指向前驱结点(prev指针)。链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点。

1.2 添加操作

1、思路分析

头部插入

  • 新建插入节点newNode

  • first前驱指向newNode

  • newNode后驱指向first

  • first指向newNode,这时候head只是表示第二个节点,而head需要表示第一个节点故改变指向。

尾部插入

  • 新建插入节点newNode
  • newNode前驱指向last
  • last后驱指向newNode
  • last指向newNode,这时候last只是表示倒数第二个节点,而last需要表示最后节点故指向newNode

中间插入

新建插入节点newNode

找到要插入newNode的前一个节点preNode。和后一个节点nextNode

newNode后驱指向nextNode,nextNode前驱指向newNode,此时newNode和后面与链表已经联立,但是和前面处理分离状态。

preNode后驱指向newNodenewNode前驱指向preNode,此时插入完整操作完毕。

2、代码示例

链表类:DoubleLinkedList

package cn.linkedlist.demo03;

public class DoubleLinkedList<E> {
    // 链表元素的数量
    private int size;
    // 声明头结点
    private Node first;
    // 声明尾节点
    private Node last;

    // 创建Node节点
    private class Node{
        // 存放内容
        public E data;
        // 指向链表的上一个节点
        public Node prev;
        // 指向下一个节点
        public Node next;
        // 构造方法
        
        public Node() {
            
        }
        
        public Node(Node prev, E data, Node next) {
            this.prev = prev;
            this.data = data;
            this.next = next;
        }

        @Override
        public String toString(){
            return data.toString();
        }
    }

    // 初始化头结点
    public DoubleLinkedList(){
        first = null;
        last = null;
        size = 0;
    }

    /***
     * 获取链表中的元素个数
     * @return
     */
    public int getSize(){
        return size;
    }

    /***
     * 返回链表是否为空
     * @return
     */
    public boolean isEmpty(){
        return size == 0;
    }

    /***
     * 根据链表的index位置添加新的元素e
     * @param index
     * @param data
     */
    public void add(int index, E data){
        // 调用方法
        rangeCheckAdd(index);

        if (index == size) { // 往最后面添加元素
            addLast(data);
        } else if(index == 0){
            addLast(data);
        } else {
            // 新添加节点下一个元素
            Node nextNode = node(index);
            // 新添加节点的上一个元素
            Node prevNode = nextNode.prev;
            // 新添加节点
            Node newNode = new Node (prevNode, data, nextNode);
            // next节点的上一个prev指向新节点
            nextNode.prev = newNode;
            // prevNode节点的下一个next指向新节点
            prevNode.next = newNode;
        }
        size++;
    }

    /***
     * 在链表头添加新的元素e
     * @param data
     */
    public void addFirst(E data){
        // 创建一个新节点
       Node newNode = new Node(null, data, null);
       if(isEmpty()){
           last = newNode; // last -> newNode
       }else {
           first.prev = newNode; // first.prev->newNode
       }
       newNode.next = first; // newNode.next -> first;
       first = newNode;
       size++;
    }

    /***
     * 在链表末尾添加新的元素e
     * @param data
     */
    public void addLast(E data){
        // 创建一个新节点
        Node newNode = new Node(null, data, null);
        if(isEmpty()){
            first = newNode; // first->newNode
        }else{
            last.next = newNode; // last指向的节点指向新节点
            newNode.prev = last; // 新节点的前驱指向last指针
        }
        last = newNode; // last指针指向新节点
        size++;
    }
	
    /**
     * 获取index位置对应的节点对象
     * @param index
     * @return
     */
    private Node node(int index) {
        rangeCheck(index);
        Node node;
        if (index < (size >> 1)) {
            node = first;
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
        } else {
            node = last;
            for (int i = size - 1; i > index; i--) {
                node = node.prev;
            }
        }
        return node;
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append("size=").append(size).append(", [");
        // 定义一个指针变量
        Node cur = first;
        while(cur != null){
            res.append(cur + "->");
            cur = cur.next;
        }
        res.append("NULL");
        res.append("]");
        return res.toString();
    }

    // 索引值检查范围方法
    private void rangeCheck(int index){
        if(index < 0 || index >=size){
            // 调用越界处理方法
            outOfBounds(index);
        }
    }

    // 添加方法索引检查范围
    private void rangeCheckAdd(int index){
        if(index < 0 || index >size){
            // 调用越界处理方法
            outOfBounds(index);
        }
    }
    // 数组索引越界处理
    private void outOfBounds(int index){
        throw new IndexOutOfBoundsException("index:" + index + ", Size:" + size);
    }
}

测试类:DoubleLikedListTest

package cn.linkedlist.demo03;

public class DoubleLinkedListDemo01 {
    public static void main(String[] args) {
        DoubleLinkedList<Integer> list = new DoubleLinkedList<>();
        System.out.println("===链表头部插入===");
        for(int i=0; i<5; i++){
            list.addFirst(i);
            System.out.println(list);
        }

        System.out.println("===链表尾部插入===");
        list.addLast(12);
        list.addLast(111);
        list.addLast(123);
        list.addLast(15);
        System.out.println(list);

        System.out.println("===链表中间插入===");
        list.add(2, 23);
        list.add(7, 66);
        list.add(8, 39);

        System.out.println(list);
    }
}

3、代码示例

1.3 修改和查询操作

1、查询操作

链表类:DoubleLinkedList

/***
 * 得链表的第index个位置的元素
 * @param index
 * @return
*/
public E get(int index){
    return node(index).data;
}

/***
  * 获得链表的第一个元素
  * @return
 */
public E getFirst(){
    return get(0);
}

/***
  * 获得链表的最后一个元素
  * @return
 */
public E getLast(){
    return get(size - 1);
}

/***
 * 查找链表中是否有元素e
 * @param data
 * @return
*/
public boolean contains(E data){
    Node cur = first.next;
    while(cur != null){
        if(cur.data.equals(data))
            return true;
        cur = cur.next;
    }
    return false;
}

测试类:DoubleLikedListTest

package cn.linkedlist.demo03;

public class DoubleLinkedListDemo01 {
    public static void main(String[] args) {
        DoubleLinkedList<Integer> list = new DoubleLinkedList<>();
        for(int i=0; i<5; i++){
            list.addFirst(i);
        }
        list.addLast(12);
        list.addLast(111);
        list.addLast(123);
        list.addLast(15);
       
        list.add(2, 23);
        list.add(7, 66);
        list.add(8, 39);
        
        System.out.println("===查找元素===");
        Integer integer = list.get(2);
        System.out.println("通过索引获取元素:" + integer);
        Integer first = list.getFirst();
        System.out.println("第一个链表元素:" + first);
        Integer last = list.getLast();
        System.out.println("最后链表元素:" + last);
        boolean b = list.contains(23);
        System.out.println("是否存在该元素:" + b);
    }
}

2、执行结果

3、修改操作

链表类:DoubleLinkedList

/***
     * 修改链表的第index(0-based)个位置的元素为e
     * @param index
     * @param data
     */
public void update(int index, E data){
    // 调用索引检测方法
    rangeCheck(index);
    // 创建cur指针,指向虚拟头结点
    Node cur = first;
    for(int i = 0 ; i < index ; i ++) {
        cur = cur.next;
    }
    cur.data = data;
}

测试类:DoubleLikedListTest

package cn.linkedlist.demo03;

public class DoubleLinkedListDemo01 {
    public static void main(String[] args) {
        DoubleLinkedList<Integer> list = new DoubleLinkedList<>();
        for(int i=0; i<5; i++){
            list.addFirst(i);
        }
        list.addLast(12);
        list.addLast(111);
        list.addLast(123);
        list.addLast(15);
       
        list.add(2, 23);
        list.add(7, 66);
        list.add(8, 39);

        System.out.println("===修改节点元素===");
        System.out.println("linkedList(修改前)" + list);
        list.update(4, 38);
        System.out.println("linkedList(修改后)" + list);
    }
}

4、执行结果

1.4 删除操作

1、思路分析

因为是双向链表,因此可以实现自我删除某个节点,直接找到要删除的这个节点。

头结点删除

first节点的后驱节点的前指针prev改为null

first节点指向first.next,这样first就指向需要的第一个节点。

尾节点删除

尾删除就是删除双向链表中的最后一个节点,也就是尾指针所指向的那个节点,思想和头删除的思想一致。

last.prev.next=null尾节点的前一个节点(prev)的后驱节点等于null

last = last.prev尾节点指向它的前驱节点,此时尾节点由于步骤1next已经为null,完成删除。

中间删除

找到待删除节点deleteNode的前驱节点preNodepreNode.next是要删除的节点

preNode.next.next.pre=preNode,将待删除deleteNode的后驱节点nextNodeprev指针指向preNode,等价于nextNode.pre=preNode

preNode.next=preNode.next.next;,此时deleteNode被跳过成功删除。

2、代码示例

链表类:DoubleLinkedList

/***
 * 从链表中删除index位置的元素, 返回删除的元素
 * @param index
*/
public void remove(int index){
    // 调用索引检测方法
    rangeCheck(index);
    // 条件判断
    if(index == 0){
        removeFirst();
    }else if(index == size -1 ){
        removeLast();
    }else {

        //删除位置的前一个元素
        Node preNode = first;
        for(int i=0; i < index-1; i++) {
            preNode = preNode.next;
        }
        //要删除位置的元素
        Node deleteNode = preNode.next;
        //要删除元素的下一个元素
        Node nextNode = deleteNode.next;
        
        preNode.next = nextNode;
        nextNode.prev = preNode;

        size--;
    }
}

/***
 * 从链表中删除第一个元素, 返回删除的元素
*/
public void removeFirst(){
    if (size == 1)
    {
        first = null;
        last = null;
    } else {
        first =first.next;
    }
    size--;
}

/***
 * 从链表中删除最后一个元素, 返回删除的元素
*/
public void removeLast(){
    if (size == 1)
    {
        first = null;
        last = null;
    } else {
        last.prev.next = null;
        last = last.prev;
    }
    size--;
}

/***
 * 从链表中删除元素e
 * @param data
 */
public void removeElement(E data){
    // 创建头结点
    Node prev = first;
    while(prev.next != null){
        if(prev.next.data.equals(data))
            break;
        prev = prev.next;
    }

    if(prev.next != null){
        Node delNode = prev.next;
        prev.next = delNode.next;
        delNode.next = null;
        size --;
    }
}

测试类:DoubleLikedListTest

package cn.linkedlist.demo03;

public class DoubleLinkedListDemo01 {
    public static void main(String[] args) {
        DoubleLinkedList<Integer> list = new DoubleLinkedList<>();
        for(int i=0; i<5; i++){
            list.addFirst(i);
        }
        
        list.addLast(12);
        list.addLast(111);
        list.addLast(123);
        list.addLast(15);
        
        list.add(2, 23);
        list.add(7, 66);
        list.add(8, 39);

        System.out.println("===删除链表节点前====");
        System.out.println(list);
        System.out.println("===删除链表节点后====");

        // 删除链表第一个节点
        list.removeFirst();
        System.out.println(list);
        // 根据链表index位置的元素, 返回删除的元素
        list.remove(2);
        System.out.println(list);

        // 删除链表最后一个节点
        list.removeLast();
        System.out.println(list);

        // 删除链表中的元素
        list.removeElement(39);
        System.out.println(list);
    }
}

3、执行结果

标签:index,实现,list,next,链表,双向,newNode,节点
来源: https://blog.csdn.net/hxy1625309592/article/details/121950189

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有