恋上数据结构 链表(手写LinkedList+练习)

Posted 结构化思维wz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恋上数据结构 链表(手写LinkedList+练习)相关的知识,希望对你有一定的参考价值。

Gitee地址

LinkedList(链表)

动态数组有个明显的缺点:
动态数组可能会造成内存空间的大量浪费

能否用到多少内存就申请多少内存呢?链表就可以办到这一点,链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的。

节点类(Node)

/**
     * 节点类
     */
    private static class Node<E>
        /**
         * 存储的元素
         */
        E element;

        /**
         * 下一个节点
         */
        Node<E> next;

        /**
         * 构造函数
         */
        public Node(E element, Node<E> next) 
            this.element = element;
            this.next = next;
        
    

接口设计

由于链表与动态数组可以抽象出共同的方法,所以我们可以实现接口来优化代码。

抽象接口之后创建对象的方法变为:

List<Interger> list = new LinkedList();

接口设计为:

package 链式结构;

public interface List<E> 

	static final int ELEMENT_NOT_FOUND = -1;
	/**
	 * 清除所有元素
	 */
	void clear();

	/**
	 * 元素的数量
	 * @return
	 */
	int size();

	/**
	 * 是否为空
	 * @return
	 */
	boolean isEmpty();

	/**
	 * 是否包含某个元素
	 * @param element
	 * @return
	 */
	boolean contains(E element);

	/**
	 * 添加元素到尾部
	 * @param element
	 */
	void add(E element);

	/**
	 * 获取index位置的元素
	 * @param index
	 * @return
	 */
	E get(int index);

	/**
	 * 设置index位置的元素
	 * @param index
	 * @param element
	 * @return 原来的元素ֵ
	 */
	E set(int index, E element);

	/**
	 * 在index位置插入一个元素
	 * @param index
	 * @param element
	 */
	void add(int index, E element);

	/**
	 * 删除index位置的元素
	 * @param index
	 * @return
	 */
	E remove(int index);

	/**
	 * 查看元素的索引
	 * @param element
	 * @return
	 */
	int indexOf(E element);

手写LinkedList

LinkedList

package 链式结构.linkedlist;

import org.w3c.dom.Node;
import 链式结构.List;

/**
 * @ClassName: LinkedList
 * @Description: 链表
 * @author: wangz48
 * @date: 2021-12-27 9:57
 */

public class LinkedList<E> implements List 

    /*==============成员变量================*/
    /**
     * 链表长度
     */
    private int size;
    /**
     * 头结点
     */
    private Node first;



    /*===============构造方法===============*/
    /**
     * 默认无参构造,因为不需要传容量
     */
    public LinkedList()
    


    /*===============成员方法===============*/

    /**
     * 清空链表
     * size = 0;
     * first = null
     */
    @Override
    public void clear() 
        size = 0;
        first = null;
    

    @Override
    public int size() 
        return size;
    

    @Override
    public boolean isEmpty() 
        return size == 0;
    

    @Override
    public boolean contains(Object element) 
        return indexOf(element) != ELEMENT_NOT_FOUND;
    

    @Override
    public void add(Object element) 
        add(size,element);
    

    @Override
    public Object get(int index) 
        Node<E> node = node(index);
        return node.element;
    

    @Override
    public Object set(int index, Object element) 
        Node<E> node = node(index);
        E old = node.element;;
        node.element = (E) element;
        return old;
    

    /**
     * 添加元素。需要找index-1的元素
     * @param index
     * @param element
     */
    @Override
    public void add(int index, Object element) 
        if (index == 0)
            first = new Node<>(element, first);
        else 
            //前一个节点
            Node<E> preNode = node(index - 1);
            //新节点
            Node<E> node = (Node<E>) new Node(element, preNode.next);
            //前一个节点指向新的
            preNode.next = node;
        
        //长度增加
        size++;
    
    private Node<E> node(int index)
        rangeCheck(index);
        Node<E> node = first;
        for (int i = 0; i < index; i++) 
            node = node.next;
        
        return node;
    

    /**
     * 获取前面的元素,用next指向index+1的节点
     * @param index
     * @return
     */
    @Override
    public Object remove(int index) 
        rangeCheck(index);
        Node<E> node = first;
        if (index == 0)
         first = first.next;
        else 
            Node<E> prevNode = node(index - 1);
            prevNode.next = prevNode.next.next;
        
        size--;
        return node.element;
    

    @Override
    public int indexOf(Object element) 
        if (element == null)
            Node<E> node = first;
            for (int i = 0; i < size; i++) 
                if (node.element == null)return i;
                node = node.next;
            
        else 
            Node<E> node = first;
            for (int i = 0; i < size; i++)
                if (element.equals(node.element))return i;
                node = node.next;
            
        
        return ELEMENT_NOT_FOUND;
    

    @Override
    public String toString()
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("size=").append(size).append(",[");
        Node<E> node = first;
        for (int i = 0; i < size; i++) 
            if(i != 0)
                stringBuilder.append(",");
            
            stringBuilder.append(node.element);
            node = node.next;
        
        stringBuilder.append("]");
        return stringBuilder.toString();
    

    /*===============其他方法===============*/

    /**
     *  边界检查
     */
    private void outOfBounds(int index)
        throw new IndexOutOfBoundsException("Index"+index+",Size:"+size);
    
    /**
     * 权限检查
     */
    private void rangeCheck(int index)
        if (index < 0 || index >= size)
            outOfBounds(index);
        
    
    /**
     * add检查索引越界
     */
    private void rangeCheckForAdd(int index)
        if (index < 0 || index > size)
            outOfBounds(index);
        
    


    /*===============节点内部类===============*/

    /**
     * 节点类
     */
    private static class Node<E>
        /**
         * 存储的元素
         */
        E element;

        /**
         * 下一个节点
         */
        Node<E> next;

        /**
         * 构造函数
         */
        public Node(E element, Node<E> next) 
            this.element = element;
            this.next = next;
        
    


练习

1.删除链表中的节点

分析:

当前节点的值 = .next的值

当前节点的next= .next.next;

class Solution 
    public void deleteNode(ListNode node) 
        node.val = node.next.val;
        node.next = node.next.next;
    

2.反转链表

递归解法

class Solution 
    public ListNode reverseList(ListNode head) 
        //返回条件
        if(head == null || head.next == null)return head;
        
        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    

迭代法

class Solution 
    public ListNode reverseList(ListNode head) 
        if(head == null || head.next == null)return head;
        ListNode newHead = null;
        while(head != null)
            ListNode tmp = head.next;
            head.next = newHead;
            newHead = head;
            head = tmp;
        
        return newHead;
    

以上是关于恋上数据结构 链表(手写LinkedList+练习)的主要内容,如果未能解决你的问题,请参考以下文章

手写LinkedList

LinkedList 链表及练习

从0开始手写ArrayList动态数组和LinkedList双向链表

从0开始手写ArrayList动态数组和LinkedList双向链表

恋上数据结构手写ArrayList + Java动态扩容分析

恋上数据结构队列 Queue