vmatrix上的小问题^_^

  1. [Classes and Objects]Array

类中的一个成员函数是要实现数组中从 [from,to) 的排序,类似用上学期学过的选择排序(或者冒泡排序也行)实现.
假如我想把这个对象作为成员函数的一个参数值,应该怎么做?
并且编译的时候一直说XXX does not name a type(在类定义体中的typedef有什么需要注意的地方吗)??

我猜是因为typedef作用域限制??把成员函数实现的时候的返回值改成原来的类型名就可以通过了.

pointer可以直接用private的_data来赋值吗??(int cannot convert to {aka:int}???)**

好不容易通过编译之后标准测试没有过…应该是resize和sort函数没有写对.

  1. [Classes and Objects]Simple Linked List

单向链表:只能从每一个结点开始向后访问,不能访问它之前的结点.

在结点中用最后一个结点的地址作为tail和用最后一个结点的next地址作为tail程序运行结果不一样??
在结点中有些地址相同,可以互换吗???
为什么不可以???调试了一晚上才发现错在哪里了啊!!!头痛…

要将一个int类型转换为string类型,一开始知识简单的加上了’0’,但是这只对于一位的整数有效,如果整数大于等于10,就不能进行转换了.

从网上看到可以利用string stream进行转化,但是stringstream声明的位置不一样运行结果有时会出错!!

比如:

``C

std::string list::toString(void) const {
node* current=head;
std::string str;

while(current!=NULL) {
	int num;
	num=current->data;
	std::stringstream ss;
	ss<<num;
	str+=ss.str();
	std::cout<<str<<std::endl;
	str+="->";
	
	if(current->next==NULL) {
		str+="NULL";
	}
	
	current=current->next;
}

return str;
}

`` C

如果把声明放到外面就会重复输出??

insert函数一开始提交了三遍都有内存泄露的问题,就是一开始先new 了一个node,然后分情况把它连到了链表中,但是一直内存检查过不了…后来分着把他们new出来就过了??

3.[Classes and Objects]Job Manager

在finishOneJob的函数里如果不加判断jobFrontPointer是否为NULL的条件就会有运行错误(也许是因为指针只能释放一次??)

[Operator Overloading]简单的Matrix运算

因为含有指针,所以要重载赋值运算符还要用深复制的策略来写拷贝构造函数,但是在拷贝构造函数调用重载的赋值运算符之前,要先对matrix动态分配空间,否则会出现运行错误.

但是赋值运算符的重载函数里明明是先释放matrix的原有空间然后再对matrix动态分配,就算matrix之前只想NULL,不也会有空间吗??

[Operator Overloading]Fraction

这个题就是非常基本的重载运算符的一道题目,但是因为一开始我把分数的计算想的太过简单了.

就比如加法和减法就采取了最基本的先通分再运算,但是当两个分母过大并且有公因数的时候容易造成溢出;

对分数进行的化简不能只在输出运算符的重载函数中,否则会导致本来可以化简的分数再参与其他运算时还是原来的值,也容易造成溢出;

对于当分母为负数时要将负号调整到分子上.

[Operator Overloading]The Complex class

友元函数不属于类的函数,因此不能得到this指针,函数后面如果加const编译会出错;

重载输入的时候想的过于复杂反而只能得到第一个的输出,原因不太清楚.

[Operator Overloading]Doubly Linked List

  1. 注意!!有的函数可以调用其他函数来实现,但是注意不要造成死循环!!
    比如用数组做参数的构造函数可以调用一个赋值函数,但是一开始写赋值函数的时候又用了构造函数,这样会在函数调用的时候产生栈溢出,导致运行错误.

  2. 而且有的时候会在对链表的遍历过程中忘记让curr指针每次更新,导致陷入死循环出不来.

  3. 值得注意的一点是因为是双向链表所以每次对链表进行修改的时候还要记得将下一个指针的prev指针也要更新,一开始都忘记这一点了…当成单向链表去写了…

  4. clear函数如果依次调用erase函数会出现运行错误??如果改掉clear函数erase函数不修改也能正常运行,好奇怪.

  5. 还有一点是用数组作为参数的构造函数中,我没有考虑数组是一个空数组的情况,也就是长度为0,数组的首地址实际上并没有分配空间,但是我直接就动态分配了一个头节点,在测试样例中有一例会出错.

``C

void list::erase(int position) {
listPointer curr = head;
listPointer temp = head;
int i;

if (position < 0 || position >= _size) {
	return;
}
else if (head == NULL) {
	return;
}
else if (position == 0) {
	if (head != NULL) {
		temp = head;
		head = head->next;
		if (head != NULL)
			head->prev = NULL;
		delete temp;
		temp = NULL;
		
		_size--;

		return;
	}
}

else if (position == _size - 1) {
	temp = tail;
	tail = tail->prev;
	tail->next = NULL;
	delete temp;
	temp = NULL;
	_size--;

	return;
}

curr = at(position);


curr->prev->next = curr->next;
curr->next->prev = curr->prev;
delete curr;
curr = NULL;

_size--;

return;
}
void list::clear(void) {
int i;

for (i = 0;i < _size;i++) {
	erase(i);
}
return;
}

``

6.我突然发现,这个erase(i)其实有问题,因为第一次执行完erase(0)删除了头节点之后,再需要删除的下一个结点依然应该是erase(0),而不是erase(1),这样会导致中间有很多结点被跳过了,没法删除,并且到后面会超过链表长度,直接return。

另外还有几个函数需要用到在链表的动态变化过程中进行删除,这样的下标应该设置成如下形式:

``C

list& list::remove_if(bool (*condition)(listPointer)) {
listPointer curr = head;
int i;
int index = 0;

if (head == NULL) {
	return *this;
}

for (i = 0;i < _size;i++) {
	if ((*condition)(curr)) {
		curr = curr->next;
		erase(index);		//erase(i) is wrong!!!!
	}
	else {
		curr = curr->next;
		index++;
	}
}

return *this;
}

``
而且还有一个很不好的地方就是在erase的循环语句执行完成之后没有将head和tail指向空,这样在输出的时候也会出现问题。

7.还有在重载+=的运算符的时候一开始只是简单的想成了把两条链表连起来就行了,只用了
tail->next=other.head;
_size+=other._size;
但是还要满足other的头指针指向tail,tail指向整条链的最后。

最后改成了这个样子:

``C

list& list::operator+=(const list & other) {
if (other.head == NULL) {
	return *this;
}
else {
	tail->next = other.head;
	other.head->prev = tail;
	_size += other._size;
	tail = at(_size - 1);
	tail->next = NULL;
}


return *this;
}

``
但是还是运行出错。。。

它报错的时候说引发了未经处理的异常:tail是nullptr。

怎么会啊!!!
我改成了这个样子:

``C

if (other.head == NULL) {
	return *this;
}
else if (head == NULL) {
	*this = other;

	return *this;
}
else {
	tail->next = other.head;
	other.head->prev = tail;
	_size += other._size;
	tail = at(_size - 1);
	tail->next = NULL;
}

return *this;

``

还是说tail是一个空指针…哭了…叶嘉琪搞得我好惨…

8.我觉得有问题的几个函数就是insert(),erase(),还有operator +=的重载.

[Classes and Objects]D&A Static Linked List

这道题一开始没有看明白它是什么意思,后来发现它和离散课上老师讲的一个数组其实是一样的.

这里的指针并不是一个真实的地址,但是可以用来指向下一个元素,就是指向下一个结点的下标.

所以这个静态链表其实可以分为两部分,一部分是使用了的链表,另一部分是没有使用的空结点所组成的链表.因此在private的数据中需要两个指针,一个指向正在工作的head,另一个指向空结点的head。

并且在初始化的时候将head初始化为nullpointer,将empty_head初始化为0。然后将结点数组的每一个元素的data设置为默认的参数值,但是下一个指针依次指向相邻的下一个元素。这样就连成了一条全为空的空结点。

想明白了之后我觉得应该挺容易实现的,毕竟是静态的链表.不再需要动态分配内存,错误也会少一点。画一画图应该就能理解了。

但是提交的时候程序出了几个问题:

很奇怪的一个地方是insert函数不知道为什么在erase后重新在头上插入结点时有些时候会出错,我中间又输出了一下,成了这样:
在这里插入图片描述

前几个的插入都是正常的,但是不知道为什么最后一个插入就变成了全是3???

找了好久都没有找到错误,直到后来输出了一下head和empty_head:

在这里插入图片描述

发现有些时候head和empty_head的地址相同,应该是这里出错了。

调试了两个多小时,发现真的要好好的画图!!不然搞得顺序都是反的…

最后找出来应该是erase在position=_size-1的时候出的错。

最后找出来的错误…居然是在重载赋值运算符的时候…把一个empty_head不小心写成了head…检查的时候也没想到会在这里出错,一直在查insert和erase。

我可能是个傻子了。

[Inheritance]Zoo (eden)

这个题我首先遇到的问题是在提交的时候文件的包含关系总是弄不对。因为Animal和Cat、Dog的定义和实现是放在一起的,但是Zoo的头文件要包含Animal.h,就会导致编译的时候出现重复定义的问题。之前看题目给的头文件都是有几行这样的内容:
#ifndef XXXXX
#define XXXX

#endif

后来查了一下明白,这样可以避免重复定义的错误,并且这里必须要用到,否则会重复定义两遍。

虽然我还没搞明白什么是虚函数,但是试着写了写过了标准测试,但是随机测试没有过。

因为这道题要求能够按添加动物的顺序对他们进行print,所以要存储他们插入的顺序,我用了一个数组,如果是猫就是设置为1,是狗就设置为0。但是在删除动物的时候没有对Order数组进行相应的修改,所以会在调用print函数的时候会出错。
一开始zoo中用来保存动物的变量其实是个Animal,但是导致编译错误,好像是因为声明了纯虚数所以不能创建类的实例??
所以只能将Cat和Dog分开来存储,但这样又导致再修改的时候比较困难。
后来重新看了main函数,发现它没有Dog和Cat交替添加的情况,所以没有必要再另设一个数组储存先后顺序。
而且题目中说相同的动物只能添加一次,我就再添加之前另写了一个比较是否有重复元素的函数,但是再一个随机测试里出错了。据说好像比较的不是对象的数据,而是两个对象的地址是否相同??

[Operator Overloading]Big Integer Add & Subtract

这道题里我一开始声明了一个string nums,然后直接用nums[i]的形式对nums进行了修改,但是这样在运行的时候就会出现错误,必须要改成append或者是+=的形式才可以。编译器的提示是string类型out of range,应该是在没有初始化的时候不能用下标的形式去访问,这样不安全。

(并且这里的大整数加减跟上个学期写过的一道程设题差不多,就是先按位进行加减,然后把它进行相应的进位或是借位,化成是一个有效的数字形式。还要注意内存的分配和释放。)

[Classes and Objects]Student

这个Date类中需要用到将格式类似“2017-5-7”的日期转换成日期的信息,所以需要用‘-’将字符串进行分割。

利用string stream,但是遇到了一个问题是无法清空一个string stream,temp.clear()没有用。

[Classes and Objects]Mediator Pattern

这道题讲到了中介者模式。
中介者模式是一种行为模式,用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

中介者模式包含了抽象中介者(无法实例化为对象,提供函数接口)、具体中介者(抽象中介者的子类);抽象同事类、具体同事类。

“每一个具体同事类都包含了一个具体中介类” 这句话应该怎么理解??
[外链图片转存失败(img-0qPuwRJm-1562071693919)(https://design-patterns.readthedocs.io/zh_CN/latest/_images/Mediator.jpg)]
[外链图片转存失败(img-GwTzNOTl-1562071693919)(https://design-patterns.readthedocs.io/zh_CN/latest/_images/seq_Mediator.jpg)]

这里有一个比较完整的代码,可以看一看

多态的时候记得要有虚析构函数!!否则会当作base类去析构,子类其余的内存会泄露!!

pair 的用法:

pair可以将两个数据合成一个数据(就是离散课上老师讲关系的时候提到的一种数据类型),这两个数据可以不是同一种类型。
实质上是一个结构体,两个成员变量是first和second(可以直接使用)。
可以通过make_pair直接构造一个pair。

如果某个函数需要返回的数据不止1个,可以利用pair。

list的用法:

list顺序存储元素,但是一开始我不明白什么是iterator(迭代器)。

后来查了资料发现,C++STL中有许多容器,比如vector也是一种容器。但是对不同种的容器经常会有许多相似的操作,比如元素的查找并且返回。

如果容器可以提供一个访问元素的统一接口,就可以实现操作函数的复用,而不必对于每一个容器都写一个相同功能的操作函数。

所以我觉得迭代器的本质与指针比较像。

更多有关iterator的小知识

使用的时候大致如下:

[Template] Template Specification

这个题我有一点不明白,如果把cmp函数模板的声明中的形参加上了const,结果反而会不对。

``C

template <typename T> bool cmp(const  T& a, const T& b);
template <typename T> bool cmp(const  T* a,const  T* b);
bool cmp(const  char* a, const char* b);

``

main函数里面的测试有一些会先对变量进行修改,然后再用他们的地址作为实参进行比较。
但是在cmp函数里明明没有对T类型的变量进行修改,为什么会出现这种错误??

(注意:strcmp函数在相等的时候返回的值是0!!!)

[Classes and Objects]Array

复习的时候想重新写一遍这道题,一开始选择的排序方式是选择排序,后来想换用冒泡排序更简单,但是要注意循环变量的取值,因为排序的区间是一个左开右闭的区间。

``C

	for(i=from;i<to-1;i++) {
	for(j=from;j<to-i-1+from;j++) {
    	if(_data[j]>_data[j+1]) {
        	data_type temp;
        		
       		temp=_data[j];
      	    _data[j]=_data[j+1];
           _data[j+1]=temp;
   	 }
  }
}

``

[Classes and Objects]Class for Time

对于用stringstream来进行数据类型的转换,如果要通过同一个stringstream对象来进行多次转换,要ss.clear()!

单例模式:

一个类只能由一个对象,如果多次调用getInstance()得到的是相同的。
因此将构造函数放到private中,不允许私自调用构造函数创建对象。而且getInstance()和instance均应该为static类型。

赋值运算符重载(数据成员为char*)

要考虑一种情况A=A,如果先把左边的内容delete之后右边因为是按引用传递,也会变成空的,所以最后赋值的结果就会是空。
还有一种是用一个空指针进行赋值,一开始有一个小地方没有注意导致出现了段错误,一开始就定义了变量len=strlen(object.m_pData),但是如果strlen中的参数为NULL的话会出现运行错误,把这句声明放到判断是否为空指针后面就好了。

单链表:

复习的时候重新写了一遍,但是随机测试有两个过不了,也看不出来哪里错了。
注意:
拷贝构造函数如果要利用赋值运算符,一定要先给head和_size赋初值!!!否则在调用赋值运算的函数时对head进行判断是随机值,遇到了运行错误。
对链表的排序我用了冒泡排序,就是要注意结点指针变量的声明位置。

随机测试一个过不了的原因是time limit,我发现之前用的选择排序可以过,换成冒泡排序就不行。

``C

const char* a="HUHU";
const char* b="HUHU";

if(a==b)
	cout<<"Equal!"<<endl;

``

两个const char* 类型的变量可以直接进行比较??

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值