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 可以看到一个宏观面。对程序架构改进很有益处。 



STL vector 动态数组实现

上一篇:ssh连接时认证时间过长解决方法


下一篇:oracle之FUNCTION拙见