打造 C++ 最灵活动态数组结构 (一)

      问题:

      1 实现一个动态数组,要求有XXX成员变量。(XXX 表示各种类型的变量,变量里面允许有子变量,子变量里有子变量... ...)

      2 构造一个树型结构的菜单函数。

      3 从HTTP 网络流中解析数据并对本地数据赋值。

      4 把某一数据流中数据打包传递到外部,或保存在本地做永久存储,或做数据库归档。

      5 设计一个树型结构的数据库表结构。

      6 ... ...

      作为一名C++ 的程序员,我相信你有足够的能力解决以上问题。让我们来一同分析一下以上问题的解决方法。

        第一个问题,需要一个动态数组,也许我们应该使用malloc new 等操作符来动态的分配空间,或者使用STL 容器中提供的方法构造指定类型的模板类。至于里面的成员变量要根据题目要求来构造各种各样的struct class union enum ... ... 啊~ 题目怎么没说是什么类型? 晕,那没法做了,你不说清楚是什么类型的我可怎么做啊? 我用的是C++。

        第二个问题,可以定义一个任意复杂的类结构,表示树中的某一个节点。这个结构里面有许多我认为有必要加上的成员变量,和指针。而且应该用链表,最好是双向链表把这些接点连接起来,为了不关心空间的产生与释放,我也许会定义一个动态的内存管理器... ...

         第三个问题,这个解析应该在双方定好协议,协议里面要包含这个数据结构的类型,接受到这个数据之后我好根据本地对这个类型的定义来解析这个数据结构,不要告诉我你那边没有一个和我一模一样的定义,否则我解析错了可完全是你的责任哦~~

        第四个问题,如果我是单一类型的数据 比如整型数组,那么我可以遍例数组里面的成员,然后按照一种我认为很优美的格式写入到文件中,或传输,如果类型里面还有子类型,那么我要清楚知道里面类型的变量类型并且根据一种同样优美的格式写入到文件中或传输,可是你最好不要乱改类型的结构,否则我这个写入文件的强大函数可是会力即失效的,不是和你开玩笑,除非你这个写入或传输的操作是一次性或者是永久性的,否则最好不要让我写。我也懒的写。

        第五个问题,一般的树型表结构至少要有两个字段,一个用来记录当前节点ID,另一个用来记录子节点ID。遍例子节点时可以一条Select 搞定,什么你告诉我要删除这个节点下的所有子节点数据?那要遍例所有子孙节点... ... ,方法是先 Select 出子节点,在Select 数据,再Select 子节点... ....希望数据库要够强大才好,一般我们是要强迫自己相信这一点的。否则这个任务就很难完成了

        第六个问题,你还没想好,那我就是不用做了,不过我应该好好想想上面几个问题还有哪些容易产生的问题,如何避免上面的哪些麻烦? 这不会你想问的东西吧??      

       以上是我的一些分析和假设,相信读此文章的您会有更好的解决办法,刚好,我也有一个,那就是用脚本,Python ? PHP? JS? Ruby? Perl?... ...这些家伙就是脚本,现用脚本思路来解决以上问题。

       第一个问题,不是问题,Python 提供的几个操作符就搞定了 -- ( )  [ ] { } 里面的数据随便添。其它脚本同理 PHP 尤其强大 Array() 搞定一切。

       第二个问题,我用 Array() 存储树型节点层次关系,单独节点实现不需要用链表和指针进行关联,节点中只要保留一个节点ID 就好,查关系时去 Array() 中找。

       第三个问题,不是问题 Serialize 函数序列化,发送,搞定。不管你是什么数据,只要接收端 UnSerialize 就可以。

       第四个问题,同上。

       第五个问题,用一个表存第三个问题中Array() 被 Serialize 序列化后的字串,用另一个表的一个字段存当前节点ID就可以了,程序运行是 反序列化Array() 节点关系到内存,遍历时先在Array() 中找到节点关系,然后一个 Select 搞定数据库。

       第六个问题,我想你在担心我的效率吧,那我就不敢保证了... ...

        数据结构?  各种各样,数据类型? 各种各样。在C++中,代码会老实的告诉你各种数据的类型与结构是什么,这种老实太多了,充斥着代码中的每一行,每一句,就算是善意的提醒,有时也显得过于苛刻了。如果你赞同以上看法,请不要跳过以下文字。

       所谓数据,我看来只要 2 种类型,一种数字类型,一种字符类型,数字类型有计算机识别其含义,字符类型由人识别其含义,纵然C++中各种类型无穷无尽,但都是这两种类型的容器,区别在于容器中容纳的数据有些相同,有些不同而已。 这里指出指针和引用也是一个数字而已。

       进入正题,我要做的就是用C++来实现一个可以解决以上6个问题的通用思路,我要用写脚本的速度完成任务,要用C++ 的效率完成任务。构造MyData 类需要支持以下语法。

	int i = 0;
	MyData testData;
	MyData testData2("[1:22, '2':0, 'dff': [1:3]]");
	testData[i]			= 100;
	testData[3]			= 3;
	testData[1]			= 1;
	testData[6]			= 2;
	testData()[1]		= 41;
	testData[5]()[6]	= 506;
	testData[5]["a"][1]	= 501;
	testData[5][3][1]	= 511;
	testData[5]()[2]	= 541;
	testData["a"]()		= Serialize("[1:22, '2':0, 'dff': [1:3]]");
	testData["a"]		= "fuck";
	testData["a"][2]	= "a";
	testData["a"]()		= "b";
	testData["a"]()		= "c";
	testData2			= "abc";
	testData["c"]()		= 1;
	testData["c"]()		= testData2;
	testData[2][i][i]	= 2;

	print_r(testData);

       第一个版本的代码如下:

 

/*--------------------------------*/

	C++ 散列化数组结构

	cjxxstar@gmail.com

	cjxx 2008-06-27

/*--------------------------------*/

#include <iostream>

#include <string>

#include <map>



using namespace std;



class MyData;



MyData& Serialize(const char* serStr, MyData* dVal = NULL);



bool UnSerialize(MyData* dVal, string& unserStr);



class MyData {



public:

	enum ENUM_DATA_TYPE {

		DATA_TYPE_DEF = 0,  // 初始类型

		DATA_TYPE_DAT = 1,	// 数组类型

		DATA_TYPE_INT = 2,  // 整数类型

		DATA_TYPE_STR = 3,  // 字符类型

	};

	typedef map<string, MyData>  MAP_MY_DATA;

public:

	// 构造

	MyData() {

		this->Init();

	}

	// 序列化构造

	MyData(const char* dVal) {

		this->Init();

		Serialize(dVal, this);

	}

	// 析构

	~MyData() {

		this->Clear();

	}

	// 判断类型

	bool IsType(enum ENUM_DATA_TYPE eType) {

		return m_cType == eType;

	}

	// 获取类型

	enum ENUM_DATA_TYPE Type() {		

		return m_cType;

	}

	// 获取MAP

	MAP_MY_DATA& Map() {

		return m_mapMyData;

	}

	// 获取整形数据

	int i() {

		return (m_cType == DATA_TYPE_INT) ? m_intData : 0;

	}

	// 获取字符数据

	const char* c() {

		return (m_cType == DATA_TYPE_STR) ? m_strData.c_str() : "";

	}

	// 获取反序列化字串

	const char* u() {  

		return UnSerialize(this, m_strUnSer) ? m_strUnSer.c_str() : "";

	}

	// 赋值为整数

	void operator=(int iVal) {

		this->Clear();

		m_intData = iVal;

		m_cType = DATA_TYPE_INT;

		this->SetFatherDat();

	}

	// 赋值为字符

	void operator=(const char* cVal) {

		this->Clear();

		m_strData = cVal;

		m_cType = DATA_TYPE_STR;

		this->SetFatherDat();

	}

	// 赋值为数据

	void operator=(const MyData& dVal) {

		this->Clear();

		m_strData	= dVal.m_strData;

		m_strUnSer	= dVal.m_strUnSer;

		m_intData	= dVal.m_intData;

		m_iNowIndex	= dVal.m_iNowIndex;

		m_mapMyData	= dVal.m_mapMyData;

		m_cType		= dVal.m_cType;

		this->SetFatherDat();

	}

	// 自动增加一个数字索引

	MyData& operator()() {

		m_iTmpIndex = m_iNowIndex;

		return this->Get(StrIndex(m_iNowIndex++));

	}

	// 整形索引

	MyData& operator[](int keyName) {

		m_iTmpIndex = keyName;

		return this->Get(StrIndex(keyName));

	}

	// 字符型索引

	MyData& operator[](const char* keyName) {

		m_iTmpIndex = 0;

		return this->Get(keyName);

	}

private:

	void Clear() {

		if (m_cType == DATA_TYPE_DAT) {

			m_mapMyData.clear();

		}

	}

	void Init() {

		m_iNowIndex = 0;

		m_iTmpIndex = 0;

		m_intData	= 0;

		m_mapMyData.clear();

		m_pFather	= NULL;

		m_cType		= DATA_TYPE_DEF; // 默认的类型

	}

	const char* StrIndex(unsigned int index) {

		char buf[256] = {0};

		sprintf_s(buf, "Int%d", index);

		m_strUnSer = buf;

		return m_strUnSer.c_str();

	}

	MyData& Get(const char* keyName) {

		MAP_MY_DATA::iterator iter;

		if (NULL == keyName) {

			iter = m_mapMyData.find("");

		} else {

			iter = m_mapMyData.find(keyName);

		}

		if (iter != m_mapMyData.end()) {

			return (*iter).second;

		} else {

			pair<MAP_MY_DATA::iterator, bool> Insert_Pair;

			MyData data;

		 	if (NULL == keyName) {

				Insert_Pair = m_mapMyData.insert(MAP_MY_DATA::value_type("", data));

			} else {

				Insert_Pair = m_mapMyData.insert(MAP_MY_DATA::value_type(keyName, data));

			}

			(*Insert_Pair.first).second.SetFather(this);

			return (*Insert_Pair.first).second;

		}		

	}

	// 设置父级类型 为DAT

	void SetFatherDat() {

		if (NULL != this->GetFather()) {

			if (! this->GetFather()->IsType(DATA_TYPE_DAT)) {

				this->GetFather()->m_cType = DATA_TYPE_DAT;

			}

			if (this->GetFather()->m_iNowIndex  < this->GetFather()->m_iTmpIndex) {

				this->GetFather()->m_iNowIndex = this->GetFather()->m_iTmpIndex + 1;

			}

			this->GetFather()->SetFatherDat();

		}

	}

	// 设置父级指针

	void SetFather(MyData* pData) {

		m_pFather = pData;

	}

	// 获取父级指针

	MyData* GetFather() {

		return m_pFather;

	}	

private:

	enum ENUM_DATA_TYPE		m_cType;		// MyData类型

	string					m_strData;		// 字串类型

	string					m_strUnSer;		// 反序列化自身串

	int						m_intData;		// 整型

	int						m_iNowIndex;	// 当前索引

	int						m_iTmpIndex;	// 临时索引

	MyData*					m_pFather;		// 父级索引指针

	MAP_MY_DATA				m_mapMyData;	// 数据容器

};



//	序列化成数据

MyData& Serialize(const char* serStr, MyData* dVal /*= NULL*/) {

	MyData* pDVal;

	if (dVal == NULL) {

		pDVal = new MyData;

	} else {

		pDVal = dVal;

	}

	// 序列化并添加数据

	return (*pDVal);

}

//	反序列化为字串

bool UnSerialize(MyData* dVal, string& unserStr) {

	if (NULL == dVal) {

		return false;

	}

	//	反序列化数据对象

	return true;

}



enum PRINT_R_STYLE

{

	PHP	= 0,

	JS	= 1,

};



string& print_s(MyData& data,  string& str, enum PRINT_R_STYLE style = PHP, int level = 0) {

	char j_style[3][10] = {"=>array(", ")", "=>"};

	char p_style[3][10] = {       ": {", "}",  ":"};

	char (* u_style)[10] = style == PHP ? p_style : j_style;

	string space = "";

	for (int i = 0; i < level; i++) {

		space += " ";

	}

	++level;

	if (data.IsType(MyData::DATA_TYPE_DAT)) {

		MyData::MAP_MY_DATA::iterator iter = data.Map().begin();

		for (;iter != data.Map().end(); iter++) {			

			if ((*iter).second.IsType(MyData::DATA_TYPE_DAT)) {

				str += space;

				str += (*iter).first.c_str();

				str += u_style[0];

				str += "/n";

				str  = print_s((*iter).second, str, style, level);

				str += space;

				str += u_style[1];

				str += "/n";

			} else if ((*iter).second.IsType(MyData::DATA_TYPE_INT)) {

				char buf[12] = {0};

				sprintf_s(buf, "%d", (*iter).second.i());

				str += space;

				str += (*iter).first.c_str();

				str += u_style[2];

				str += buf;

				str += "/n";

			} else if ((*iter).second.IsType(MyData::DATA_TYPE_STR)) {

				str += space;

				str += (*iter).first.c_str();

				str += u_style[2];

				str += (*iter).second.c();

				str += "/n";

			}

		}

	} else if (data.IsType(MyData::DATA_TYPE_INT)) {

		char buf[12] = {0};

		sprintf_s(buf, "%d", data.i());

		str += space;

		str += buf;

		str += "/n";

	} else if (data.IsType(MyData::DATA_TYPE_STR)) {

		str += space;

		str += data.c();

		str += "/n";

	}

	return str;

}



void print_r(MyData& data) {

	string str = "/n{/n";

	print_s(data, str, PHP, 1);

	str += "}";

	printf("%s", str.c_str());

}



int main(void)

{

	int i = 0;

	MyData testData;

	MyData testData2("[1:22, '2':0, 'dff': [1:3]]");

	testData[i]			= 100;

	testData[3]			= 3;

	testData[1]			= 1;

	testData[6]			= 2;

	testData()[1]		= 41;

	testData[5]()[6]	= 506;

	testData[5]["a"][1]	= 501;

	testData[5][3][1]	= 511;

	testData[5]()[2]	= 541;

	testData["a"]()		= Serialize("[1:22, '2':0, 'dff': [1:3]]");

	testData["a"]		= "fuck";

	testData["a"][2]	= "a";

	testData["a"]()		= "b";

	testData["a"]()		= "c";

	testData2			= "abc";

	testData["c"]()		= 1;

	testData["c"]()		= testData2;

	testData[2][i][i]	= 2;



	print_r(testData);



	getchar();

	return 1;

}

目前功能可以无错误返回,数据类型值。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值