您的位置:首页 > 其它

第四章作业 结点指针的回收又利用+排序+查找

2015-05-17 00:08 417 查看
main中
#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐