顺序表——基本概念、顺序表类实现、基本操作

顺序表


线性表的顺序存储结构

1、数组是实现顺序存储结构的基础。

特点:地址连续确定,容量固定,随机存取T(n) = O(1)

一维数组占用一块内存空间,数组的存储单元个数成为数组容量,也成为数字长度。每个存储单元的地址是连续的,即每个元素连续存储。(反映了顺序表的逻辑结构)。

存取任何一个元素的时间复杂度是O(1)的数据结构成为随机存储结构,数组也是随机存储结构。

2、顺序表

线性表的顺序存储结构成为顺序表。数据元素在内存的物理存储次序反映了线性表数据元素之间的逻辑次序。

当顺序表使用的数组容量不够时,解决数据溢出的办法是,申请另一个更大容量的数组并进行数组元素赋值。(延伸:浅拷贝和深拷贝)


顺序表——基本概念、顺序表类实现、基本操作_第1张图片

顺序表类声明

package SeqList;

public class SeqList extends Object
{
    protected Object[] element;                            //对象数组,保护成员
    protected int n;                                       //顺序表元素个数(长度)

    //1. 构造、存取
    public SeqList(int length)                             //构造容量为length的空表
    {
        this.element = new Object[length];                 //申请数组的存储空间,元素为null。
                //若length<0,Java抛出负数组长度异常 java.lang.NegativeArraySizeException
        this.n = 0;
    }
    public SeqList()                                       //创建默认容量的空表,构造方法重载
    {
        this(64);                                          //调用本类已声明的指定参数列表的构造方法
    }
    
    public SeqList(T[] values)                             //构造顺序表,由values数组提供元素,忽略其中空对象
    {
        this(values.length);                               //创建容量为values.length的空表
                   //若values==null,用空对象调用方法,Java抛出空对象异常NullPointerException
        for (int i=0; i=0 && i=0 && i0)
            str += this.element[0].toString();             //执行T类的toString()方法,运行时多态
        for (int i=1; i
顺序表——基本概念、顺序表类实现、基本操作_第2张图片

操作的效率分析

O(1):isEmpty(), size(), get(), set()
O(n):toString()需要遍历顺序表




顺序表插入操作

1、对要插入的数据元素进行判断,是否为空
2、插入的数据元素的位置,是否越界
这里有两种处理:①采取容错措施,若 i<0,则插入x在最前面;若 i>n,则插入x在最后面    ②不处理,返回错误信息
3、是否溢出,若溢出,申请更大容量的数组并复制全部数组元素
4、移动数据,空出位置(主要的时间花费)
5、插入数据元素

插入过程图解:
顺序表——基本概念、顺序表类实现、基本操作_第3张图片顺序表——基本概念、顺序表类实现、基本操作_第4张图片

//2. 顺序表的插入操作
    //插入x作为第i个元素,x!=null,返回x序号。若x==null,抛出空对象异常。O(n)
    //对序号i采取容错措施,若i<0,插入x在最前;若i>n,插入x在最后
    public int insert(int i, T x)
    {
        if (x==null)                                       //判断插入的元素是否为空
            throw new NullPointerException("x==null");     //抛出空对象异常
        if (i<0)       i=0;                                //插入位置i容错,插入在最前
        if (i>this.n)  i=this.n;                           //插入在最后
        Object[] source = this.element;                    //数组变量引用赋值,source也引用element数组
        if (this.n==element.length)                        //若数组满,则扩充顺序表的数组容量
        {
            this.element = new Object[source.length*2];    //重新申请一个容量更大的数组
            for (int j=0; j=i; j--)                    //从i开始至表尾的元素向后移动,次序从后向前
            this.element[j+1] = source[j];
        this.element[i] = x;
        this.n++;
        return i;                                          //返回x序号
    }
    public int insert(T x)                                 //顺序表尾插入x元素,返回x序号。成员方法重载
    {
        return this.insert(this.n, x);                     //插入操作中,this.n加1
    }


对顺序表进行插入操作时,算法所花费的时间主要用于移动元素,插入一个元素平均需要移动顺序表元素总量的一半,时间复杂度是O(n)。




顺序表删除操作

顺序表删除元素ai,必须将ai之后的ai+1、ai+2、...、an-1元素依次向前移动

1、先将ai后的数据依次向前移动

2、将最后一个数据元素释放空间

顺序表——基本概念、顺序表类实现、基本操作_第5张图片

//3. 顺序表的删除操作
    public T remove(int i)          //删除第i个元素,0≤i0 && i>=0 && i

删除元素操作所花费的 时间主要用于移动元素。删除一个元素平均移动n/2个元素,时间复杂度为O(n)。



顺序表查找操作

顺序查找,在查找过程中,需要将key与顺序表元素逐个比较是否相等。
//4. 顺序查找
//顺序查找首次出现的与key相等元素,返回元素序号i,0≤i
 public boolean contains(T key)                         //判断是否包含关键字为key元素
    {
        return this.search(key)!=-1;
    }

顺序查找的次数取决于元素位置,T(n)=O(n)



顺序表的浅拷贝与深拷贝

浅拷贝:一个类的拷贝构造方法通常实现为成员变量逐域赋值,即将当前对象的各成员变量赋值为实际参数对应的各成员变量值,称为浅拷贝。
public SeqList(SeqList list)                      //浅拷贝构造方法,复制对象
    {
        this.n = list.n;                                   //int整数赋值,复制了整数值
        this.element = list.element;                       //数组引用赋值,两个变量共用一个数组,错误
    }
数组是引用数据类型,数组引用赋值传递了数组的引用信息,没有申请新的存储空间,this和list引用同一个数组,修改、插入、删除等操作时会同时结果相互影响

顺序表——基本概念、顺序表类实现、基本操作_第6张图片
e.g:  
 SeqList lista = new SeqList({"A","B","C","D","E"});
         SeqList listb = new SeqList(lista);       
        lista.remove(0);
lista = SeqList(B,C,D,E),   listb =
Exception in thread "main" java.lang.NullPointerException
在lista中进行remove(0)操作是对数组进行删除,实际上也删除了listb的元素,但是listb的结构没有改变。


深拷贝:不仅要复制对象的所有基本类型成员变量值,还要为引用类型变量申请存储空间,并复制其中所有元素。
public SeqList(SeqList list)              //拷贝构造方法,深拷贝,复制list
{                                      
    this.n = list.n; 
    this.element = new Object[list.element.length];    //申请一个数组
    for (int i=0; i
这里的深拷贝申请了新的数组空间,进行插入和删除操作不会影响对方对象。
但是由于对象赋值是引用赋值,深拷贝没有复制元素对象,修改其中的实例,仍会影响对方。 如下图
顺序表——基本概念、顺序表类实现、基本操作_第7张图片
∴深拷贝应该 复制每个引用类型成员变量所引用的数组或对象,直至该对象可达的所有对象。如下图所示。

顺序表——基本概念、顺序表类实现、基本操作_第8张图片

顺序表比较相等

两个线性表相等是指,它们各对应元素相等并且长度相等。
SeqList类声明覆盖equals(Object)方法
//6. 顺序表比较相等
    public boolean equals(Object obj)                      //比较两个顺序表是否相等。覆盖。O(n)
    {
        if (this==obj)                                     //若this和obj引用同一个顺序表实例,则相等
            return true;
        if (obj instanceof SeqList)                     //若obj引用顺序表实例。SeqList是所有SeqList的父类
        {
            SeqList list = (SeqList)obj;             //声明list也引用obj引用的实例
            if (this.n==list.n)                            //比较两者长度是否相等
            {
                for (int i=0; i

时间复杂度是O(n)。

你可能感兴趣的:(数据结构)