C++数据结构之:数组Array

摘要:

  it人员无论是使用哪种高级语言开发东东,想要更高效有层次的开发程序的话都躲不开三件套:数据结构,算法和设计模式。数据结构是相互之间存在一种或多种特定关系的数据元素的集合,即带“结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系,分为逻辑结构和存储结构。
  此系列专注讲解数据结构数组、链表、队列、栈、树、图,通过介绍概念以及提及一些可能适用的场景,并以C++代码简易实现,多方面认识数据结构,最后为避免重复造轮子会浅提对应的STL容器。本文介绍的是数组Array。

(开发环境:VScode,C++17)

关键词C++数据结构数组Array

声明:本文作者原创,转载请附上文章出处与本文链接。

正文:

介绍:

  数组是最简单、使用最频繁的一种数据结构,它是一种线性表数据结构,除了第一个元素以外,集合中的每个数据元素均只有一个前驱,除了最后一个元素以外,集合中每个元素均只有一个后继,用一组连续的内存空间,来存储一组具有相同类型的数据。

在这里插入图片描述

特性:
  • 静态大小:在创建数组时,需要指定数组的大小,一旦创建,数组的大小就固定不变,不能动态修改。这意味着在数组的生命周期内,元素的数量是固定的。
  • 连续存储:数组中的所有元素都存储在连续的内存位置上。这种连续性使得数组具有随机访问的特性,即可以通过索引直接访问数组中的任意元素,而不需要遍历整个数组。
  • 相同类型:数组中的所有元素都必须是同一类型。这确保了数组在内存中的一致性和可管理性。
应用:
  • 数值计算:在科学计算和工程应用中,数组经常用于存储和处理大量的数值数据。
  • 图像处理:在图像处理中,像素值通常存储在一个二维数组中。
  • 数据结构和算法:许多其他数据结构(如栈、队列、列表等)都是基于数组实现的。
  • 数据库:在数据库中,索引通常使用数组来实现,以加快数据检索的速度。
代码实现:
#carray.h
#ifndef CARRAY_H
#define CARRAY_H
#include<iostream>

#define MAX_SIZE 256
using namespace std;

template <class T>
class CArray
{
public:
    CArray();                                   // 构造函数
    CArray(unsigned int, unsigned int = 0);     // 数组构造函数
    ~CArray();                                  // 析构函数

    CArray(CArray const&);                      // 拷贝构造函数
    CArray& operator = (CArray const&);         // 重载等号操作符,用于一个数组给另外一个数组赋值

    T const& operator [] (unsigned int) const;  // 重载中括号操作符,返回一个T数值常量,返回值不能被改变,在函数末尾加const表示this指针指向const
    T& operator [] (unsigned int);              // 重载中括号操作符,返回一个T数值常量,其返回值可以被改变

    void setBase(unsigned int);                 // 设置成员变量base的数值
    void setLength(unsigned int);               // 设置成员变量length的数值

    T* data() const;                            // 返回数组数据的指针m_pData
    unsigned int getBase() const;               // 返回成员base
    unsigned int getLength() const;             // 返回成员length
    void print();                               // 打印数组内容以及各属性

private:
    T *m_pData;             // 指向数组数据的指针
    unsigned int base;      // base为数组的起始下标
    unsigned int length;    // length为数组的长度
};

// 构造函数不含变量,只需要给对象的变量一个初始值
template <class T>
CArray<T>::CArray() : m_pData(new T[MAX_SIZE]),base(0),length(0)
{
}

// 初始化数组,n为数组的长度
template <class T>
CArray<T>::CArray(unsigned int n, unsigned int m) : m_pData(new T[n]),base(m),length(n)
{
}

// 析构函数,删除数组所占用的内存空间
template <class T>
CArray<T>::~CArray()
{
    delete[] m_pData;
    m_pData = nullptr;
}

// 拷贝构造函数,将一个数组从赋值到另外一个数组
template <class T>
CArray<T>::CArray(CArray<T> const& CArray) :
  m_pData(new T[CArray.length]),
  base(CArray.base),
  length(CArray.length)
{
    for (unsigned int i = 0; i < length; ++i)
        m_pData[i] = CArray.m_pData[i];
}

// 重载赋值操作符
template <class T>
CArray<T>& CArray<T>::operator = (CArray<T> const& CArray)
{
    if (this != &CArray){
        delete[] m_pData;
        base = CArray.base;
        length = CArray.length;
        m_pData = new T[length];
        for (unsigned int i = 0; i < length; ++i)
        m_pData[i] = CArray.m_pData[i];
    }
    return this;
}

// 这两个都为取下表操作符的重载,区别为第一个返回值不可以作为左值,第二个返回值可以作为左值
template <class T>
T const& CArray<T>::operator[] (unsigned int position) const
{
    unsigned int const offset = position - base;
    if (offset >= length)
        throw out_of_range("invalid position");
    return m_pData[offset];
}
template <class T>
T& CArray<T>::operator[] (unsigned int position)
{
    unsigned int const offset = position - base;
    if (offset >= length)
        throw out_of_range("invalid position");
    return m_pData[offset];
}

template <class T>
void CArray<T>::setBase(unsigned int newBase)
{
    base = newBase;
}

template <class T>
void CArray<T>::setLength(unsigned int newLength)
{
    T* const newm_pData = new T[newLength];
    unsigned int const min = length < newLength ? length : newLength;
    for (unsigned int i = 0; i < min; ++i)
        newm_pData[i] = m_pData[i];
    delete[] m_pData;
    m_pData = newm_pData;
    length = newLength;
}

template <class T>
T* CArray<T>::data() const
{
    return m_pData;
}

template <class T>
unsigned int CArray<T>::getBase() const
{
    return base;
}

template <class T>
unsigned int CArray<T>::getLength() const
{
    return length;
}

template <class T>
void CArray<T>::print()
{
    cout << "m_pData:";
    for (unsigned int i = base; i < length; i++){
        cout << m_pData[i] << " ";
    }
    cout << endl;
    cout << "length:" << length << endl;
    cout << "base:" << base << endl;
}

#endif // !CARRAY_H
#carray.cpp
#include "carray.h"
using namespace std;

int main(int argc, char** argv)
{
  CArray<int> CArray0 = CArray<int>();
  CArray0.print();
  cout << endl;

  CArray<int> CArray1 = CArray<int>(10);
  CArray1.print();
  cout << endl;

  CArray<int> CArray2(CArray1);
  CArray2.print();
  cout << endl;
  CArray2.~CArray();

  CArray<int> CArray3(10);
  for (unsigned int i = CArray1.getBase(); i < CArray1.getLength() - CArray1.getBase(); i++){
    CArray3.data()[i] = i;
  }
  CArray3.print();
  cout << endl;

  CArray3.setBase(2);
  CArray3.print();
  cout << endl;

  CArray3.setLength(7);
  CArray3.print();
  return 0;
}

在这里插入图片描述

对应STL:
  • string

    string类本不是STL的容器,但是它与STL容器有着很多相似的操作,C++中的string类相当于是字符数组,但是其更方便于我们的操作,而且不需要在输入之前初始化字符数组的容量,节省空间。

  • array

    array即数组,其大小固定,所有的元素严格按照内存地址线性排列,array 并不维护元素之外的任何多余数据,甚至也不会维护一个size这样的变量,这保证了它在存储性能上和C++语法中的数组符号[]无异。

  • vector

    vector 就是能够动态调整大小的 array。和 array 一样,vector 使用连续内存空间来保存元素,这意味着其元素可以用普通指针的++和–操作来访问;不同于 array 的是,其存储空间可以自动调整。

  • bitset

    bitset容器相当于是01数组,其方便之处是可以直接按位(下标)进行位运算,但是要注意下标从小到大依次存低位到高位,是逆序的。

推荐阅读

C/C++专栏:
https://blog.csdn.net/weixin_45068267/category_12268204.html
(后续会更新更多数据结构以及对应的STL容器使用)

(画饼ing:)

C++数据结构之:链List:

C++数据结构之:队Queue:

C++数据结构之:栈Stack:

C++数据结构之:堆Heap:

C++数据结构之:树Tree:

C++数据结构之:图Graph:

C++ STL容器:序列式容器-数组string,vector,array,bitset:

  • 35
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用归并排序的思想来合并两个升序数组。具体步骤如下: 1. 定义一个新的数组,长度为两个原数组长度之和。 2. 分别定义两个指针,分别指向两个原数组的第一个元素。 3. 比较两个指针所指向的元素,将较小的元素放入新数组中,并将指针向后移动一位。 4. 重复步骤3,直到其中一个指针到达原数组末尾。 5. 将另一个原数组中剩余的元素依次放入新数组中。 6. 输出新数组即为合并后的升序数组。 例如,对于数组array1={3,6,13,35,54}和数组array2={14,19,26,32},按照上述步骤合并后的新数组array={3,6,13,14,19,26,32,35,54}。 ### 回答2: 题目描述: 本题要求将两个升序数组合并成一个升序数组,并输出。 解题思路: 对于这个问题,我们可以采用“双指针法”进行解答。具体来说,我们可以使用两个指针(分别指向两个数组),将两个指针所指向的元素进行比较,较小的元素加入新的数组,并将对应的指针往后移动一位。如果其中一个指针已经到达了其所在的数组的末尾,那么只需要将另一个数组的剩余元素加入新的数组即可。 举个例子,假设我们有两个升序数组array1={3,6,13,35,54} array2={14,19,26,32} 我们可以使用两个指针 i j 分别指向数组 array1 和数组 array2 的第一个元素。然后我们进行如下操作: 1.比较 array1[i] 和 array2[j] 的大小。如果 array1[i] 小于 array2[j],那么就将 array1[i] 加入新的数组,并将指针 i 向后移动一位; 2.如果 array1[i] 大于等于 array2[j],那么就将 array2[j] 加入新的数组,并将指针 j 向后移动一位; 3.如果其中一个指针已经到达了其所在的数组的末尾,那么只需要将另一个数组的剩余元素加入新的数组即可; 4.重复以上步骤,直到两个数组的元素全部加入新的数组为止。 最后,我们就可以得到合并后的升序数组 array={3,6,13,14,19,26,32,35,54}。 算法实现: 算法实现分为两种方式,一种是采用递归的方式进行合并,另一种则是使用非递归的方式进行合并。 1.非递归合并算法: C++ 代码示例: vector<int> merge(vector<int>& arr1, vector<int>& arr2) { int n = arr1.size(), m = arr2.size(); vector<int> ans(n + m); int i = 0, j = 0, k = 0; while (i < n && j < m) { if (arr1[i] < arr2[j]) ans[k++] = arr1[i++]; else ans[k++] = arr2[j++]; } while (i < n) ans[k++] = arr1[i++]; while (j < m) ans[k++] = arr2[j++]; return ans; } 将两个升序数组合并成一个新的升序数组的实现方式非常简单。我们可以使用三个变量表示当前遍历 array1 和 array2 的下标,以及合并后的数组的下标 k。我们不断比较 array1[i] 和 array2[j] 的大小,将较小的元素加入新的数组,并将对应的指针 i 或 j 向后移动一位。如果其中一个指针已经到达了其所在的数组的末尾,那么只需要将另一个数组的剩余元素加入新的数组即可。最后,我们就可以得到合并后的升序数组。 时间复杂度:O(n+m),空间复杂度:O(n+m)。 2.递归合并算法: C++ 代码示例: vector<int> merge(vector<int>& arr1, vector<int>& arr2) { if (arr1.empty()) return arr2; if (arr2.empty()) return arr1; if (arr1[0] < arr2[0]) { vector<int> sub = merge(vector<int>(arr1.begin()+1, arr1.end()), arr2); sub.insert(sub.begin(), arr1[0]); return sub; } else { vector<int> sub = merge(arr1, vector<int>(arr2.begin()+1, arr2.end())); sub.insert(sub.begin(), arr2[0]); return sub; } } 递归合并也是一种非常优秀的解法。我们可以使用递归的方式将问题分解成若干个子问题。具体来说,我们可以将 array1 和 array2 分别拆分成长度更短的子数组,然后将这些子数组递归地合并成完整的升序数组。 时间复杂度:O(n+m),空间复杂度:O(n+m)。 总结: 将两个升序数组合并成一个升序数组的问题在数据结构中非常常见,解题思路和算法实现比较简单。我们可以采用“双指针法”进行迭代,也可以采用递归的方式进行实现。无论是哪种算法,时间复杂度均为 O(n+m)。因此,对于大多数数据规模来说,该问题的解法都是非常高效和可行的。 ### 回答3: 要将两个已知的升序数组合并为一个升序数组,需要用到归并排序的思想。归并排序是一个基于分治思想的排序算法,其核心思想是将一个大问题分成多个小问题,分别解决后再进行合并。 首先,我们可以定义三个指针,分别指向两个原始数组的开头和合并后的新数组的开头。接着,比较这两个指针所指向的元素的大小,将较小的元素放入新数组中,并将指向该元素的指针后移一位。重复上述过程,直到一个原始数组中的所有元素均已放入新数组中。此时,将另一个原始数组中的剩余元素均放入新数组中即可。 具体操作过程如下: 1. 定义三个指针p、q、r,分别指向两个原始数组和合并后的新数组的开头。 2. 比较p和q所指向的元素的大小,将较小的元素放入新数组array的r位置,并将p或q指针后移一位。 3. 重复步骤2,直到p或q指针指向的原始数组中的所有元素均已放入新数组array中。 4. 将原始数组中剩余元素均放入新数组中即可。 代码如下: ```python def merge(array1, array2): # 定义新数组 array = [] # 定义指针 p = 0 q = 0 r = 0 # while循环将较小的元素放入新数组中 while p < len(array1) and q < len(array2): if array1[p] <= array2[q]: array.append(array1[p]) p += 1 else: array.append(array2[q]) q += 1 r += 1 # 将剩余元素放入新数组 if p < len(array1): array += array1[p:] if q < len(array2): array += array2[q:] return array ``` 测试代码如下: ```python array1 = [3, 6, 13, 35, 54] array2 = [14, 19, 26, 32] print(merge(array1, array2)) ``` 输出结果为: ``` [3, 6, 13, 14, 19, 26, 32, 35, 54] ``` 因此,我们可以利用归并排序的思想,将两个已知的升序数组合并为一个升序数组并输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值