自定义LinkedList数据结构

LinkedList是一个双向链表,长啥样呢

如图所示:

  • 前驱为了指向当前节点的上一个节点
  • 后驱为了指向当前节点的下一个节点
  • 中间item 存数据

数据结构是啥样子呢,代码如下:

public class LinkedList<E> {

    /**
     * 结点
     * @param <E>
     */
    private static class Node<E> {

        // 数据域
        E item;

        // 后驱指针
        Node<E> next;

        // 前驱指针
        Node<E> prev;

        // 构造方法 前驱 数据 后驱
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
}

了解了它的数据结构之后,看看它可以干啥,使用过他的小伙伴都知道,它有add方法,还可以在任意位置插入一个元素,可以get,可以remove 可以addAll 可以removeAll 等等

看下咋实现的嘞

add的实现

  • 向最尾元素插入数据,咋搞,看下实现代码
  • 	/**
    	 * 对外需要调用的方法
    	 * @param e 需要插入的原色
    	 */
    	public void add (E e) {
            // 从后面插入
    		linkLast(e);
    	}
    
    	/**
    	 * 在最后添加
    	 * @param e
    	 */
    	private void linkLast(E e) {
            // 首先你需要new 一个存放你数据的节点吧
            // 构造方法 入参咋填
            // 1.往最后面插入的 肯定是需要拿到最后的节点的last 后面说last从哪里来的 先理解它就 
           是最后一个
           // 2.构造方法内,因为是要放在最后,所以呢 原来的last就变成了存放的e的前驱,然后中间
           // 就是它的值域 最后呢,就是它的后驱,很显然现在放的就是最后,它的最后没东西,所以 
        // 放null
        	Node<E> newNode = new Node<E>(last, e, null);
    
           // 用一个临时指针 先指向最后的值,
    		Node<E> l = last;
            // 因为是要往最后添加的,所以newNode就是新的最后 我这描述的绝对白话文
            // 把last移动一下,移动到newNode的位置 下次在添加的时候 last就是这次的newNode了 以 此类推 
    		last = newNode;
            //  然后你会发现这里有个问题,万一我链表里,连个屁都没有咋办
            // 一个都没有说明什么,说明first都是空的 所以只需要把first 赋值给newNode就可以了
    		if (l == null) {
    			first = newNode;
    		}else {
                //  如果不是空 就要把它的后驱指针 指向新插入的节点
    			l.next = newNode;
    		}
    		size ++;
    	}

    get方法实现

  • 	/**
    	 * 获取第index位置上的节点的值域
    	 * @param index
    	 * @return
    	 */
    	public E get(int index) {
    // 首先判断一下 输入的index 不能超过范围
    		if(index < 0 || index >size) {
    			return null;
    		}
    		return node(index).item;
    	}
    
    	/**
    	 * 获取第index位置上的节点
    	 * @param index
    	 * @return
    	 */
    	private Node<E> node(int index) {
    		//index在前半部份 
    		if (index < (size / 2)) {
    			Node<E> node = first;
    			for(int i = 0; i < index; i++) {
    				node = node.next;
    			}
    			return node;
    		} else { //index在后半部份
    			Node<E> node = last;
    			for(int i = size - 1; i > index; i--) {
    				node = node.prev;
    			}
    			return node;
    		}
    	}

    add(int index, E e)实现

  • /**
    	 * �在index的位置上添加一个元素
    	 * @param index
    	 * @param e
    	 */
    	public void add (int index, E e) {
            // 判断输入合法性
    		if(index < 0 || index >size) {
        		return;
        	}
        // 如果输入的和大小一样 说明是往最后插入的 直接调用
    		if (index == size) {
    			linkLast(e);
    		} else {
            // 先取目标的节点
    			Node<E> target = node(index);   
                // 找到它的上一个节点
    			Node<E> pre = target.prev;
                // 前一个节点  当前存放的值  后一个节点就是找到的目标 
    			Node<E> newNode = new Node<E>(pre, e, target);
    			//要考虑index=0时的情况
    			if(pre == null) {
                    // 如果链表里只有1个 那么它的前驱一定是null 所以只需要把first移动到 新节点上就可以了
    				first = newNode;
    			} else {
                // 否则 找到前驱的下个节点赋值
    				pre.next = newNode;
    			}
    			pre = newNode;
    			size++;
    		}
    	}

    Remove实现

  •  
        public void remove(int index){
        	Node<E> target = node(index);
        	unlinkNode(target);
        }
        
        private void unlinkNode(Node<E> p) {
        	
    
            // 找头    	
        	Node<E> pre = p.prev;
            // 找尾
        	Node<E> next = p.next;
    
            // 头是空的
        	if (pre == null) {
                // 直接移动到 当前节点的下一个 那么当前节点就没有了
    			first = p.next;//删除头节点
    		} else {
                // 否则 头的下一个 执行当前节点的下一个 忽略掉自己 也就删除了
    			pre.next = p.next;
    		}
    
            // 同理
        	if (next == null) {
    			last = p.prev;//删除尾结节
    		} else {
    			next.prev = p.prev;
    		}
        	size--;
        }

    一看就会,一写就错

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值