SeqList

本文深入探讨了线性表的顺序存储结构,包括定义、设计思路、关键操作的实现如元素获取、插入和删除,以及代码实现和效率分析。通过具体示例,读者将理解顺序存储结构的优缺点。

1 线性表的顺序存储结构

1.1 顺序存储的定义

线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表中的数据元素。

在这里插入图片描述

1.2 设计思路

可以用一维数组实现顺序存储结构。

  • 存储空间:T* m_array;
  • 当前长度:‘int m_length;’
template <typename T>
class SeqList : public List<T>
{
protected:
	T* m_array;
	int m_length;
	// ...
};

1.3 顺序存储结构的元素获取操作

(1)判断目标位置是否合法。
(2)将目标位置作为数据下标获取元素。

bool SeqList<T>::get(int index, T& e) const
{
	bool ret = ((0 <= index) && (index < m_length));
	
	if (ret)
	{
		e = m_array[index];
	} 

	return ret;
}

1.4 顺序存储结构的元素插入操作

(1)判断目标位置是否合法。
(2)将目标位置之后的所有元素后移一个位置。
(3)将新元素插入目标位置。
(4)线性表长度加1。

bool SeqList<T>::insert(int index, const T& e)
{
	bool ret = (0 <= index) && (index <= m_length);
	ret = ret && ((m_length + 1) <= capacity());

	if (ret)
	{
		for (int p=m_length-1; p>=index; p--)
		{
			m_array[p+1] = m_array[p];
		}
		
		m_array[index] = e;
		m_length++;
	}
}

1.5 顺序存储结构的元素删除操作

(1)判断目标位置是否合法。
(2)将目标位置后的所有元素前移一个位置。
(3)线性表长度减1。

bool SeqList<T>::remove(int index)
{
	bool ret = ((0 <= index) && (index < m_length));

	if (ret)
	{
		for (int p=index; i<m_length-1; i++)
		{
			m_array[p] = m_array[p+1];
		}
		
		m_length--;
	}

	return ret;
}

2 继承关系图和接口实现

SeqList实现要点

  • 抽象类模板,存储空间的位置和大小由子类完成
  • 实现顺序存储结构线性表的关键操作(增,删,查等)
  • 提供数组操作符,方便快速获取元素

顺序存储结构线性表继承关系图
在这里插入图片描述

SeqList接口实现:

template < typename T >
class SeqList : public List<T>
{
protected:
    T* m_array;     // 顺序存储空间
    int m_length;   // 当前线性表长度

public:
    bool insert(int index, const T& e);	// O(n)
    bool insert(const T& e);			// O(1)
    bool remove(int index);				// O(n)
    bool set(int index, const T& e);	// O(1)
    bool get(int index, T& e) const;	// O(1)
    int find(const T& e) const;			// O(n)
    int length() const;					// O(1)
    void clear();						// O(1)

    // 顺序存储线性表的数组访问方式
    T& operator[](int index);			// O(1)
    T operator[](int index) const;		// O(1)
   
    // 顺序存储空间的容量
    virtual int capacity() const = 0;
};

3 代码实现

SeqList.h

#ifndef SEQLIST_H
#define SEQLIST_H

#include "Exception.h"

namespace  LemonLib
{

template < typename T >
class SeqList : public List<T>
{
protected:
    T* m_array;     // 顺序存储空间
    int m_length;   // 当前线性表长度

public:
    bool insert(int index, const T& e)
    {
        bool ret = ((0 <= index) && (index <= m_length));
        ret = ret && (m_length < capacity());

        if (ret)
        {
            for (int p=m_length-1; p>=index; p--)
            {
                m_array[p+1] = m_array[p];
            }

            m_array[index] = e;
            m_length++;
        }

        return ret;
    }

	bool insert(const T& e)
    {
        return insert(m_length, e);
    }
  
    bool remove(int index)
    {
        bool ret = ((0 <= index) && (index < m_length));

        if (ret)
        {
            for (int p=index; p<m_length-1; p++)
            {
                m_array[p] = m_array[p+1];
            }

            m_length--;
        }

        return ret;
    }

    bool set(int index, const T& e)
    {
        bool ret = ((0 <= index) && (index < m_length));

        if (ret)
        {
            m_array[index] = e;
        }

        return ret;
    }

    bool get(int index, T& e) const
    {
        bool ret = ((0 <= index) && (index < m_length));

        if (ret)
        {
            e = m_array[index];
        }

        return ret;
    }
	
	int find(const T& e) const
    {
        int ret = -1;

        for (int i=0; i<m_length; i++)
        {
            if (m_array[i] == e)
            {
                ret = i;
                break;
            }
        }

        return ret;
    }

    int length() const
    {
        return m_length;
    }

    void clear()
    {
        m_length = 0;
    }

    // 顺序存储线性表的数组访问方式
    T& operator[](int index)
    {
        bool ret = ((0 <= index) && (index < m_length));

        if (ret)
        {
            return m_array[index];
        }
        else
        {
            THROW_EXCEPTION(IndexOutOfBoundsException, "Param index is invalid...");
        }
    }

    T operator[](int index) const
    {
        return (const_cast<SeqList<T>&>(*this))[index];
    }


    // 顺序存储空间的容量
    virtual int capacity() const = 0;
};
}

#endif // SEQLIST_H


4 效率分析

在这里插入图片描述


5 思考

问题: 长度相同的两个SeqList,插入和删除操作的平均耗时是否相同?

元素的类型不同将导致插入和删除操作的平均耗时不同,比如一个数据类型为原生类型int,另一个数据类型为string,很明显两者的插入和删除操作的平均耗时有很大区别。


6 注意

  • 顺序存储线性表的插入和删除操作存在重大效率隐患(跟具体元素的类型有关)。
  • 线性表作为容器类,应当避免拷贝构造和拷贝赋值。
  • 顺序线性表可能被当成数组误用。
  • 工程开发中可以考虑使用数组类代替原生数组使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值