数据结构之线性表(C++)---数组描述

数据结构之线性表—数组描述


前面我写了几节二叉树,现在想想还是回过头来吧线性表写了

概述

C++里提供了强大的STL(标准模板库),而且很多大神和相关书籍多提倡我们使用STL,切勿盲目自己写,这样反而效率更低。但是在使用STL的同时,能够了解如何实现简单的STL是很爽的。

C++程序常用的数据描述方式是数组描述和链式描述,而线性表可以用来说明这两种方法。STL容器大致相当于线性表的数组描述方式和链式描述方式,当然STL还有很多其他的方法,这里就不介绍了。

线性表

线性表也叫作有序表,它的每一个实例都是元素的一个有序集合

数组描述

当我们在写数据结构的时候我们首先想到可能是如何创建,然后是它有什么操作。

创建 : 因为是利用数组来存储元素,用的也是数组类型

当创建好一个线性表的时候,它应该有如下操作:

  1. 向线性表添加元素
  2. 销毁一个线性表
  3. 判断线性表是否为空
  4. 确定线性表的长度
  5. 按给定的索引查找一个元素
  6. 安给定的元素查找第一个出现该元素的索引
  7. 按给定的索引插入一个元素
  8. 从左到右顺序输出线性表元素
    ….

也有人说是不是操作过多,放在同一个类里,会不会造成代码太复杂,拥挤,这里我们不考虑这些,只是单纯的实现这些操作

类arrayList的创建

class arrayList
{
public:
    arrayList(int initialCapacity = 10);
    arrayList(const arrayList<T>& theList);
    ~arrayList() { delete[] element; element = 0;}

    //ADT实现
    void add(T theElement);             // 向尾部添加元素
    bool empty() const { return listSize == 0; }        // 判断是否为空
    int size() const  {return listSize;};                   // 返回数组中元素的个数
    T& get(int theIndex) const;                         // 根据索引获取元素
    int indexof(const T& theElemet) const;      // 返回数组中第一个出现的下标
    void erase(int theIndex);                               // 删除操作
    void insert(int theIndex, T& theElemet);        // 插入操作
    void output() const;                                        // 输出操作
    bool equal(const arrayList<T>& theList) const;      // 判断两个线性表是否相等
    // 返回链表中可以放置的元素个数
    int Capacity() {
        return arrayLength;
    }
    // 倍增数组
    void changeLengthlD(T* &a, int oldLength, int newLength);

private:
    // 检查下标是否过界
    bool CheckIndex(int theIndex)
    {
        if(theIndex <0 || theIndex > arrayLength)
            return false;
        return true;
    }   

    T* element;     // 存储一元数组的容器
    int arrayLength; // 一维数组的容量
    int listSize;   // 线性表的元素个数

};

注:由于这里用到了模板类所以特意提醒下
《C++编程思想》里说道,模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。

类的具体实现

template <typename T> 
arrayList<T>::arrayList(int initialCapacity)
{
    if(initialCapacity < 1)
        // throw "The initialCapacity must be > 0";
        initialCapacity = 10; // default 10

    arrayLength = initialCapacity;
    element = new T[initialCapacity];
    listSize = 0;
}

template <typename T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{
    arrayLength = theList.arrayLength;
    listSize = theList.listSize;

    element = new T[arrayLength];

    for(int i = 0 ; i < listSize; i++)
        element[i] = theList[i];
}

template <typename T>
void arrayList<T>::add(T theElement)
{
    if(listSize < arrayLength)
    {
        element[listSize] = theElement;
        listSize++;
    }
    else
    {
        changeLengthlD(element, arrayLength, 2*arrayLength);
        element[listSize] = theElement;
        listSize++;
    }
}


template <typename T>
T& arrayList<T>::get(int theIndex) const
{
    if(theIndex < 0 || theIndex > listSize)
    {
        return element[-1];
    }

    return element[theIndex];
}

template <typename T>
int arrayList<T>::indexof(const T& theElemet) const
{
    for(int i = 0; i < listSize; i++)
    {
        if(theElemet == element[i])
            return i;
    }

    return -1;
}


template <typename T>
void arrayList<T>::erase(int theIndex)
{
    if(theIndex < 0 || theIndex > listSize)
    {
        return ;
    }

    copy(element + theIndex + 1, element + listSize, element + theIndex);
    listSize--;
}

template <typename T>
void arrayList<T>::insert(int theIndex, T& theElemet)
{
    if(theIndex < 0 || theIndex > listSize)
    {
        return;
    }

    if(listSize == arrayLength)
    {
        int newLength = 2*arrayLength;
        changeLengthlD(element, arrayLength, newLength);
    }

    copy(element + theIndex, element + listSize, element + theIndex + 1);
    element[theIndex] = theElemet;
    listSize++;
}

template <typename T>
void arrayList<T>::output() const
{
    for(int i = 0; i < listSize; i++)
        cout << element[i] << ' ';
    cout << endl;
}


template <typename T>
void arrayList<T>::changeLengthlD(T* &a, int oldLength, int newLength)
{
    T* temp = new T[oldLength];
    for(int i = 0; i < listSize; i++)
    {
        temp[i] = a[i];
    }

    delete[] a;
    a = new T[newLength];
    arrayLength = newLength;
    for(int i = 0; i < listSize; i++)
    {
        a[i] = temp[i];
    }
}

template <typename T>
bool arrayList<T>::equal(const arrayList<T>& theList) const
{
    if(listSize != theList.listSize)
        return false;
    if(arrayLength != theList.arrayLength)
        return false;

    bool equal = true;

    for(int i = 0; i < listSize; i++)
    {
        if(element[i] != theList.element[i])
        {
            equal = false;
            break;
        }
    }
    return equal;
}

实现的代码都是很简单的,这里主要讲下本文插入元素和删除元素中的思路,在代码中我们用到了copy函数,这里假设数组元素为: 1, 2, 3, 4, 5 ,6, 7, 8

当我们在元素’4’的后面插入一个’0’,’4’之后的每一个元素都要顺序往后面移一位,copy()在这时就简化了代码量。
( 其中copy的定义OutputIt copy( InputIt first, InputIt last, OutputIt d_first ))

Vector简单描述

vector是STL提供的一个基于数组的类,他不仅包含了上述介绍的全部方法,还增加了很多其它的方法,有兴趣的可以自己去看文档。例如:它没有get,而与之相应的是operator[](当然还有其他的), 。

数组描述的优缺点

数组描述的优点在于令人满意的时间性能

数组描述的缺点是空间利用率低,如果造成内存不足,可能是动态数组空间分配失败或者数组长度倍增失败所致。


友情链接: 数据结构之线性表—数组描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值