動態數組是全部數據結構中最簡單的一種,甚至在不少的語言中,數組自己就是能夠不定長的。由於在學習c++的時候,使用動態數組的各類操做都不是很方便(數據結構的學習最好仍是c或c++,基礎打好了其餘的語言數據結構就很簡單)。因此開始學習如何去實現一個像STL中的vector同樣的動態數組。ios
由於後面還準備寫一個有序數組,因此這裏使用一個CArray類,把數組的各類基本特性先建立好。後面須要寫什麼數組,就能夠寫它下面的子類,來完成特殊的功能。c++
對於一個數組,我以爲須要的基本功能大概三個方面: 1.在主函數中建立數組對象並初始化,這點確定是必須的。 2.數組的容量以及當前數組所含有的元素個數。 3.打印數組,較爲方便的輸出數組中的元素。 對於插入元素,由於不一樣的數組有不一樣的插入需求,因此考慮是在子類中再寫數組的插入與刪除。算法
首先建立CArray這個類,即CArray.h和CArray.cpp兩個文件。在頭文件CArray.h中,定義好基本的方法與成員變量:編程
#pragma once
class CArray {
public:
//成員函數
CArray();//構造函數,即用來初始化
~CArray();//析構函數,使用完後釋放空間
void Print();//打印數組的元素
int getCapacity();//獲得數組的容量
int getSize();//獲得數組當前的元素個數
//成員變量
int* mp_Array;//存放數組對象的指針
int m_Size;//數組當前的元素個數
int m_Capacity;//數組的容量
};
複製代碼
mp_Array是一個指針變量,指向咱們要建立數組的存儲地址。用指針來操做數組應該是很方便的,畢竟c++的標準數組其實也是一個常指針。數組
寫完頭文件,而後在CArray.cpp文件中,將頭文件聲明的函數具體功能寫出來。bash
主義在構造函數中咱們如今只須要定義初始數組當前元素個數爲0就能夠了,能夠先不用把數組的容量定義好,由於不一樣的數組有不一樣的需求,這些能夠放在它的子類去定義。數據結構
#include "CArray.h"
#include<iostream>
CArray::CArray()//構造函數初始化
{
m_Size = 0;
}
CArray::~CArray()//析構函數
{
delete[] mp_Array;
}
int CArray::getCapacity()//獲得數組的容量
{
return m_Capacity;
}
int CArray::getSize()//獲得數組當前的元素個數
{
return m_Size;
}
void CArray::Print()//打印數組全部元素
{
printf("\nprint all date : \n");
for (int i = 0; i < m_Size; i++)
{
printf("%d\n", mp_Array[i]);
//在使用打印函數的時候,必定已經建立好了數組對象
//因此這裏的mp_Array[i]是可使用的,在後面的文件中咱們會進行賦值
}
}
複製代碼
到這裏一個數組的基類就創建好了,固然對於數組還有其餘的功能能夠實現,在這裏只完成數組的基本功能。函數
對於動態數組來講,咱們須要的功能以下: 1.初始化動態數組對象。 2.插入元素,由於數組是一個連續的控件,在數組中插入效率很低,須要把插入位置後面的元素所有後移。因此這裏的插入元素只實如今尾部插入是最好的。 3.刪除元素,和插入元素同理,刪除尾部元素。 4.查找該數組裏某一個值的位置 首先建立好CDynamicArray.h和CDynamicArray.cpp文件。在頭文件CDynamicArray.h聲明咱們須要的函數。學習
#pragma once
#include "CArray.h"
class CDynamicArray ://這個類要繼承前面寫的數組基類
public CArray
{
public:
CDynamicArray();//構造函數
~CDynamicArray();//析構函數
void PushBack(int value);//在數組的末尾插入元素,裏面的參數爲要插入的數據
void Remove();//移除數組末尾的一個元素
int Find(int value, bool isPrint);//查找某一個元素,返回的是位置
//這裏的isPrint是我用來測試時添加的打印語句,在找到之後能夠打印該元素的位置
//也能夠不使用該參數
void Clear();//清空該數組全部的元素
void Sort(int start, int end, bool up);//有參數的數組排序,參數是要參與排序的起始位置和末尾位置
//第三個參數是排序是從小到大仍是從大到小
void Sort();//無參數的數組排序,默認整個數組都排序,而且從小到大
};
複製代碼
要實現的基本功能大概就是這些,也能夠自由添加更多的功能,只須要在頭文件中聲明函數,而後在cpp文件中實現相應的功能便可。測試
1.構造函數 初始化數組對象,由於在數組的基類中只初始化了數組當前的元素個數,在這裏要初始化數組的容量,以及開闢一段新的內存空間給數組,並賦值給函數指針。這裏默認初始內存大小爲10(能夠自由設置)。
CDynamicArray::CDynamicArray()
{
m_Capacity = 10;
mp_Array = new int[m_Capacity];//注意new一個內存空間的寫法,
}
複製代碼
mp_Array = new int[m_Capacity]是開闢了一個新的內存,並把內存的地址賦給了數組對象中的指針,之後就可使用這個指針來操做整個內存空間了。
2.插入元素 這也是動態數組最重要的部分。對於動態數組來講,最重要的特色就是數組的容量是能夠動態變化的,能夠根據數組裏面元素的增長而自動變長。但實際是每個數組必須都有一個內存大小,只是說對於用戶使用的時候,這個數組好像是沒有長度,能夠任意添加元素。 因此實際上的動態數組應該是先給定一個初始的內存大小,讓用戶能夠添加元素。當添加的元素達到了目前數組的容量,即m_Size=m_Capacity,這個時候若是再添加元素,內存就不夠了。咱們能夠開一個更大內存的地址空間,而後把原來數組裏面的全部元素,所有複製過去。這樣就實現了一個基本的「任意長度」的功能。具體步驟參考註釋。
//插入元素
void CDynamicArray::PushBack(int value)
{
//數組容量還足夠時,直接把值存到相應的位置
if (m_Size != m_Capacity)
{
mp_Array[m_Size] = value;
m_Size++;
return;
}
//若是數組容量不夠,則:
//1.先開一個新內存空間(通常容量爲原來的2倍)
//2.而後把原來的數據複製過去
//3.而後delete原來的內存
//4.再讓mp_Array指針指向新的內存空間
//5.把容量m_Capacity改成原來的2倍
//6.把要插入的值放入相應的位置,而且元素個數 m_Size+1
int* pNewSpace = new int[m_Capacity * 2];//開一個新的內存空間
memcpy(pNewSpace, mp_Array, sizeof(int)*m_Capacity);
//複製一段內存空間,裏面的參數分別是
//新的地址,複製源地址,複製源的長度(單位是字節,因此這裏要使用sizeof(int)*m_Capacity)
delete[] mp_Array;
mp_Array = pNewSpace;
m_Capacity *= 2;
mp_Array[m_Size] = value;//容量已夠,開始賦值
m_Size++;
}
複製代碼
3.刪除數組末尾的元素 這一步很簡單,只須要把當前數組元素個數m_Size-1就能夠,並不須要去改動要刪除的這個值,在下次插入的時候會自動覆蓋掉。
//刪除末尾的元素
void CDynamicArray::Remove()
{
m_Size -= 1;
}
複製代碼
4.查找 查找數組中具體值的方法有不少,由於該數組並非有序的,因此直接順序查找比較簡單,即從數組的開始位置一直查找到m_Size的位置
//查找指定值的元素,返回元素所在的位置
int CDynamicArray::Find(int value, bool isPrint)
{
for (int i = 0; i < m_Size; i++)
{
if (mp_Array[i] == value)
{
if (isPrint)
printf("the position of date \"%d\" is %d\n", value, i);
return i;
}
//沒找到就返回-1
if (i == m_Size - 1)
{
if (isPrint)
printf("the position of date \"%d\" is not in array\n", value);
return -1;
}
}
}
複製代碼
5.清空數組 清空全部元素和刪除元素相似,直接把m_Size置0便可,數組只能訪問到m_Size大小的位置。
//清空全部元素
void CDynamicArray::Clear()
{
m_Size = 0;
}
複製代碼
6.排序 關於排序算法有不少種,這裏選擇使用冒泡排序。具體能夠參考另外一篇關於排序的文章 blog.csdn.net/nsytsqdtn/a… 在動態數組的頭文件中定義了兩種排序,一種是有參數,能夠自定義範圍的排序;另外一種是無參數,整個數組一塊兒排序。 這是有參數的排序:
//有參數,有範圍的排序
void CDynamicArray::Sort(int start, int end, bool up)//第三個參數true則爲從小到大
{
if (start >= 0 && end < m_Size)//防止排序的範圍越界
{
if (up)//判斷第三個參數,來決定從小到大仍是從大到小,true則爲從小到大
{
//冒泡排序,從小到大
for (int j = end; j > start; j--)
{
for (int i = start; i < j; i++)
{
if (mp_Array[i] > mp_Array[i + 1])
{
int temp = mp_Array[i];
mp_Array[i] = mp_Array[i + 1];
mp_Array[i + 1] = temp;
}
}
}
}
else//從大到小的排序
{
for (int j = end; j > start; j--)
{
for (int i = start; i < j; i++)
{
if (mp_Array[i] < mp_Array[i + 1])
{
int temp = mp_Array[i];
mp_Array[i] = mp_Array[i + 1];
mp_Array[i + 1] = temp;
}
}
}
}
}
}
複製代碼
無參數的排序:
//無參數,整個數組的排序(只能從小到大)
void CDynamicArray::Sort()
{
int start = 0, end = m_Size - 1;
for (int j = end; j > start; j--)
{
for (int i = start; i < j; i++)
{
if (mp_Array[i] > mp_Array[i + 1])
{
int temp = mp_Array[i];
mp_Array[i] = mp_Array[i + 1];
mp_Array[i + 1] = temp;
}
}
}
}
複製代碼
動態數組的全部功能函數就都已經實現,咱們還須要在主程序中來調用一下前面寫的動態數組
在主函數中要使用前面所寫的動態數組,就只須要像建立類對象同樣把動態數組的對象建立出來就可使用了。首先仍是建立一個新文件Array.cpp。 建立對象的方法有兩種,一種是CDynamicArray* dArray = new CDynamicArray()。這種用new建立對象的方法須要手動去釋放空間,因此相對使用起來更復雜。在主函數中推薦使用第二種建立對象的方式,即CDynamicArray dArray。 咱們使用動態數組來插入數據,而且進行排序,而後打印整個數組
#include "pch.h"
#include<iostream>
using namespace std;
#include "CDynamicArray.h"
using namespace std;
int main() {
int n;
cin >> n;
//動態數組測試
CDynamicArray dArray;//建立動態數組對象
for (int i = 0; i < n; i++)
{
int temp;
cin >> temp;
dArray.PushBack(temp);//把手動輸入的數據插入到數組的末尾
}
dArray.Sort(0,dArray.getSize()-1,false);
//數組從第0位置到最後一個位置一塊兒排序
//這裏和無參排序效果同樣
dArray.Print();//打印整個數組
return 0;
}
複製代碼
運行結果以下:
輸入:
10
9 15 5 30 11 7 6 51 1 40
輸出:
print all date :
51
40
30
15
11
9
7
6
5
1
複製代碼
也能夠在主函數中具體測試插入數據之後,數組的容量和當前元素的個數具體是怎麼樣變化的,在這裏就不作多的測試了。 至此,就實現了一個動態數組,相比c++標準的數組,本身寫出來的東西,調用起來仍是會方便一些。由於沒有使用模板元編程,數組的數據類型只設置了int,並且修改起來也不會很方便。因此更好的使用c++的動態數組能夠參考STL中的vector。最後給出全部文件的源代碼。
CArray.h文件的代碼以下:
#pragma once
class CArray {
public:
//成員函數
CArray();//構造函數,即用來初始化
~CArray();//析構函數,使用完後釋放空間
void Print();//打印數組的元素
int getCapacity();//獲得數組的容量
int getSize();//獲得數組當前的元素個數
//成員變量
int* mp_Array;//存放數組對象的指針
int m_Size;//數組當前的元素個數
int m_Capacity;//數組的容量
};
複製代碼
CArray.cpp文件的代碼以下:
#include "CArray.h"
#include<iostream>
CArray::CArray()//構造函數初始化
{
m_Size = 0;
}
CArray::~CArray()//析構函數
{
delete[] mp_Array;
}
int CArray::getCapacity()//獲得數組的容量
{
return m_Capacity;
}
int CArray::getSize()//獲得數組當前的元素個數
{
return m_Size;
}
void CArray::Print()//打印數組全部元素
{
printf("\nprint all date : \n");
for (int i = 0; i < m_Size; i++)
{
printf("%d\n", mp_Array[i]);
//在使用打印函數的時候,必定已經建立好了數組對象
//因此這裏的mp_Array[i]是可使用的,在後面的文件中咱們會進行賦值
}
}
複製代碼
CDynamicArray.h文件的代碼以下:
#pragma once
#include "CArray.h"
class CDynamicArray ://這個類要繼承前面寫的數組基類
public CArray
{
public:
CDynamicArray();//構造函數
~CDynamicArray();//析構函數
void PushBack(int value);//在數組的末尾插入元素,裏面的參數爲要插入的數據
void Remove();//移除數組末尾的一個元素
int Find(int value, bool isPrint);//查找某一個元素,返回的是位置
//這裏的isPrint是我用來測試時添加的打印語句,在找到之後能夠打印該元素的位置
//也能夠不使用該參數
void Clear();//清空該數組全部的元素
void Sort(int start, int end, bool up);//有參數的數組排序,參數是要參與排序的起始位置和末尾位置
//第三個參數是排序是從小到大仍是從大到小
void Sort();//無參數的數組排序,默認整個數組都排序,而且從小到大
};
複製代碼
CDynamicArray.cpp文件的代碼以下:
#include "CDynamicArray.h"
#include<stdlib.h>
#include<string.h>
#include<iostream>
CDynamicArray::CDynamicArray()
{
m_Capacity = 10;
mp_Array = new int[m_Capacity];//注意new一個內存空間的寫法,
}
CDynamicArray::~CDynamicArray()
{
}
//插入元素
void CDynamicArray::PushBack(int value)
{
//數組容量還足夠時,直接把值存到相應的位置
if (m_Size != m_Capacity)
{
mp_Array[m_Size] = value;
m_Size++;
return;
}
//若是數組容量不夠,則:
//1.先開一個新內存空間(通常容量爲原來的2倍)
//2.而後把原來的數據複製過去
//3.而後delete原來的內存
//4.再讓mp_Array指針指向新的內存空間
//5.把容量m_Capacity改成原來的2倍
//6.把要插入的值放入相應的位置,而且元素個數 m_Size+1
int* pNewSpace = new int[m_Capacity * 2];//開一個新的內存空間
memcpy(pNewSpace, mp_Array, sizeof(int)*m_Capacity);
//複製一段內存空間,裏面的參數分別是
//新的地址,複製源地址,複製源的長度(單位是字節,因此這裏要使用sizeof(int)*m_Capacity)
delete[] mp_Array;
mp_Array = pNewSpace;
m_Capacity *= 2;
mp_Array[m_Size] = value;//容量已夠,開始賦值
m_Size++;
}
//刪除末尾的元素
void CDynamicArray::Remove()
{
m_Size -= 1;
}
//查找指定值的元素,返回元素所在的位置
int CDynamicArray::Find(int value, bool isPrint)
{
for (int i = 0; i < m_Size; i++)
{
if (mp_Array[i] == value)
{
if (isPrint)
printf("the position of date \"%d\" is %d\n", value, i);
return i;
}
//沒找到就返回-1
if (i == m_Size - 1)
{
if (isPrint)
printf("the position of date \"%d\" is not in array\n", value);
return -1;
}
}
}
//清空全部元素
void CDynamicArray::Clear()
{
m_Size = 0;
}
//有參數,有範圍的排序
void CDynamicArray::Sort(int start, int end, bool up)//第三個參數true則爲從小到大
{
if (start >= 0 && end < m_Size)//防止排序的範圍越界
{
if (up)//判斷第三個參數,來決定從小到大仍是從大到小,true則爲從小到大
{
//冒泡排序,從小到大
for (int j = end; j > start; j--)
{
for (int i = start; i < j; i++)
{
if (mp_Array[i] > mp_Array[i + 1])
{
int temp = mp_Array[i];
mp_Array[i] = mp_Array[i + 1];
mp_Array[i + 1] = temp;
}
}
}
}
else//從大到小的排序
{
for (int j = end; j > start; j--)
{
for (int i = start; i < j; i++)
{
if (mp_Array[i] < mp_Array[i + 1])
{
int temp = mp_Array[i];
mp_Array[i] = mp_Array[i + 1];
mp_Array[i + 1] = temp;
}
}
}
}
}
}
//無參數,整個數組的排序(只能從小到大)
void CDynamicArray::Sort()
{
int start = 0, end = m_Size - 1;
for (int j = end; j > start; j--)
{
for (int i = start; i < j; i++)
{
if (mp_Array[i] > mp_Array[i + 1])
{
int temp = mp_Array[i];
mp_Array[i] = mp_Array[i + 1];
mp_Array[i + 1] = temp;
}
}
}
}
複製代碼
Array.cpp文件的代碼以下:
#include "pch.h"
#include<iostream>
using namespace std;
#include "CDynamicArray.h"
using namespace std;
int main() {
int n;
cin >> n;
//動態數組測試
CDynamicArray dArray;//建立動態數組對象
for (int i = 0; i < n; i++)
{
int temp;
cin >> temp;
dArray.PushBack(temp);//把手動輸入的數據插入到數組的末尾
}
dArray.Sort(0,dArray.getSize()-1,false);
//數組從第0位置到最後一個位置一塊兒排序
//這裏和無參排序效果同樣
dArray.Print();//打印整個數組
return 0;
}
複製代碼