数据结构二 (线性表)

2018-07-12  本文已影响6人  Rreply

线性表(List)

定义:是零个或者多个数据元素的有限序列
线性表首先是一个序列,其内部的元素都是有序的,然后是一个有限的序列。例如十二星座,是有序的,有限的,所以它是一个List。
位序:线性表中元素在其中的位置。

定义:是指用一段地址连续的存储单元依次存储线性表的数据元素。
例如在图书馆替室友占座,一般都是占连续的一排座位,这个就是顺序存储结构。

描述线性表的三个属性

存储空间的起始位置
线性表的最大存储容量
线性表的当前长度

数组长度与线性表长度的区别
数组长度是存放线性表的存储空间的长度,一般来说是不变的。
线性表长度是线性表中数据元素的个数,是可变的。
读取的时间复杂度
只要知道数组中第一个元素的存储位置,后面的元素都可以使用N = A + (n - a) * dx来得到,其中大写字母为元素的物理存储位置,小写字母为 元素在数组中的位置。因此不管n如何变化,只需要一步就能够实现读取的操作,其时间复杂度为O(1)。

步骤

  1. 将插入位置以及其后的元素都往后移一位
  2. 将要插入的元素放到插入位置上

Java实现

public class insert {

    static int[] test_1; //原始的数组

    /**
     *对原始的数组进行初始化
     */
    private static int[] getTest() {
        test_1 = new int[10];
        for (int i = 0; i < test_1.length; i++) {
            test_1[i] = i;
        }
        return test_1;
    }

    public static int[] insertTest(int s, int[] test, int num) {
        int[] test_2 = new int[test.length + 1];
        for (int i = 0; i < s-1; i++) {
            test_2[i] = test[i];
        }
        for (int i = s-1; i < test.length; i++) {
            test_2[i+1] = test[i];
        }
        test_2[s-1] = num;
        return test_2;
    }

    public static int[] deleteTest(int s, int[] test) {
        int[] test_3 = new int[test.length - 1];
        for (int i = 0; i < s-1; i++) {
            test_3[i] = test[i];
        }
        for (int i = s; i < test.length; i++) {
            test_3[i - 1] = test[i];
        }
        return test_3;
    }

    public static void main(String[] args) {

        int[] test = getTest();
        int[] results = insertTest(3, test, 2);
        for (int i = 0; i < results.length; i++) {
            System.out.println(results[i]);
        }
        int[] results1 = deleteTest(4, test);
        for (int i = 0; i < results1.length; i++) {
            System.out.print(results1[i]);
        }
    }
}

由代码可知,线性表顺序存储的增加与删除的时间复杂度都是O(n)。

顺序存储结构的优点

线性表的链式存储结构

特点:用一组任意的存储单元存储线性表的数据元素,这组数据元素单元可以是连续的,也可以是不连续的,这就意味着在每个元素的存储内容中必须要由下一个元素的位置信息,因为这还是一个线性表,需要有序,有限。这样就能够利用大量碎片空间来存储信息。

在链式储存中,每一个数据元素由两个数据项组成,一个储存数据元素本身的信息,叫做数据域,一个储存着下一个数据元素的位置信息,叫做指针域指针域中存储的信息叫做指针或者。这两部分组成数据元素的存储映像,成为结点(Node)
头指针:链表中第一个结点的存储位置为头指针。
头节点:为了便于操作,在单链表的第一个结点之前附设一个结点,成为头结点。头结点的数据域可以不存储信息,头结点的指针域指向第一个结点的位置。

头指针与头结点的异同

单链表的读取

算法思路

Java实现

public class Model {

    private Object o;
    private Model m;

    Model(Object o, Model m) {
        super();
        this.o = o;
        this.m = m;
    }

    public Object getO() {
        return o;
    }

    public void setO(Object o) {
        this.o = o;
    }

    public Model getM() {
        return m;
    }

    public void setM(Model m) {
        this.m = m;
    }
}
package com.company;

public class SingleLinkedList {

    private Model start;
    private Model current;
    private int size;

    //获取一个空的单链表
    private SingleLinkedList() {
        start = current = new Model(null, null);
        size = 0;
    }

    //判断该单链表是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //获取该单链表的大小
    public int getSize() {
        return size;
    }

    //读取单链表
    public Model getModel(int i) {
        current = start.getM();
        int j = 1;
        while (!this.isEmpty() && j<i) {
            current = current.getM();
            j++;
        }
        return current;
    }

    //在单链表的最后添加
    public void addToLast(Object o) {
        //因为是在单链表的最后添加的,所以其指针域为null
        Model newModel = new Model(o, null);
        //到达单链表的最后
        while (current.getM() != null) {
            current = current.getM();
        }
        current.setM(newModel);
        size++;
    }

    //在单链表的开始添加
    public void addToStart(Object o) {
        Model startModel = start.getM();
        Model newModel = new Model(o, startModel);
        start.setM(newModel);
        size++;
    }

    //在单链表的中间某处添加
    public void add(int i, Object o) {
        if (i == 1) {
            addToStart(o);
        }
        //获取要被往后推的model
        Model after = getModel(i);
        //获取要被添加处之前的model
        Model before = getModel(i-1);
        //创建新的model,并与后面的model连接起来
        Model newModel = new Model(o, after);
        //与之前的model连接起来
        before.setM(newModel);
        size++;
    }

    public void deleteFirst() {
        Model first = start.getM();
        Model next = first.getM();
        start.setM(next);
    }

    //在链表中某处删除
    public void delete(int i) {
        if (getSize() == 0) {
            System.out.println("链表为空不能删除");
            return;
        }
        if (i == 1) {
            deleteFirst();
        } else {
            //获取要被删除的model
            Model deletedModel = getModel(i);
            //获取被删除model前一位置的model
            Model before = getModel(i - 1);
            //获取被删除model之后的model
            Model after = deletedModel.getM();
            before.setM(after);
        }
    }

    public void printAll() {
        if (isEmpty()) {
            System.out.println("链表为空");
        } else {
            for (current = start.getM(); current != null; current = current.getM()) {
                System.out.print("[" + current.getO().toString() + "]" + " ");
            }
        }
    }

    public static void main(java.lang.String[] args) {
        SingleLinkedList linkedList = new SingleLinkedList();
        for (int i = 1; i < 8; i++) {
            linkedList.addToLast(i);
        }
        linkedList.printAll();
        System.out.println("初始化完成");
        java.lang.String result = linkedList.getModel(1).getO().toString();
        System.out.println(result);
        linkedList.add(3, 12);
        linkedList.printAll();
        linkedList.delete(4);
        System.out.println("删除线性表中第四位");
        linkedList.printAll();
    }
}

单链表结构与顺序存储结构的优缺点

结论

循环链表

定义:将单链表中终端终点的指针端由空指针改为指向头结点,单链表就会变成一个头尾相接的循环链表(circular linked list)
头结点不是循环链表的必须组成成分,如果没有头结点,那链表中终端终点的指针变成头指针就行了。

循环链表与单链表的主要区别在于循环的判断条件上,原来是判断结点的指针域是否为null,现在是结点的指针域是否指向头结点或者第一个结点。

双向链表

定义:在单链表的每一个结点中,都保存着指向上一个结点的指针域。

上一篇 下一篇

猜你喜欢

热点阅读