数据结构与算法(java版) 第一季 - 04 双向链表

目录

01 简介

02 clear

03 add

04 remove

05 接口测试

06 总结

07 单向循环链表 add

08 单向循环链表 remove

09 约瑟夫问题

10 静态链表

11 ArrayList的优化思路


01 简介

  • 由于存在尾节点,直接是使用last可以访问,双向链表的存在使得访问更加容易一些,通过它的大小和size一半进行比较.
  •  将原始的节点进行添加的过程,添加头节点和尾部节点.
        private LinkedList.Node<E> first;
        private LinkedList.Node<E> last;
    
        public LinkedList() {
        }
  •  通过索引的方法进行寻找的方式是如下所示:
    private LinkedList.Node<E> node(int index) {
        this.rangeCheck(index);
        LinkedList.Node node;
        int i;
        if (index < this.size >> 1) {
            node = this.first;

            for(i = 0; i < index; ++i) {
                node = node.next;
            }

            return node;
        } else {
            node = this.last;

            for(i = this.size - 1; i > index; --i) {
                node = node.prev;
            }

            return node;
        }
    }

02 clear

  • java虚拟机之中存在gc root,即便两个对象是存在指针指着的,也可能是被清理掉的.
  • 情况一:栈指针之中的局部变量(局部变量指向的对象)
        public void clear() {
            this.size = 0;
            this.first = null;
            this.last = null;
        }

03 add

  • 插入节点的过程(考虑特殊位置)
  • 代码流程

04 remove

  • 删除元素的操作,进行断线处理
  •  代码流程

05 接口测试

  • 重写toString方法,可以使用System.out.println的方式进行测试.
        public String toString() {
            StringBuilder sb = new StringBuilder();
            
            if(prev != null)
            {
             sb.append(prev.element);   
            }else{
                sb.append("null");
            }
            
            sb.append("_").append(element).append("_");
            
            if(next != null)
            {
                sb.append(next.element);
            }else{
                sb.append("null")
            }
            
            return sb;
        }

06 总结

  • 单向链表和双向链表进行一个比较,操作数量会大大减少.(双向链表的优势)
  •  双向链表和动态数组进行比较的过程.
  • java官方在双向链表进行clear的时候,将节点之间的链条都是清空了.原因是由于迭代器的存在,清空clear的时候,可能是迭代器正在使用里面链条的节点,可能是不会进行销毁的.因此,最好是是将所有的链条都断开.(非必须)

07 单向循环链表 add

  • 单向循环链表示意图
  • 特殊情况:①当向index位置是0的地方进行插入的时候,是需要进行相应的一个注意,first指向插入的节点,最后一个位置的节点,指向这一个位置的节点.②没有节点的存在,在index为0的地方进行插入节点.如下图所示:

  • 代码段是如下所示:
        public void add(int index, E element) {
        
         rangeCheckForAdd(index);//检查index是否正确
            
            if(index == 0)
            {
                first = new Node<>(element,first);//创建一个新的节点,first指向这个节点
                
                //拿到最后一个节点
                Node<E> last = (size == )?first:node(size-1);
                last.next = first;
            }else{
                Node<E> prev = node(index-1);
                prev.next = new Node<>(element,prev.next);
            }
            size++;
        }

08 单向循环链表 remove

  • 删除操作也是需要注意0节点的过程.
  • 注意的情况:①如果要还删除的第一个节点的话,这里应当注意的是需要提前拿到最后一个节点,防止出现越界的情况.②只有一个元素的情况(直接进行滞空处理),如下图所示:

  • 代码段是如下所示:
    
            public  E remove(int index)
            {
                rangeCheck(index);
                
                Node<E> node = first;
                if(index == 0)//当index=0的时候,需要注意两种情况
                {
                    if(size == 1)
                    {
                        first = null;
                    }else {
                        Node<E> last = node(size - 1);
                        first = first.next;
                        last.next = first;
                    }
                }
                else{
                    Node<E> prev = node(index - 1);
                    node = prev.next;
                    prev.next = node.next;
                }
                size--;
                return node.element;
            }

09 约瑟夫问题

  • 所谓的约瑟夫问题就是进行一个枪毙的过程,比如说:每隔两个人就是会枪杀一个人,最终活下来的那个人就是最幸运的人。如下图所示:对于上述的问题,我们需要得出元素退出的顺序。
  • 如何进行设计,如下所示:
    public class Main {
    	public static void josephus(){
    		CircleLinkedList<Integer> list = new CircleLinkedList<>();
    		for(int i = 1; i <= 8; i++){
    			list.add(i);
    		}
    		list.reset(); //指向头结点
    		while(!list.isEmpty()){
    			list.next();
    			list.next();
    			System.out.println(list.remove());
    		}
    	}
    	
    	public static void main(String[] args) {
    		josephus();
    	}
    }
    

10 静态链表

  • 早期的编程语言是没有指针的,如何实现相应的链表功能?

        通过数组来模拟链表,称为静态链表;数组的每个元素存放2个数据:值、下一个元素的索引;数组0位置存放的是头结点信息。

        执行过程是如下所示: 

  •  如果数组的每个元素只能存放1个数据?那就使用两个数组,一个数组存放索引关系,一个数组存放值。

11 ArrayList的优化思路

  • 之前的ArrayList删除0位置的元素的时候,所有的数据需要进行一个移动。解决方式可以通过如下解释方式,加入一个first指针的方式。
  • 插入元素的优化方式。在插入的过程之中,通过对比前后元素的数量,选取少的一方元素进行移动,这样可以大大减少挪动移动的次数,原理是类似于LinkedList。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值