定义:

线性表全名线性存储构造是最根本、最简略、也是最罕用的一种数据结构,专门用于存储逻辑关系为"一对一"的数据。

个性:

  1. 数据类型统一
  2. 数据的逻辑关系都具备一对一关系
  3. 数据元素无限(专业术语为:存在惟一一个被称为“第一个”的数据元素,存在惟一一个被称为“最初一个”的数据元素)
  4. 是有序序列(专业术语为:除第一个元素外,每个元素都有惟一的一个”间接前驱“。除最初一个元素外,每一个元素都有惟一的”间接后继“)

存储形式:

线性表,基于数据在理论物理空间中的存储状态,又可细分为**程序表(顺序存储构造)**和**链表(链式存储构造)**。

程序表(顺序存储构造):

定义:

程序表,个别应用数组实现。也就是在内存中找个初始地址,而后数据元素顺次排队,数组大小有两种形式指定——动态调配和是动静扩大。

特点:

  1. 随机拜访:可通过首地址和元素序号在单位工夫O(1)内找到指定的元素。
  2. 存储密度高:存储密度高是因为每个结点存储空间指用来存储数据元素,没有别的额定开销。
  3. 物理地位相邻:物理地位和逻辑地位一样,放弃相邻,因而插入和删除元素须要挪动大量元素,比拟耗时。这是物理构造相邻的所有数据结构的通病,尽管拜访快,然而如果有频繁的增删挪动操作,就会效率很低。

    长处:

  4. 空间利用率高(理由:间断寄存)
  5. 存取速度高效,通过下标间接进行存储和读取。(想想排队哈)
  6. 顺序存储,随机读取(不算是长处,算是特点)

毛病:

  1. 插入和删除比较慢。(想想插队,前面的全副须要往后移一个位)
  2. 程序表开始时就要定义一个长度,因而是存在空间限度的。当须要存储的元素个数可能多于程序表元素时,可能呈现“溢出”问题。

链式存储构造:

定义:

用一组任意的存储单元存储线性表的数据元素(这组存储单元能够是间断的,也能够是不间断的),包含数据域和指针域,数据域存数据,指针域批示其后继的信息。

特点:

随机存储、程序读取:物理地位和逻辑地位不同,物理地位随机存储,但都通过指针域连成线,能够按逻辑程序读取

长处:

  1. 插入和删除的速度快,保留原有的物理程序(只扭转下指针。想想上述的插队问题就明确了)。
  2. 没有空间限度,根本只与内存空间大小无关。(满天飞)
  3. 随机存储,程序读取(算是特点)

毛病:

  1. 查找元素比较慢(不能进行索引拜访,只能从头结点开始程序查找)
  2. 占用额定的空间用来存储指针(不是间断寄存的(满天飞理解下),空间碎片多)
    造成空间节约。

实操

创立线性表接口类

/** * 线性表接口 * @author gxw * @date 2021/11/1 早晨21:50 */public interface LinearList {    /**     * 查找办法     */    //查找,是否蕴含g元素    boolean contains(Object g);    //查找,返回 g 元素所在位置    int indexOf(Object g);    //查找,返回第i地位的元素    Object getByIndex(int i);    /**     * 增加办法     */    //将元素插入到第i个地位    void add(int i, Object g) throws Exception ;    //将元素插入到最初    void add(Object g) throws Exception ;    //将g元素插入到x元素之前    boolean addBefore(Object x, Object g) throws Exception;    //将g元素插入到x元素之后    boolean addAfter(Object x, Object g) throws Exception;    /**     * 删除办法     */    //删除第i个元素    void remove(int i) throws Exception ;    //删除第一个为g的元素    void remove(Object g) throws Exception ;    /**     * 批改办法     */    //将第i个元素替换为g    boolean replace(int i, Object g);    //将x元素全副替换为g    boolean replaceAll(Object x, Object g);    /**     * 返回线性表大小     */    int getSize();    /**     * 判断线性表是否为空     */    boolean isEmpty();    /**     * 输入线性表     */    void display();}

程序表:

第一步:创立程序表实现类

/** * 线性表之程序表(顺序存储构造) * @author gxw * @date 2021/11/1 早晨21:51 */public class SequenceList implements LinearList {    //申明大小为maxSize的程序表    private Object[] myList;//程序表的存储空间    private int size;//程序表以后的长度    private int maxSize;//程序表最大的长度    //构造方法来初始化程序表    public SequenceList(int maxSizeParam){        //设置程序表的初始长度为0        size = 0;        //设置程序表的最大长度        maxSize = maxSizeParam;        //实例化程序表        myList = new Object[maxSize];    }    //是否蕴含g元素    @Override    public boolean contains(Object g) {//工夫复杂度O(n)        for (Object x : myList) {            if(x.equals(g))                return true;        }        return false;    }    //获取g元素在第几个地位    @Override    public int indexOf(Object g) {//工夫复杂度O(n)        for(int i = 0;i < size;i++){            if(myList[i].equals(g))                return i;        }        return -1;    }    //获取第i地位的元素    @Override    public Object getByIndex(int i) {//工夫复杂度O(1)        //判断是否合乎现有长度        if(i < 0 || i > size)            return null;        return myList[i];    }    @Override    public void add(int i, Object g) throws Exception {//工夫复杂度O(n)        //判断程序表是否曾经满员        if(size == maxSize)            throw new Exception("程序表已满员,不可插入!");//手动抛出异样        //判断i是否在正确范畴内        if(i < 0 || i > size)            throw new Exception("插入地位不合理,不可插入!");//手动抛出异样        //筹备执行插入,在插入之前,将要插入地位的元素往后移        for(int j = size;j > i;j--){            myList[j] = myList[j - 1];        }        //执行插入        myList[i] = g;        //现有程序表长度减少1        size++;    }    @Override    public void add(Object g) throws Exception {//工夫复杂度O(1)        //判断程序表是否曾经满员        if(size == maxSize)            throw new Exception("程序表已满员,不可插入!");//手动抛出异样        //执行插入,插入到最初        myList[size] = g;        //现有长度加一        size++;    }    @Override    public boolean addBefore(Object x, Object g) throws Exception {//工夫复杂度O(n)        //判断程序表是否曾经满员        if(size == maxSize)            return false;        //先获取x元素所在位置        int index = indexOf(x);        if(index < 0)            return false;        //将x元素以及后继元素往后移        add(index, g);        return true;    }    @Override    public boolean addAfter(Object x, Object g) throws Exception {//工夫复杂度O(n)        //判断程序表是否曾经满员        if(size == maxSize)            return false;        //先获取x元素所在位置        int index = indexOf(x);        if (index < 0)            return false;        //将x元素的后继元素往后移        add(index + 1, g);        return true;    }    @Override    public void remove(int i) throws Exception {//工夫复杂度O(n)        //判断程序表是否曾经为空        if(size == 0)            throw new Exception("程序表已空,无奈删除!");//手动抛出异样        //判断i元素是否在0-size范畴内        if(i < 0 || i > size)            throw new Exception("角标超出范围,无奈删除!");//手动抛出异样        //将i元素之后后继元素往前移        for(int j = i;j < size;j++){            myList[j] = myList[j + 1];        }        //程序表长度减一        size--;    }    @Override    public void remove(Object g) throws Exception {//工夫复杂度O(n)        //判断程序表是否曾经为空        if(size == 0)            throw new Exception("程序表已空,无奈删除!");//手动抛出异样        //查找元素的地位        int index = indexOf(g);        if(index >= 0){            //删除元素,并将后继元素往前移            remove(index);        }else{            throw new Exception("程序表无此元素,无奈删除!");//手动抛出异样        }    }    @Override    public boolean replace(int i, Object g) {//工夫复杂度O(1)        //判断程序表是否曾经为空        if(size == 0)            return false;        //判断i是否在0-size范畴内        if(i < 0 || i > size)            return false;        //执行替换,将i元素的值替换为g        myList[i] = g;        return true;    }    @Override    public boolean replaceAll(Object x, Object g) {//工夫复杂度O(n)        //判断程序表是否曾经为空        if(size == 0)            return false;        //暂存角标字符串        String indexStr = "";        //取出元素为x的所有角标        for (int i = 0;i < size;i++){            if(myList[i].equals(x)){                indexStr += i + ",";            }        }        indexStr = indexStr.substring(0, indexStr.length() - 1);        String[] indexArr = indexStr.split(",");        //将取出的所有角标全替换为g元素        for (int i = 0;i < indexStr.split(",").length;i++){            int index = Integer.parseInt(indexArr[i]);            //设置值            myList[index] = g;        }        return true;    }    @Override    public int getSize() {        return size;    }    @Override    public boolean isEmpty() {        return size == 0;    }    @Override    public void display() {        for (int i = 0;i < size;i++){            System.out.print(myList[i] + " ");        }        System.out.println("展现程序表完结:一共长度为:" + size);    }}

第二步:测试

public static void main(String[] args) throws Exception {        /**         * 程序表         */        SequenceList sequenceList = new SequenceList(10);        //增加        sequenceList.add("sequence ");        sequenceList.add("hello ");        sequenceList.add("world!");        sequenceList.add("hello ");        sequenceList.display();        //指定角标增加        sequenceList.add(1, "哈哈 ");        sequenceList.display();        //在指定元素之前增加        sequenceList.addBefore("哈哈 ", "呼呼 ");        sequenceList.display();        //在指定元素之后增加        sequenceList.addAfter("哈哈 ", "嘿嘿 ");        sequenceList.display();        //替换        sequenceList.replace(1, "略略 ");        sequenceList.display();        //将指定元素值全都替换成设置元素值        sequenceList.replaceAll("hello ", "HELLO ");        sequenceList.display();        //删除        sequenceList.remove(1);        sequenceList.display();        //指定元素删除        sequenceList.remove("HELLO ");        sequenceList.display();    }

后果:

链表:

第一步:因为单链表依赖于Node,所以创立Node类

/** * 单链表采纳了结点,所以须要以下定义 * 次要两个属性,一个是数据域(存放数据内容),一个是指针域(寄存下一个的结点的地址) */public class Node {    //数据域    private Object data;    //指针域    private Node next;    public Node(){        this.data = new Object();        this.next = null;    }    public Node(Object data, Node next){        this.data = data;        this.next = next;    }    public Node(Object data){        this.data = data;    }    public Object getData() {        return data;    }    public void setData(Object data) {        this.data = data;    }    public Node getNext() {        return next;    }    public void setNext(Node next) {        this.next = next;    }}

第二步:创立单链表实现类

/** * 线性表之链表(链式存储构造) * @author gxw * @date 2021/11/1 早晨21:53 */public class LinkedList implements LinearList {    private Node headNode = new Node();//定义一个头空结点    private int size;//定义一共有几个结点    @Override    public boolean contains(Object g) {        Node node = headNode;//从头结点开始        for(int i = 0;i < size;i++){            if(node.getData().equals(g)){                return true;            }            //拜访下一个结点            node = node.getNext();        }        return false;    }    @Override    public int indexOf(Object g) {        Node node = headNode;//从头结点开始        //因为头结点不存数据,所以间接获取子结点数据        node = node.getNext();        for(int i = 0;i < size;i++){            if(node.getData().equals(g)){                return i;            }            //拜访下一个结点            node = node.getNext();        }        return -1;    }    @Override    public Object getByIndex(int i) {        Node node = headNode;//从头结点开始        for(int j = 0;j < i;j++){            //拜访下一个结点,直到拜访的第i个地位            node = node.getNext();        }        return node.getData();    }    @Override    public void add(int i, Object g) throws Exception {        //如果i不在0-size范畴        if(i < 0 || i > size)            throw new Exception("角标超出失常范畴 i:" + i);        //获取到第i个后面的结点,只须要让后面的结点指针域指到新要增加的结点上,        // 本人的指针域指到第i个前面的结点上,就能够实现增加了        Node node = headNode;        for(int j = 0;j < i;j++){            node = node.getNext();//继续拜访指针域,直到拜访到第i个结点        }        //创立新要增加的结点        Node newNode = new Node();        //设置新结点的数据域        newNode.setData(g);        //设置新结点的指针域,将后面获取到的结点的指针域的值,赋值给新要增加的结点        newNode.setNext(node.getNext());        //而后让后面取得的结点的指针域指向新增加的指针,即可胜利增加        node.setNext(newNode);        //结点数加一        size++;    }    @Override    public void add(Object g) throws Exception {        //在最初增加结点        add(size, g);    }    @Override    public boolean addBefore(Object x, Object g) throws Exception {        //获取结点所在位置        int index = indexOf(x);        //如果没有匹配的结点        if(index < 0)            return false;        //在x结点前增加结点,相当于就是查找到结点地位以后地位        add(index, g);        return true;    }    @Override    public boolean addAfter(Object x, Object g) throws Exception {        //获取结点所在位置        int index = indexOf(x);        //如果没有匹配的结点        if(index < 0)            return false;        //在x结点后增加结点        add(index + 1, g);        return true;    }    @Override    public void remove(int i) throws Exception {        //如果i不在0-size范畴        if(i < 0 || i > size)            throw new Exception("角标超出失常范畴 i:" + i);        //删除结点,原理就是让此结点的前一个结点的指针域,指到此结点的下一个结点        Node node = headNode;        for (int j = 0;j < i;j++){            node = node.getNext();        }        //将前一个结点的指针域,指到此结点的下一个结点        node.setNext(node.getNext().getNext());        //结点数减1        size--;    }    @Override    public void remove(Object g) throws Exception {        //查找元素所在位置        int index = indexOf(g);        //执行删除        remove(index);    }    @Override    public boolean replace(int i, Object g) {        //如果i不在0-size范畴        if(i < 0 || i > size)            return false;        //找到第i个结点        Node node = headNode;        for (int j = 0;j < i + 1;j++){ //因为头结点是空结点,所以须要略过,就i + 1            node = node.getNext();        }        //而后将第i个结点的数据域更换为g        node.setData(g);        return true;    }    @Override    public boolean replaceAll(Object x, Object g) {        return false;    }    @Override    public int getSize() {        return size;    }    @Override    public boolean isEmpty() {        return size == 0;    }    @Override    public void display() {        Node node = headNode;        for (int i = 0;i < size;i++){            node = node.getNext();            System.out.print(node.getData() + " ");        }        System.out.println("展现实现,结点长度为:" + size);    }}

第三步:测试

public static void main(String[] args) throws Exception {              /**         * 单链表         */        LinkedList linkedList = new LinkedList();        //增加        linkedList.add("1");        linkedList.add("2");        linkedList.add("3");        linkedList.display();        //在2之前增加        linkedList.addBefore("2", "4");        linkedList.display();        //在2之后增加        linkedList.addAfter("2", "5");        linkedList.display();        //查找地位        System.out.println(linkedList.indexOf("1"));        System.out.println(linkedList.indexOf("2"));        System.out.println(linkedList.indexOf("3"));        //替换        linkedList.replace(1, "22 ");        linkedList.display();        //删除        linkedList.remove("3");        linkedList.display();    }

后果:

其它补充:

前驱:

数据结构中,一组数据中的每个个体被称为“数据元素”(简称“元素”)。

间接前驱:

某一元素的左侧相邻元素称为“间接前驱”

前驱元素:

位于此元素左侧的所有元素都统称为“前驱元素”

后继

间接后继:

某一元素的右侧相邻元素称为“间接后继”

后继元素:

位于此元素右侧的所有元素都统称为“后继元素”

————————————END—————————————
数据结构之线性表篇,在此完结,学习中的总结,心愿能够帮忙认真学习的你,如果总结有问题,也心愿贵人忘请斧正,谢谢!