数据结构之线性表-顺序存储

本人文笔较差,语文从来不及格,基础不好,写此类文章仅供自己学习,理解队列及其他知识,高手大神请略过。参考书籍 《数据结构与算法分析-Java语言描述》

1.1 线性表简介

线性表是0个或多个元素的有限序列。即元素之间有顺序且有限。假设表中有元素A1,A2,A3,....,AN,若存在1<i<N,则 A是 Ai-1的直接后继,Ai-1 是Ai的直接前驱。作为线性表,必须满足A1没有前驱,AN没有后继(有限性)。N是线性表的长度。当N=0时,即表中没有任何元素也即空表。

1.2 线性表的顺序存储

在内存中用一段地址连续的存储单元依次存储线性表的数据元素。如每天上下班挤地铁排成一条长队,有时候几个要好的同事接连的站在一起。其他人就占据不了这几个位置了。转换成计算机语言就是在内存中找了一块地儿,把这段内存空间给占了,然后把相同数据类型的元素(暂且理解成通用Object类型)放在这块儿地儿。用数组实现,第一个人就存储在下标是0的那个位置,线性表的长度就是人数。此时在等地铁的时候又遇到一个同事,我们让他(她)跟我们一起,于是线性表的长度就加了1,但是事先已经定义了数组的长度,即内存中只占了我们几个人空间,这时有个同事看向左侧一排发现没人,就带着我们过去排队,然后我们都能排在一起了。即重新定义了数组,内存中多占了块儿地儿。另一种情况是,突然有个同事内急去上厕所,我们就多余占了一个位置。即线性表的长度是不断变化的,而数组要预先占好足够多的空间。所以线性表的长度总是小于或等于数组的长度。

存储器中的每个存储单元都有自己的编号,当在没有重写toString方法时,打印一个实例得到的结果,即内存地址。确定任何一个元素位置了,就可以通过编号计算其他任意元素的位置了。即它获取元素的时间复杂度是O(1)。

假设之前那个同事占据了好几十个人的空间,我们只有m个人现在考虑前面的插入问题即突然又来了一位同事,若插在最后一个同事位置后面(这里假设它站过来需要t时间,t是个固定常数),这时其他同事都不用动,时间复杂度即是常数O(1),若插在中间的某个位置k(0<k<m),则k之前的同事也不用动,但是k之后的m-k个同事每一个都要向后挪一位,用时(m-k)*t的时间,最费时情况的是他(她)若插到最前面的那个同事前面,我们每一个人都将向后挪动一个位置将耗时m*t,所以平均耗时m*t/2, 平均时间复杂度即O(N),N是规模,这里是同事的人数m。当然移除元素即每个元素向前挪,和插入一样,平均时间复杂度都是O(N)。

至此,就明白了,基本的线性表顺序存储(其实其他结构的存储也是)就包括插入,删除,获取元素及获取表的长度的几个操作。Java代码的简单实现:

/**
 * Created with IntelliJ IDEA.
 * CreateUser:  blentle
 * Email: [email protected]
 * CreateTime:  2014/11/6 12:40
 * ModifyUser:  blentle
 * ModifyTime:  2014/11/6 12:40
 * Class Description:
 * To change this template use File | Settings | File Templates.
 */
public class SequenceList<T> {
    //不指定存储空间时的默认存储,操作时越界暂时将抛出异常
    private static final int DEFAULT_CAPACITY = 10;
    //线性表的最大长度(数组的长度)
    private int capacity;
    //线性表元素的个数
    private int size;
    //存储线性表元素的数组
    private Object[] elementData;

    /**
     * 使用默认的最大存储空间,超过最大存储空间将抛出异常
     */
    public SequenceList() {
        this(DEFAULT_CAPACITY);
    }

    /**
     *
     * @param initialCapacity 最大存储空间初始化
     */
    public SequenceList(int initialCapacity) {
        this.capacity = initialCapacity;
        this.elementData = new Object[capacity];
    }

    /**
     *
     * @return 线性表的长度
     */
    public int size() {
        return this.size;
    }

    /**
     *
     * @return 线性表是否是空表
     */
    public boolean isEmpty() {
        return this.size == 0;
    }

    /**
     * 获取元素
     * @param index
     * @return T
     */
    public T get(int index) {
        //检查序号是否越界,注意inde是从0开始
        if(index >= size) {
            throw new IndexOutOfBoundsException("index is :"+ index + "but size is:" + this.size);
        }
        return elementData(index);
    }

    public boolean add(int index,T element) {
        //检查序号是否越界,注意inde是从0开始,最大值是size-1
        if(index > size || index < 0) {
            throw new IndexOutOfBoundsException("index is :"+ index + ",but size is:" + this.size);
        }
        //若链表已满(元素个数等于数组初始化最大容量,一般ArrayList继续扩展容量,这里抛出异常)
        if(size == capacity) {
            throw new IndexOutOfBoundsException("list is full...");
        }
        if(index == size) {
            //插在表尾
            elementData[size] = element;
        } else {
            //插在其他地方,index后面的的每一个元素向后挪一位
            for(int i = size + 1 ; i > index ; i--) {
                elementData[i] = elementData[i-1];
            }
        }
        //index位置被替换成element
        elementData[index] = element;
        size++;
        return true;
    }

    /**
     * 不指定插入位置,插入表尾
     * @param t 链表元素
     * @return
     */
    public boolean add(T t) {
        return add(size,t);
    }

    /**
     * 从表中移除元素
     * @param index 元素序号
     * @return
     */
    public boolean remove(int index) {
        if(index >= size || index < 0) {
            throw new IndexOutOfBoundsException("index is :"+ index + ",but size is:" + this.size);
        }
        for(int k = index ; k < size - 1 ; k++) {
            elementData[k] = elementData[k + 1];
        }
        elementData[size - 1] = null;
        size--;
        return true;
    }

    /**
     * 清空线性表
     */
    public void clear() {
        if(size > 0) {
            for(int i = 0 ; i < size ; i ++) {
                elementData[i] = null;
            }
            size = 0;
        }
    }

    @Override
    public String toString() {
        String a = "";
        for(int i = 0 ; i < size() ; i ++) {
            a += (T)elementData[i] + " ";
        }
        return a;
    }

    /**
     * 获取元素并强制转换的封装(参考ArrayList源码)
     * @param index
     * @return
     */
    private T elementData(int index) {
        return (T) elementData[index];
    }
}

1.3 从代码可以看出线性表的特点

  • 快速地从表中获取任意位置的元素。
  • 插入和删除操作需要移动大量的元素。
  • 当表的长度变化比较大时,不太好确定存储空间的容量(数组的初始化大小)
时间: 2024-08-01 22:47:44

数据结构之线性表-顺序存储的相关文章

数据结构例程——线性表顺序存储的应用

本文是数据结构基础系列网络课程(2):线性表中第6课时线性表顺序存储的应用中所讲的例程. 例:删除元素 问题:已知长度为n的线性表A采用顺序存储结构,设计算法,删除线性表中所有值为x的数据元素. 要求:时间复杂度为O(n).空间复杂度为O(1)的算法 解法0:用基本运算实现,不满足复杂度要求 (注:本文中所需要的list.h和list.cpp见点击参照-) #include "list.h" #include <stdio.h> void delnode1(SqList *

浅谈数据结构之线性表顺序存储(一)

 首先,数据结构是由某一数据元素集合及该集合中所有数据元素之间的关系组成.具体来说,数据结构应当包含三方面的内容:(1).数据的逻辑结构:(2).数据的存储结构:(3).对数据所施加的操作.而数据的存储结构形式有两种:顺序存储与链式存储.在这里,先谈一谈线性表的顺序存储. 线性表:零个或多个数据元素的有限序列.第一,它是一个序列,也就是说,元素之间是有顺序的:第二,它是有限的,即元素个数是有限的.而线性表的顺序存储结构,说白了,就是在内存中找块地,通过占位的形式把一定的内存空间给占了,然后把相同

数据结构之线性表——顺序存储结构(php代码实现)

<?php /**  *  * 线性表:即零个或多个数据元素的有限序列.  * 线性表的数据结构:即数据元素依此存储在一段地址连续的存储单元内.在高级语言中就表现为数组.  *  * 1. DestroyList: 销毁顺序线性表  * 2. ClearList: 将线性表重置为空  * 3. ListEmpty: 判断线性表是否为空  * 4. ListLength: 返回线性表的长度  * 5. GetElem: 返回线性表中第$index个数据元素  * 6. LocateElem: 返回

数据结构之线性表之顺序存储结构(3)

1 前言 经过前两张的理论基础,我相信大家都能简单的明白了数据结构和算法一些常用的概念了,从今天开始我们开始学习数据结构中线性表,一起叩响数据结构的大门. 2 详述 线性表(List):零个或者多个数据元素的有限序列. 如果用数学语言来进行定义: (声明:由于下标不是很好弄出来,所以只能表示下面这种方式了,请见谅!) 若线性表记作(a1,...ai-1,ai,ai+1,...,an),则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素.当i

数据结构之线性表(顺序存储结构)

小学生放学都是要按顺序排队的,一个接一个,每个小学生的前后位置是固定的,这样便于迅速清点. 其实这就是一个线性表,从这件事里我们就可以找到很多关于线性表的特性,如 1.线性表是一个序列,它是有顺序的(排队) 2.第一个元素无前驱,最后一个无后继,其他每个元素都有一个前驱和后继(一个接一个) 3.元素是有限的(小学生的个数是有限的) 4.数据类型都相同(都是小学生在排队) 说明白线性表示什么,下面我们直接看线性表的实现 线性表的实现分顺序存储结构和链式存储结构 顺序存储结构: #define LI

数据结构-线性表顺序存储(c++)

数据结构-线性表顺序存储(c++) 2018-09-06 List.h  //头文件 1 #define OK 1 2 #define ERRO0R 0 3 #define TRUE 1 4 #define FALSE 0 5 #define MAXSIZE 20 //存储空间初始分配量 6 7 typedef int Status; //Status 函数结果状态码 8 typedef int ElemType; //ElemType 据具体情况而定 9 10 class SqList 11

数据结构——线性表顺序存储结构

 关于线性表 线性表是零个或者多个数据元素的集合.它主要有以下三个特征: 1:线性表的数据元素之间是有顺序的. 2:线性表中数据元素个数是有限的. 3:线性表中数据元素数据类型是相同的. 关于线性表的操作,主要有 创建线性表.销毁线性表.清空线性表.将元素插入线性表.将元素从线性表中删除.获取线性表中某个位置的元素.获取线性表的长度. 线性表主要有两种存储结构: 1:线性表的顺序存储结构,c语言中的数组及采用这种方式. 2:线性表的链式存储结构. 关于顺序存储结构 定义: 是指用一段地址连续的内

数据结构与算法-线性表顺序存储结构删除操作的实现

这一章节我们来看一下线性表顺序存储结构删除操作的简单实现 package com.ray.testobject; public class Test { private Object[] list; public Object[] getList() { return list; } /** * 初始化list * * @param num * 元素个数 */ private void iniList(int num) { list = new Object[num]; for (int i =

数据结构与算法-总结线性表顺序存储结构的优缺点

这一章节主要总结线性表顺序存储结构的优缺点. 在总结之前,我们来讨论一下线性表顺序存储结构的执行方法的时间复杂度: 存储.读取:O(1) 插入.删除:O(n) 优点: 1.无需为表中的逻辑关系增加额外的存储空间 2.可以快速存取表中对象 缺点: 1.插入和删除需要移动大量的对象 2.存储设备的碎片化 3.当线性表过大的时候,很难确定长度 版权声明:本文为博主原创文章,未经博主允许不得转载.