STL vector 動態數組實現

在參加某公司二輪筆試時 ,要求編寫出vector 動態數組的實現方法。 筆試過程中,因爲緊張的緣故,沒有理清思路。 編程漏洞百出。心理甚是不滿。特抽晚上重新整理一遍思路。將代碼附上。以供分享和交流。


對類的實現方法要求:

1    可實現數組大小查詢

2 數組指定數據查詢

3 手動,自動設置數組大小

4 在數組尾部添加數據

5    置換指定位置數據

6  在數組指定位置插入數據


題目頭文件:

class vector
{
public:
	vector();
	vector( int nSize );
	vector( const vector& vData );
	~vector();
	
	// Set data to vector by index, need increase size if index large equal than m_nSize. 
	bool SetData( int index, double dData ); 
	//Get the data by index
	bool GetData( int index, double& dData);
	
	// Returns the size of this vector. 
	int GetSize()const{ return m_nSize; }
	// Set the number of data
	void SetSize(int nSize) ;

	// Add one data to the end of vector, m_nSize will be m_nSize+1.	
	bool Add( double dData);
	
	// Insert the number of data - dData into the vector object with the specified index.
	bool InsertAt( int nIndex, double dData, int nCount = 1 );

private:
	double *m_pData;
	int m_nSize;
};
題目CPP 文件

#include "vector.h"

/*
Please implement the following class.  Note: 
1.	Your codes should be written and debugged in Visual C++, and need test all methods in vector class, just like in the following main function.
2.	Library functions cannot be used.
3.	Good coding style (necessary comment, good structure, error check etc.) is preference.
4.	All comments should be written in English.
*/

vector::vector()
{
	m_nSize = 0;

	// to do
}

vector::vector( int nSize )
{
	m_nSize = nSize;

	// to do
}

vector::vector( const vector& vData )
{
	// to do
}

vector::~vector()
{
	// to do
}

void vector::SetSize( int nSize )
{
	// to do
}

bool vector::SetData( int index, double dData )
{
	// to do
	return false;
}

bool vector::GetData( int index, double& dData)
{
	// to do
	return false;
}

bool vector::Add( double dData)
{
	// to do
	return false;
}

bool vector::InsertAt( int nIndex, double dData, int nCount)
{
	// to do
	return false;
}



筆試要求:

1 實現main 文件中正常運行

2 編程過程中不允許調用庫函數

3 要求實現代碼的防禦性編程機制。確保程序的健碩性

4 良好的編程風格,編程架構設計,清晰的英文註釋

題目 main 文件

#include<iostream>
#include<stdlib.h>
#include "vector.h"
using namespace std;

void main()
{
	cout<<"This is a test function"<<endl;

	vector vec(5);
	vec.SetData(0,0.1);
	vec.SetData(1,0.2);
	vec.SetData(2,0.3);
	vec.SetData(3,0.4);
	vec.SetData(4,0.5);
	vec.Add(0.6); // add 0.6 at the end of vec object
	vec.InsertAt(0, 0.01, 2); // insert two 0.01 at the beginning of vec object

	// print out the result
	cout << "Size of vec is " << vec.GetSize() << endl; // size should be 8

	for(int nn = 0; nn < vec.GetSize(); nn++)
	{
		double dData;
		if( vec.GetData(nn, dData) )
			cout << dData << endl;
	}
}



下面是筆者利用晚上時間完善的代碼:

頭文件修改部分

class vector
{
public:
	.............................

private:
	double *m_pData;
	int m_nSize;
	int m_edge;				// new adding variant 
};

對頭文件的修改是添加一個  整形成員變量。 主要是用來指定數組指定的大小範圍
int m_edge;


cpp 文件方法實現:

#include "vector.h"

/*
Please implement the following class.  Note: 
1.	Your codes should be written and debugged in Visual C++, and need test all methods in vector class, just like in the following main function.
2.	Library functions cannot be used.
3.	Good coding style (necessary comment, good structure, error check etc.) is preference.
4.	All comments should be written in English.
*/

vector::vector()
{
	m_nSize = 0;
	m_edge=1024;
	m_pData=new double[1024];		// set the default size is 1024;

	// to do
}

vector::vector( int nSize )
{
	//===============================
	// time for jugde the nsize , to guarantee the array is big enough
	if (nSize<0)
	{
		// assert(1!=1);		// abort 
		m_edge=-1;
		return;
	}

	m_nSize = nSize;

	if (nSize<1024&&nSize>=0)
	{
		m_edge=1024;
		m_pData=new double[1024];		// set the default size is 1024;
	}
	else if (nSize>=1024&&nSize<1024*3)
	{
		m_edge=1024*3;
		m_pData=new double[1024*3];
	}
	else if (nSize>=1024*3&&nSize<1024*8)
	{
		m_edge=1024*8;
		m_pData=new double[1024*8];
	}

	else if (nSize>=1024*8&&nSize<1024*20)
	{
		m_edge=1024*20;
		m_pData=new double[1024*20];
	}
	else
	{
// 		assert(1!=1);		// coding defense for the enter size 
// 							// is too huge for the array. this could extend 
		m_edge=-1;
		return;
	}


	// to do
}

vector::vector( const vector& vData )
{
	// to do
	m_nSize=vData.GetSize();
	int nSize=m_nSize;

	//===============================
	// define the proper array size 
	if (nSize<0)
	{
		// assert(1!=1);		// abort 
		return;
	}

	if (nSize<1024&&nSize>=0)
	{
		m_edge=1024;
		m_pData=new double[1024];		// set the default size is 1024;
	}
	else if (nSize>=1024&&nSize<1024*3)
	{
		m_edge=1024*3;
		m_pData=new double[1024*3];
	}
	else if (nSize>=1024*3&&nSize<1024*8)
	{
		m_edge=1024*8;
		m_pData=new double[1024*8];
	}

	else if (nSize>=1024*8&&nSize<1024*20)
	{
		m_edge=1024*20;
		m_pData=new double[1024*20];
	}
	else
	{
		// 		assert(1!=1);		// coding defense for the enter size 
		// 							// is too huge for the array. this could extend 
		m_edge=-1;
		return;
	}

	//================================================
	// copy the data to the m_pData

	double pTemp;

	for (int i=0; i<m_nSize; i++)
	{
		// this is a big issue for the data could not get from the object
// 		vData.GetData(i,pTemp);
		m_pData[i]=pTemp;
	}

}

vector::~vector()
{
	delete m_pData;
	// to do
}

void vector::SetSize( int nSize )
{
	// to do
	//==================================
	// defense coding 
	if (nSize<m_nSize)		// the setting size could be smaller than the original size
	{
		return;
	}
	
	if (nSize>=m_nSize&&nSize<m_edge)		// in the safe array just adjust the parameter 
	{
		m_nSize=nSize;
		return;
	}
	
	// if the edge had been broken though , then relocate the array size
	// copy the data, assign the m_edge and m_nSize  
	else if (nSize>=m_edge)						
	{
		double *pTemp;	
		// get the real m_edge 

		if (nSize>=1024&&nSize<1024*3)		// the default m_edge is 1024
		{
			m_edge=1024*3;
			pTemp=new double[1024*3];
		}
		else if (nSize>=1024*3&&nSize<1024*8)
		{
			m_edge=1024*8;
			pTemp=new double[1024*8];
		}

		else if (nSize>=1024*8&&nSize<1024*20)
		{
			m_edge=1024*20;
			pTemp=new double[1024*20];
		}
		else
		{
			// 		assert(1!=1);		// coding defense for the enter size 
			// 							// is too huge for the array. this could extend 
			m_edge=-1;
			return;
		}
		// ===========================================
		// copy data into the new array 
		for (int i=0; i<m_nSize; i++)
		{
			pTemp[i]=m_pData[i];
		}	

		delete m_pData;					// release the old array 
		m_pData=pTemp;					// retrieve the new array memory pointer 
		
		m_nSize=nSize;					// set the size 			
	}



}

bool vector::SetData( int index, double dData )
{
	// to do
	//==================================================
	// index legislation checking 
	if (index<0)
	{
		return false;
	}

	if (index<m_nSize)		// in the working arrange change the value directly 
	{
		m_pData[index]=dData;
		return true;
	}
	else if (index>=m_nSize&& index<m_edge)		// still in the array space 
	{
		m_nSize=index;			// extend the size of the array 
		m_pData[index]=dData;
		return true;
	}
	// once the container is not big enough to contain the array data 
	// relocate a new space to store the data 
	else if (index>m_edge)	
	{
		SetSize(index);
		m_pData[index]=dData;
		return true;

	}




}

bool vector::GetData( int index, double& dData)
{
	// to do
	// once time the function get the correct parameter 
	// return true , if not then return false 
	if (index<0||index>m_nSize)
	{
		return false;
	}

	dData=m_pData[index];

	return true;
}

bool vector::Add( double dData)
{
	// to do
	//========================================
	if (++m_nSize<m_edge)				// in the safe range 
	{
		m_pData[m_nSize-1]=dData;
		return true;
	}
	else								// need to relocate the array space 
	{
		SetSize(m_nSize);		
		m_pData[m_nSize-1]=dData;		// set the end of the 
		return true;
		
	}

}

bool vector::InsertAt( int nIndex, double dData, int nCount)
{
	// to do
	//==============================================
	// make sure the space for the array shift
	SetSize(m_nSize+nCount);		// m_nSize will be m_nSize+nCount
	
	//==============================================
	// shift nCount steps array
	for (int i=m_nSize-1; i>=nIndex+nCount; i--)
	{
		m_pData[i]=m_pData[i-nCount];
	}
	
	for (int i=0; i<nCount; i++)
	{
		if(!SetData(nIndex+i,dData))
		{
			return false;
		}
	}
	return true;

}



筆者貼出的代碼中存在一個bug 。 主要是關於深拷貝構造函數。 
vector::vector( const vector& vData )
{
	// to do
	m_nSize=vData.GetSize();
	

	//================================================
	// copy the data to the m_pData

	double pTemp;

	for (int i=0; i<m_nSize; i++)
	{
		// this is a big issue for the data could not get from the object
 		vData.GetData(i,pTemp);      // bug  position
		m_pData[i]=pTemp;
	}

}

要求將形參對象的私有數組拷貝到新的數組當中。筆者本考慮使用形參對象的方法實現數據的輸出。但是編譯器一直提示:

error C2662: “vector::GetData”: 不能將“this”指針從“const vector”轉換爲“vector &”
現在還沒有弄明白具體原因是什麼, 特提出來和大家討論討論O(∩_∩)O~


總結:

1 防禦性編程模式是衡量一個職業與業餘開發者的重要準則。

在過去的開發過程中,對這方面重視程度遠遠不夠。這或許也是原有的設計思維模式存在的固有缺陷: 先實現基本功能,後完善。 但是往往在實現基本功能之後,之前挖下坑卻忘記或者沒有能夠填補。

先實現,後完美的開發設計模式,最大的特點在於可實現產品快速更迭。爲了實現代碼的編程,將編程過程中的枝葉先行忽略。將主體架構實現出來,在考慮後續的完善。但是這種模式最大的缺陷,同時也就造成了這樣一種尷尬局面: 

你填不贏新手挖的坑,扶不正老人修的廟。

一旦留下的坑沒有被及時填補,對於後續的開發維護工作無疑是巨大的痛苦。筆者在筆試的時候,在寫完代碼之後,就陷入了這樣一種尷尬局面。知道自己寫的代碼中存在bug 。但是總是找不出來。整個人處於一種高度緊張的狀態。結果可想而知。

2 不論什麼情況下,保持原有的編程節奏,是確保臨場發揮時編程代碼質量的重要條件

筆者在筆試時,剛開始有點輕敵,在理清楚思緒,頭腦中只是有個大概方向的情況就匆匆動手。結果時間上因爲後期的調試bug 沒有佔到任何便宜。更是把自己弄的焦頭爛額。


改進方案:

1 或許是因爲在線筆試緊張的原因,完全亂了平時編程的節奏。對於具有一定規模的編程,筆者覺得應該先行對代碼的功能需求進行整理分析,理清楚主次關係。以及優先需要實現的方法

2 在編程之前,編程之中,編程之後,將編程過程中可能遇到的問題,bug隨時記錄下來。做到編程隨時隨地有log 。雖然不一定需要馬上將bug 消滅。但是將bug 記錄下來,

一是有利於後期補坑的工作。

二則是爲了快速開發的需求,先主幹,後枝葉的原則。 

三則是記錄下來的bug 之間很有可能存在一定關聯,當某方面bug 聚集到一定程度,通過log 可以看到一個宏觀面。對程序架構改進很有益處。 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章