第四章作业 结点指针的回收又利用+排序+查找
2015-05-17 00:08
417 查看
main中
sclass.cpp
sclass.h
#include <iostream> #include "sclass4_11_Node.h" int CNode::sNodeNum=0; void main() { int now; int k; cout<<"1*************************************************."<<endl;//主要观察拷贝构造函数和new以及delete的作用 CNodeArray oCNA1; {//内部作用域,去掉注释可观察到oCN1和oCN2的析构位置 int i; char s[81];//存放暂时获取的结点名字 string str; //CNode oCN1("Zhang San"),oCN2("Li Si"); //oCN2=oCN1;//调用重载的赋值运算符 CNode *poCN1,*poCN2;//定义一个CNode指针 for(i=0;i<5;i++) { cout<<"Input a Node Name or word\"stop\":"; cin.getline(s,81,'\n');//输入字符串作为结点名,str=gets(s); str=s; if(str=="stop") break; poCN1=new CNode(str);//调用一般构造函数新建对象 // poCN2=new CNode(*poCN1);//调用拷贝构造函数新建对象&*poCN1=poCN1传入的是它的地址,它本身参数引用输入 // cout<<oCNA1[0]<<endl; // cout<<*(oCNA1[0].GetStr())<<endl; oCNA1.Insert(*poCN1); // oCNA1.Insert(*poCN2); cout<<"aIndex="<<oCNA1.GetaIndex()<<endl; } cout<<"***********"<<endl; //查找 cout<<"要查找含该字符串的结点位置"<<endl; string look; cin>>look; for(int f=0;f<oCNA1.GetaIndex();f++) { if(look==*(oCNA1[f].GetStr())) { cout<<"************No:"<<f<<endl; } } //排序 for(int j=0;j<oCNA1.GetaIndex()-1;j++) { cout<<"j="<<j<<endl; //cout<<"aIndex="<<oCNA1.GetaIndex()<<endl; cout<<"第一步"<<endl; for(now=j,k=j+1;k<oCNA1.GetaIndex();k++) { cout<<"k="<<k<<endl; cout<<"第二步"<<endl; if((*(oCNA1[k].GetStr()))<(*(oCNA1[now].GetStr()))) { now=k; cout<<"最小的下标为:now="<<now<<endl; } } if(now!=j) { string temp=*(oCNA1[now].GetStr()); str=*(oCNA1[j].GetStr()); poCN1=new CNode(str); oCNA1.Insert(*poCN1,now); str=temp; poCN1=new CNode(str); oCNA1.Insert(*poCN1,j); } } cout<<"排序结果是:"<<endl; cout<<"*(oCNA1[0].GetStr())"<<*(oCNA1[0].GetStr())<<endl; cout<<"*(oCNA1[1].GetStr())"<<*(oCNA1[1].GetStr())<<endl; cout<<"*(oCNA1[2].GetStr())"<<*(oCNA1[2].GetStr())<<endl; cout<<"排序结束"<<endl; //删除一个已有结点 cout<<"删除一个已有的结点CNode结点删除后的回收又利用"<<endl; oCNA1.Delete(oCNA1.GetaIndex()-1); str="123"; poCN1=new CNode(str); oCNA1.Insert(*poCN1); } /* cout<<"销毁结点0"<<endl; oCNA1.Delete(0); cout<<"*(oCNA1[0].GetStr())"<<*(oCNA1[0].GetStr())<<endl; cout<<"*(oCNA1[1].GetStr())"<<*(oCNA1[1].GetStr())<<endl;*/ /*cout<<"*****START*************************************."<<endl; cout<<oCNA1[0];//观察重载运算符的"<<"和"[]"运算符,其中在<<中值传入参数时创建了一个obj的对象,所以创建一个拷贝构造函数,然后当函数结束时,自动的析构它 cout<<"*****END***************************************."<<endl; for(int i=0;i<5;i++) { oCNA1.Delete(i);//注释掉本语句可观察到delete的作用 } cout<<"2**********************************************."<<endl; //第二段作用域主要观察重载的new和delete的调用 { CNode oCN1("Genghis kahan"); CNodeArray *poCN3=new CNodeArray;//调用重载“new” //cout<<"111"<<endl; delete poCN3;//调用重载delete,通过:delete可调用系统delete//为什么当使用delete的时候CNodeArray函数才析构 //cout<<"123"<<endl; } cout<<"3**********************************************."<<endl; {//第三段作用域主要观察《》,=等运算符的重载 CNode oCN1("Genghis khan"),oCN2("11"),oCN3(oCN1); cin>>oCN3; cout<<oCN3; oCN3=oCN2,oCN1; cout<<oCN3; }*/ }
sclass.cpp
#include "sclass4_11_Node.h" CNode::CNode(string str) { m_pStr=new string(str); if(NULL==m_pStr) { cout<<"内存分配失败"<<endl; exit(0);//内存分配失败,直接退出了程序 } m_nodeNum=GetNumber(); cout<<"CNode全新创建结点,No:"<<m_nodeNum<<",Name:"<<*m_pStr<<endl; } CNode::CNode(const CNode &oCN)//拷贝构造函数的参数只有一个,就是同类的其他对象的引用,且不可修改(其参数通常是同一类的const对象),拷贝构造函数必须以引用的形式传递参数的原因是,当一个对象以传递值的方式传入一个函数时,将自动调用拷贝构造;如果一个对象时被传入自己的拷贝构造函数,也将调用它的拷贝构造函数;而函数返回对象时也需要调用拷贝构造函数,这样就可能引起无线循环,而采用引用可以避免这种情况的发生 { m_pStr=new string (*oCN.m_pStr);//oCN是一个对象而oCN.m_pStr是一个指针,外面再加*表示指向这个对象里面的指针指向的内容 if(m_pStr==NULL) { cout<<"内存分配失败。"<<endl; exit(0); } m_nodeNum=GetNumber();//取得结点编号,并赋值给m_nodeNum; cout<<"CNode拷贝创建结点,No:"<<m_nodeNum<<",Name:"<<*m_pStr<<endl; } CNode::~CNode() { cout<<"~CNode销毁结点,No:"<<m_nodeNum<<",Name"<<*m_pStr<<endl; delete m_pStr; } CNode &CNode::operator =(const CNode &oCN) { if(this==&oCN) { return *this; } delete m_pStr; m_pStr=new string(*oCN.m_pStr); if(NULL==m_pStr) { cout<<"内存分配失败。"<<endl; exit(0); } m_nodeNum=oCN.m_nodeNum; cout<<"CNode复制了对象,No:"<<m_nodeNum<<",Name:"<<*m_pStr<<endl; return *this; } const CNode &CNode::operator ,(const CNode &oCN) { return oCN;//直接返回第二操作数 } ostream& operator<<(ostream& scout,CNode& obj) { scout<<"Node Name:"<<*(obj.GetStr())<<",";//若用户自定义的ostream中的引用scout,则也可以使用《 scout<<"Node Number:"<<obj.GetNodeNum()<<"."<<endl; return scout;//ostream类型返回scout } istream& operator>>(istream& scin,CNode& obj) { char s[81]; cout<<"please Enter Node Name:"; scin.getline(s,81,'\n');//getline(scin,*(obj.GetStr())) *(obj.GetStr())=(string)s;//s转化为string对象后再赋值 cout<<"Please Enter Node Number:"; scin>>obj.GetNodeNum(); return scin;//istream类型返回scin } int CNode::GetNumber(void) { return sNodeNum<LEN?sNodeNum++:(sNodeNum=0); } string *CNode::GetStr() { return m_pStr; } int &CNode::GetNodeNum() { return m_nodeNum; } CNodeArray::CNodeArray(int aLength)//构造时将指针全部初始化,指向NULL { for(int i=0;i<aLength;i++) { m_poCN[i]=NULL; } m_aLength=aLength; m_aIndex=0;//当前结点下标设置为0 cout<<"CNodeArray,创建一个结点数组对象,length=:"<<m_aLength<<endl; } CNodeArray::~CNodeArray(void)//~CNodeArray析构函数,确认m_poCN指向的对象的指针所指向的空间是否析构了 { for(int i=0;i<m_aIndex;i++) { if(m_poCN[i]!=NULL) { delete m_poCN[i]; cout<<"delete:m_poCN["<<i<<"]."<<endl; } } cout<<"~CNodeArray:析构完成."<<endl; } //这里设计了很简单的结点插入功能,即只是让数组的CNode指针指向新结点而已。 //为了安全起见,先对插入位置坐判断,如果原来有结点,报插入失败,返回 bool CNodeArray::Insert(CNode &oCN) { if(m_aIndex>=m_aLength) { cout<<"对不起,超过了数组最大下标,不可再插入!"<<endl; return false; } if(m_poCN[m_aIndex]!=NULL) { cout<<"此位置已有结点,不可再插入!"<<endl; return false; } m_poCN[m_aIndex]=&oCN;//重载运算符 cout<<"插入新结点,Pos:"<<m_aIndex<<",No:"<<oCN.GetNodeNum()<<",Name:"<<*oCN.GetStr()<<endl; m_aIndex++; return true; } void CNodeArray::Insert(CNode &oCN,int i) { if(i>=m_aLength) { cout<<"对不起,超过了数组最大下标,不可再插入!"<<endl; } m_poCN[i]=&oCN;//重载运算符 cout<<"插入原有的结点,Pos:"<<m_aIndex<<",No:"<<oCN.GetNodeNum()<<",Name:"<<*oCN.GetStr()<<endl; } //这里不是链表操作,相当于delete一个结点,并让指针为空即可 bool CNodeArray::Delete(int index) { if(m_poCN[index]==NULL) { cout<<"Pos:"<<index<<"=NULL,无需调用delete运算符."<<endl; return false; } delete m_poCN[index];//先释放当前结点应为结点可能指向某一块区域,先把它释放掉再将结点指向空NULL,m_poCN[i]是CNode类型,所以销毁它会自动运行析构函数~CNode() m_poCN[index]=NULL; cout<<"delete:m_poCN["<<index<<"],"<<"Pos:"<<index<<",次位置指向的结点delete成功!"<<endl; /*for(index=index+1;index<m_aIndex;index++)//回收再利用 { cout<<"index="<<index<<endl; m_poCN[index]->ReviseNodeNum(); }*/ m_aIndex--; return true; } CNode CNodeArray::operator [](int i) { if(i<m_aIndex&&(i>=0)) { return *m_poCN[i]; } else { if(m_poCN[i]==NULL) { cout<<"没有元素,出错."<<endl; exit(0); } cout<<"数组越界"<<endl; exit(0); } } void *CNodeArray::operator new(size_t size) { cout<<"调用CNodeArray自定义的new创建对象.\n"<<endl; return malloc(size);//c++在以下三种情况下需要调用拷贝构造函数,当以对象作为函数参数,以值传递的方式传入函数体时;当以对象作为函数返回值,以值传递的方式从函数返回对象时;当用对象初始化另外一个对象时。 }//return 是以值传递所以创建了一个拷贝构造函数 void CNodeArray::operator delete(void *p)//上面已创建后而得到它的地址后就马上析构 { cout<<"调用CNodeArray自定义的delete销毁对象.\n"; free(p); }
sclass.h
#ifndef _SCLASS4_11_NODE_H_ #define _SCLASS4_11_NODE_H_ #include <iostream> #include <string>//使用string类型就要用到string类型 using namespace std; const int LEN=20; class CNodeArray;//向前声明结点类数组类,以便在CNode类中声明为友元类使用 class CNode { friend CNodeArray; friend ostream& operator<<(ostream& scout,CNode& obj); friend istream& operator>>(istream& scin,CNode& obj); public: static int sNodeNum; public: CNode(string str);//结点编号通过调用CreatNumber()函数得到 CNode(const CNode &oCN); virtual ~CNode(); CNode &operator=(const CNode &oCN); const CNode &operator,(const CNode &oCN); int GetNumber(void); string *GetStr(); int &GetNodeNum(); /*void ReviseNodeNum() { m_nodeNum--; }*/ private: string *m_pStr; int m_nodeNum; }; class CNodeArray { friend CNode; public: CNodeArray(int aLength=LEN); virtual ~CNodeArray(void); CNode operator[](int i); void *operator new(size_t size);//size_t是vc中定义的一个类型而不是c++中定义的标准类型 void operator delete(void *p); bool Insert(CNode &oCN);//在结点中插入一个结点 void Insert(CNode &oCN,int i); bool Delete(int index);//在结点中删除一个结点 int GetaIndex() { return m_aIndex; } CNode* operator()(int i) { return m_poCN[i]; } private: CNode *m_poCN[LEN];//结点指针数组用来存放指向结点的指针 int m_aLength;//指针数组长度 int m_aIndex;//结点指针数组中数组的当前下标值 }; #endif
相关文章推荐
- 利用递归查找链表中与数据成员值与形参n相同的结点
- 【二叉树】利用树结点本身指针域遍历二叉树
- 【二叉树】利用树结点本身指针域遍历二叉树
- 数据结构之快慢指针查找链表中间结点
- 利用指针对二维数组进行遍历查找程序
- 巧妙利用两个指针遍历链表——链表中倒数第k个结点
- 在树根结点指针为r的二叉查找(排序)树上删除键值为e的结点
- 利用返回指针值的函数进行查找学生的成绩
- 第四章作业:4.17:建立一个对象数组,内放6个学生的数据(学号,成绩),用指针向数组首元素,输出第2,4,6个学生的数据。
- 【数据结构作业二】写出单链表结点的结构体类型定义及查找、插入、删除算法,并以单链表作存储结构,实现有序表的合并
- 利用Collections工具类查找一个字符串在字符串数组里的位置即其角标
- 灵巧指针与垃圾回收源代码CPtrArray
- 如何利用DOM删除一个结点的某个属性?
- 第六周作业1 -- 利用哈夫曼编码英文字母表
- 【转】Linus:利用二级指针删除单向链表
- 建立一个带附加头结点的单链表.实现测长/打印/删除结点/插入结点/逆置/查找中间节点/查找倒数第k个节点/判断是否有环
- 对整数数组进行二分查找;传数组指针会丢失数组大小信息。
- 第六周作业1-利用哈夫曼编码字母表
- 作业:利用正则表达式将网页内容替换为OMIT
- (整合多篇文章)C++悬垂指针、野指针、内存泄漏和垃圾回收机制