我们每天做着和昨天一样的事情,却又希望明天的结果与今天不一样。呵呵!!!

前言

程序 = 数据结构 + 算法。其重要性不言而喻,不多说,直接进入正题。

线性表是由零个或多个元素组成的有限序列,通俗来说就是具有线性一样的性质----好家伙,说了跟没说一样。

线性表从存储方式来看可以分为顺序存储链式存储。顺序表有几个基础操作,插入,删除,及查询。当然,还有一些很多其它的操作,为了简单,本例将通过代码实现顺序存储与链式存储。

 

一、顺序存储

如下图,按着顺序存储下去,一般采用数组实现

java 线性表单长度 java中线性表_java 线性表单长度

插入:

java 线性表单长度 java中线性表_数据结构_02

删除:

第一步,将待删除数据删除

第二步,将后面数据往前挪

查询:

可直接通过索引位置查询。

不多说,直接上代码。

public class ZListImpl implements ZList {
    // 数据集合
    private ZElement[] datas;

    // 数组最大长度
    private final int maxLength;

    /**
     * 数组初始长度为0
     */
    private int length = 0;

    public ZListImpl(int maxLength) {
        this.maxLength = maxLength;
        this.datas = new ZElement[maxLength];
    }


    @Override
    public void delete(int index) {
        if (index < 0 || index > length - 1) {
            System.err.println("index越界");
        }
        // 当前索引位置数据后面的往前挪一位
        for (int i = index; i < length; i++) {
            datas[i] = datas[i+1];
        }
        //数组长度减一
        length--;
    }

    @Override
    public void add(ZElement zElement) {
        // 不允许插入空值
        if (zElement.getData() == null) {
            return;
        }
        // 当前数组长度大于最大长度,暂不支持动态扩容
        if (length >= maxLength) {
            System.err.println("该链表数据已满");
        }
        datas[length] = zElement;
        // 数组长度增加
        length++;
    }

    @Override
    public int getId(ZElement element) {
        // -1 表示不存在该元素
        if (element.getData() == null) {
            return -1;
        }
        // 如果有多个元素匹配,返回第一个索引值
        for (int i = 0; i < length; i++) {
            if (datas[i].getData().equals(element.getData())) {
                return i;
            }
        }
        return -1;
    }

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

二、链式存储

链式存储的特性节点信息存储着两部分内容,数据与上/下一个节点的地址,这里以单链表为例。

插入,画的略显粗糙

如图,我们要在节点2后面插入5,需要将节点5的后继指向节点2下一个节点-即3,然后再将节点2和后继节点指向5,完成插入操作

java 线性表单长度 java中线性表_java 线性表单长度_03

 

删除

第一步,当前节点的后继节点指向待删除节点的后继节点

第二步,。。。。,对没有了

查询

使用游标,从头节点开始,如果查询不到,游标往后走,遍历到下一个节点,直到查询到数据或全部链表查询完成。

代码如下(删除的代码)

import javax.xml.soap.Node;

public class ZLinkImpl implements ZLinkInterface {
    // 初始化头节点
    ZNode head = null;
    // 链表长度
    public int size = 0;

    @Override
    public void add(String target, String data) {
        ZNode targetNode = get(target);
        if (targetNode == null) {
            add(data);
        } else {
            ZNode zNode = new ZNode(data);
            zNode.setNext(targetNode.getNext());
            targetNode.setNext(zNode);
            size++;
        }
    }

    @Override
    public void delete(String data) {
        ZNode pNode = getPreNode(data);
        ZNode next = pNode.getNext();
        // 不是最后一个节点
        if (next != null) {
            // 上一节点数据指向当前节点的下一个节点
            pNode.setNext(next.getNext());
        } else {
            pNode.setNext(null);
        }
        this.size--;

    }

    @Override
    public ZNode get(String data) {
        if (this.size != 0 && data != null) {
            ZNode next = head;
            while (next != null) {
                if (data.equals(next.getData())) {
                    return next;
                } else {
                    next = next.getNext();
                }
            }
        }
        return null;
    }

    public ZNode getPreNode(String data) {
        if (this.size != 0 && data != null) {
            ZNode next = head.getNext();
            while (next != null) {
                if (data.equals(next.getNext().getData())) {
                    return next;
                } else {
                    next = next.getNext();
                }
            }
        }
        return null;
    }

    // 没有目标,采用尾插法插入到链表最后
    public void add(String data) {
        // 当前链表为空
        if (this.size == 0) {
            head = new ZNode(data);
        } else {
            // 当前链表游标,获取链表最后游标
            ZNode thisCur = head;
            while (thisCur != null && thisCur.getNext() != null) {
                thisCur = thisCur.getNext();
            }
            // 待插入链表插入到当前节点后面
            ZNode willNode = new ZNode(data);
            thisCur.setNext(willNode);
        }
        size++;
    }
}

主类

public class ZLinkMain {
    public static void main(String[] args) {
        ZLinkImpl zLink = new ZLinkImpl();
        zLink.add("1");
        zLink.add("2");
        zLink.add("3");
        zLink.add("4");
        zLink.add("2","5");
        System.out.println(zLink.size);
    }
}

调试看到的结果 1 -> 2 -> 5- > 3 ->4

java 线性表单长度 java中线性表_java 线性表单长度_04

三、总结

顺序存储相对于链式存储来说

优点:快速存取元素,无需记录元素关联的数据

缺点:数据碎片化,插入删除效率较低

 

当然,其实里面还有一些bug以及很多设计的不完善的地方,最完整的代码可以看看jdk List集合的源码,里面有各种各样的api,例如倒置,两个线性表之间 操作,底层还有自动扩容等,都是需要我们大量时间去研究和学习的,话说回来,理解了与写代码是两回事儿。

还有快慢指针(可用来查询链表中间值),静态链表(数组实现了链式存储,虽然现在基本上不用,其中的思考方式值得我们学习),约瑟夫算法以及魔术师发牌的实现,有机会我会把这几个算法整理一下发出来。从一个学习者来说,我已经懂了,如果要结合代码将这个问题讲清楚,我还得再学习,反之,如果我能把这些问题全部都写出来,那我肯定掌握了这些内容,这也是我写文章的初衷。最后,希望大家做时间的朋友,共勉。