数据结构和算法:线性表链式存储的简单实现

一、先定义简单的线性表规则,然后实现

1、接口

/**
 * [Project]:moy-gradle-project  <br/>
 * [Email]:moy25@foxmail.com  <br/>
 * [Date]:2018/1/24  <br/>
 * [Description]: 简单的线性表定义<br/>
 *
 * @author YeXiangYang
 */
public interface SimpleList<E> {

    /**
     * 添加元素
     *
     * @param e 需要添加的元素
     * @return 添加成功返回<tt>true<tt/>
     */
    boolean add(E e);

    /**
     * 将元素添加到指定下标上,对应下标不存在抛出异常
     *
     * @param index 下标
     * @param e     元素
     * @return 添加成功返回<tt>true<tt/>
     */
    boolean add(int index, E e);

    /**
     * 删除最后一个元素,集合为空则抛出异常
     *
     * @return 被删除的元素
     */
    E removeLast();


    /**
     * 删除指定下标的元素,对应下标不存在抛出异常
     *
     * @param index
     * @return 被删除的元素
     */
    E remove(int index);

    /**
     * 删除集合中的对于元素
     *
     * @param e 需要被删除的元素
     * @return 删除成功返回<tt>true<tt/>
     */
    boolean remove(E e);

    /**
     * 将指定下标改成对应元素,对应下标不存在抛出异常
     *
     * @param index 下标
     * @param e     需要添加到指定位置为元素
     * @return
     */
    E set(int index, E e);

    /**
     * 获取指定下标的元素,对应下标不存在抛出异常
     *
     * @param index 下标
     * @return 下标对应的元素
     */
    E get(int index);

    /**
     * 返回元素对应的最小下标
     *
     * @param e 元素
     * @return 返回元素对应的最小下标,不存在返回<tt>-1<tt/>
     */
    int indexOf(E e);

    /**
     * 判断集合中是否包含目标元素
     *
     * @param o 目标元素
     * @return 该集合存在目标元素,返回<tt>true<tt/>
     */
    boolean contains(Object o);

    /**
     * 获取集合元素个数
     *
     * @return 集合中元素个数
     */
    int size();

    /**
     * 判断集合中是否为空
     *
     * @return 集合中为空返回<tt>true<tt/>
     */
    boolean isEmpty();

    /**
     * 清除集合中所有元素
     */
    void clear();

    /**
     * 重写toString方法
     *
     * @return 返回友好信息
     */
    String toString();
}
View Code

2、实现

package com.moy.data.structure.list;


/**
 * [Project]:moy-gradle-project  <br/>
 * [Email]:moy25@foxmail.com  <br/>
 * [Date]:2018/1/27  <br/>
 * [Description]: <br/>
 *
 * @author YeXiangYang
 */
public class SimpleLinkedList<E> implements SimpleList<E> {
    private int size;
    private transient Node<E> first;
    private transient Node<E> last;

    @Override
    public boolean add(E e) {
        return add(size, e);
    }

    @Override
    public boolean add(int index, E e) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("index:" + index + ",size:" + size);
        }
        if (null != first) {
            if (0 == index) {
                Node<E> newData = new Node<>(e, first);
                first = newData;
            } else if (size == index) {
                Node<E> newData = new Node<>(e, null);
                last.next = newData;
                last = newData;
            } else {
                Node<E> prevNode = getNode(index - 1);
                Node<E> oldNode = prevNode.next;
                Node<E> newData = new Node<>(e, oldNode);
                prevNode.next = newData;
            }
        } else {
            Node<E> newData = new Node<>(e, null);
            this.first = newData;
            this.last = newData;
        }
        size++;
        return Boolean.TRUE;
    }

    @Override
    public E removeLast() {
        return remove(size - 1);
    }

    @Override
    public E remove(int index) {
        rangeCheck(index);
        E oldData = null;
        if (0 == index) {
            oldData = first.data;
            first.data = null;
            first = first.next;
        } else if (size - 1 == index) {
            Node<E> lastNode = getNode(index - 1);
            lastNode.next = null;
            oldData = last.data;
            last.data = null;
            last = lastNode;
        } else {
            Node<E> lastNode = getNode(index - 1);
            Node<E> currentNode = lastNode.next;
            Node<E> nextNode = currentNode.next;
            lastNode.next = nextNode;
            oldData = currentNode.data;
            currentNode.data = null;
            currentNode.next = null;
        }
        size--;
        return oldData;
    }

    @Override
    public boolean remove(E e) {
        int targetIndex = indexOf(e);
        if (targetIndex >= 0) {
            remove(targetIndex);
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    @Override
    public E set(int index, E e) {
        Node<E> node = getNode(index);
        E oldData = node.data;
        node.data = e;
        return oldData;
    }

    @Override
    public E get(int index) {
        Node<E> node = getNode(index);
        return node.data;
    }

    private Node<E> getNode(int index) {
        rangeCheck(index);
        Node<E> current = this.first;
        if (null != current) {
            int dataIndex = -1;
            while (null != current) {
                dataIndex++;
                if (dataIndex == index) {
                    return current;
                }
                current = current.next;
            }
        }
        throw new IllegalArgumentException("index:" + index + ",size:" + size);
    }

    private void rangeCheck(int index) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("index:" + index + ",size:" + size);
        }
    }

    @Override
    public int indexOf(E e) {
        if (null != first) {
            int index = -1;
            Node<E> current = this.first;
            do {
                index++;
                if (null == e) {
                    if (null == current.data) {
                        return index;
                    }
                } else {
                    if (e.equals(current.data)) {
                        return index;
                    }
                }
                current = current.next;
            } while (null != current);
        }
        return -1;
    }

    @Override
    public int size() {
        return size;
    }

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

    @Override
    public boolean contains(Object o) {
        try {
            E e = (E) o;
            return indexOf(e) >= 0;
        } catch (Exception e) {
            // 转型出错则不包含
        }
        return Boolean.FALSE;
    }

    @Override
    public void clear() {
        if (null != first) {
            Node<E> currentNode = this.first;
            while (null != currentNode) {
                currentNode.data = null;
                currentNode = currentNode.next;
            }
        }
        first = null;
        last = null;
        size = 0;
    }

    private static class Node<E> {
        Node<E> next;
        E data;

        public Node(E data, Node<E> next) {
            this.next = next;
            this.data = data;
        }
    }

    public SimpleLinkedList() {
        first = null;
        last = null;
        size = 0;
    }

    @Override
    public String toString() {
        if (null == first) {
            return "[]";
        }
        StringBuilder result = new StringBuilder();
        Node<E> currentNode = this.first;
        boolean isFirst = Boolean.TRUE;
        do {
            if (isFirst) {
                result.append("[");
                isFirst = Boolean.FALSE;
            } else {
                result.append(", ");
            }
            result.append(String.valueOf(currentNode.data));
            currentNode = currentNode.next;
        } while (null != currentNode);
        result.append("]");
        return result.toString();
    }
}

3、测试

package com.moy.data.structure;

import com.moy.data.structure.list.SimpleLinkedList;
import com.moy.data.structure.list.SimpleList;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.LinkedList;
import java.util.List;

/**
 * [Project]:moy-gradle-project  <br/>
 * [Email]:moy25@foxmail.com  <br/>
 * [Date]:2018/1/28  <br/>
 * [Description]:
 * <p><br/>
 *
 * @author YeXiangYang
 */
public class SimpleLinkedListTest {

    SimpleList<Object> simpleList;
    List<Object> list;

    @Before
    public void before() {
        int len = 10;

        simpleList = new SimpleLinkedList<>();
        list = new LinkedList<>();

        insertInitSimpleList(len);
        insertInitList(len);

        System.out.println("**************** Before ******************");
        System.out.println("自定义执行测试方法之前:	" + simpleList);
        System.out.println("官方的执行测试方法之前:	" + list);
    }

    private void insertInitList(int len) {
        for (int i = 0; i < len; i++) {
            if (len / 2 == i) {
                list.add(null);
            } else {
                list.add(i);
            }
        }
    }

    private void insertInitSimpleList(int len) {
        for (int i = 0; i < len; i++) {
            if (len / 2 == i) {
                simpleList.add(null);
            } else {
                simpleList.add(i);
            }
        }
    }

    @After
    public void after() {
        System.out.println("自定义执行测试方法之后:	" + simpleList);
        System.out.println("官方的执行测试方法之后:	" + list);
        System.out.println("**************** After *******************");
        System.out.println();
    }

    @Test
    public void addTest() {
        int index = 10;
        Object data = 123;
        try {
            System.out.println(simpleList.add(index, data));
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            list.add(index, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void removeTest() {
        System.out.println(list.remove(list.size() - 1));
        System.out.println(simpleList.removeLast());


        Integer removeData = new Integer("7");
        System.out.println(list.remove(removeData));
        System.out.println(simpleList.remove(removeData));

        System.out.println(list.remove(null));
        System.out.println(simpleList.remove(null));
    }

    @Test
    public void setTest() {
        int index = 0;
        Object data = 2333;
        try {
            System.out.println(simpleList.set(index, data));
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            System.out.println(list.set(index, data));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Test
    public void getTest() {
        int index = 0;
        try {
            System.out.println(simpleList.get(index));
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            System.out.println(list.get(index));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void isEmptyTest() {
        System.out.println(list.isEmpty());
        System.out.println(simpleList.isEmpty());
    }

    @Test
    public void containsTest() {
        Object object = 0;
        System.out.println(list.contains(object));
        System.out.println(simpleList.contains(object));
    }


    @Test
    public void clearTest() {
        list.clear();
        simpleList.clear();
    }
}
View Code

4、总结

     a、实现简单的链式线性表来加深印象,使用链式存储的好处是不用担心扩容问题、新增和删除操作也不用进行数组位移,但是查找元素还是要遍历所有元素

     b、查看官方实现java.util.LinkedList可知,其实现使用双向节点,在查询也做了优化,根据元素位置和链表总个数,决定从头节点还是尾节点开始查询

yexiangyang

moyyexy@gmail.com


 

原文地址:https://www.cnblogs.com/moy25/p/8506231.html