完蛋了,面向对象成了习惯,做啥题目都来这套。。。
很简单的问题,创建一个带头结点的循环链表。实现三个功能:
创建循环链表,删除循环链表中数据值为3的倍数的节点,显示链表内容。
给大家看看今天早上刚写的热乎的程序,其实就一个CircularLinkList类。CircularLinkList这个名称不大好,将就着用吧,暂时想不到。
第一版:
恩恩,要求干啥就干啥。这是第一反应,也是我交作业的作品。
分别由三个方法来实现
void createCircularLinkList();
void deleteCircularLinkList();
void displayCircularLinkList();
/*CircularLinkList.h*/
struct Node{
int data;
Node *next;
};
class CircularLinkList{
private:
Node *head;
Node *pointer;
public:
void createCircularLinkList();
void deleteCircularLinkList();
void displayCircularLinkList();
};
/*CircularLinkList.cpp*/
#include<iostream>
#include<fstream>
#include"CircularLinkList.h"
using namespace std;
void CircularLinkList::createCircularLinkList(){
Node *newNode;
int newData;
ifstream in("CircularLinkList.data");
//第一个节点的处理
if(in){
//从CircularLinkList.data读入第一个数据
in>>newData;
//创建新节点并让newNode指向新节点
newNode = new Node;
//为新节点赋值
newNode->data = newData;
//让头指针指向第一个节点
head = newNode;
//让pointer指向第一个节点
pointer = newNode;
}
for(; in; ){
//从CircularLinkList.data读入一个数据
in>>newData;
//创建新节点并让newNode指向新节点
newNode = new Node;
//为新节点赋值
newNode->data = newData;
//上一个节点指向新节点
pointer->next = newNode;
//pointer往前进一格
pointer = pointer->next;
}
//最后一个节点指向第一个节点
newNode->next = head;
}
void CircularLinkList::deleteCircularLinkList(){
Node *tmp;
//pointer指向头结点
pointer = head;
/*第一个节点先不判断*/
for(; ;){
//判断的是pointer后面的那个节点
if((pointer->next->data % 3) == 0){
//让tmp指向要删除的节点
tmp = pointer->next;
if(pointer->next == head)
head = pointer->next->next;
//架空要删除的节点
pointer->next = pointer->next->next;
//释放要删除节点的内存空间
delete tmp;
}
else{
//pointer往前进一格
pointer = pointer->next;
//如果pointer再一次指向了头结点则退出循环
}
if(pointer == head)
break;
}
}
void CircularLinkList::displayCircularLinkList(){
pointer = head;
for(; ;){
cout<<pointer->data<<" ";
//pointer往前进一格
pointer = pointer->next;
//如果pointer再一次指向了头结点则退出循环
if(pointer->next->next == head){
cout<<pointer->data;
break;
}
}
cout<<endl;
}
东西虽然算是完成了,调试测试了些特殊情况:
需要删除第一个的情况
需要删除最后一个的情况
需要删除连续两个的情况
做到通过这几项。其他的情况偶就不敢保证了。
至此,交作业的作品已经完成。但是?问题又来了。
如此代码,复用性何在?囧了吧。。。
删除节点只能删除data值为3的倍数的节点。而且是一下子全给删了。。。
这意味这这个List只能为我提供交作业的功能,而不能将来为我所利用。因为实际情况往往复杂而多变,不是删除能被3整除的节点,就是删除能被4整除的节点,还有可能是删除第3个节点以及3的倍数个节点……
我的直觉告诉我不能为了解决某个特定问题而专门创造出一个通用性极差的方法(如上述程序中的deleteCircularLinkList())。更为明智的做法是,创建多个通用方法,通过这些方法的组合,来解决我们面临的问题。这样一来,即使有了新的需求,我们也只需要组合调用已有的通用方法就能解决问题(最坏情况不过就是需要再设计一些通用的方法)。面向对象的思想,提高重用。
提炼一下精华:
n个通用方法>一个专方法
下面我们就按照这个思想重新设计这个List类
ps:细节修改,为了明确方法的作用,我修改了方法的名字。
void create();
void deleteNodes(int StrategyId);
void display();
添加了这几个方法
bool IsStrategyFit(int StrategyId);
bool IsDataMultipleOf3();
bool IsDataMultipleOfN(int n);
/*CircularLinkList.h*/
struct Node{
int data;
Node *next;
};
class CircularLinkList{
private:
Node *head;
Node *pointer;
//判断pointer所指节点是否符合策略
bool IsStrategyFit(int StrategyId);
//判断pointer所指节点是否是3的倍数
bool IsDataMultipleOf3();
//判断pointer所指节点是否是n的倍数
bool IsDataMultipleOfN(int n);
public:
void create();
void deleteNodes(int StrategyId);
void display();
};
/*CircularLinkList.cpp*/
#include<iostream>
#include<fstream>
#include"CircularLinkList.h"
using namespace std;
void CircularLinkList::create(){
Node *newNode;
int newData;
ifstream in("CircularLinkList.data");
//第一个节点的处理
if(in){
//从CircularLinkList.data读入第一个数据
in>>newData;
//创建新节点并让newNode指向新节点
newNode = new Node;
//为新节点赋值
newNode->data = newData;
//让头指针指向第一个节点
head = newNode;
//让pointer指向第一个节点
pointer = newNode;
}
for(; in; ){
//从CircularLinkList.data读入一个数据
in>>newData;
//创建新节点并让newNode指向新节点
newNode = new Node;
//为新节点赋值
newNode->data = newData;
//上一个节点指向新节点
pointer->next = newNode;
//pointer往前进一格
pointer = pointer->next;
}
//最后一个节点指向第一个节点
newNode->next = head;
}
void CircularLinkList::deleteNodes(int StrategyId){
Node *tmp;
//pointer指向头结点
pointer = head;
/*第一个节点先不判断*/
for(; ;){
//判断的是pointer后面的那个节点,而不是pointer
//判断是否符合我们的策略
if(IsStrategyFit(StrategyId)){
//让tmp指向要删除的节点
tmp = pointer->next;
//这个if判断头结点是否被删
if(pointer->next == head)
//头结点被删,重新指定一个头结点
head = pointer->next->next;
//架空要删除的节点
pointer->next = pointer->next->next;
//释放要删除节点的内存空间
delete tmp;
}
else{
//pointer往前进一格
pointer = pointer->next;
//如果pointer再一次指向了头结点则退出循环
}
if(pointer == head)
break;
}
}
//判断是否符合判断策略
//StrategyId 判断进行时所使用的策略
bool CircularLinkList::IsStrategyFit(int StrategyId){
bool isStrategyFit;
switch(StrategyId){
case 1: isStrategyFit = IsDataMultipleOf3();
break;
case 2: isStrategyFit = IsDataMultipleOfN(6);
break;
case 3: isStrategyFit = IsDataMultipleOfN(9);
break;
}
return isStrategyFit;
}
//判断data是否3的倍数
bool CircularLinkList::IsDataMultipleOf3(){
return IsDataMultipleOfN(3);
}
//判断data是否N的倍数
bool CircularLinkList::IsDataMultipleOfN(int n){
return ((pointer->next->data % n) == 0);
}
void CircularLinkList::display(){
pointer = head;
for(; ;){
cout<<pointer->data<<" ";
//pointer往前进一格
pointer = pointer->next;
//如果pointer再一次指向了头结点则退出循环
if(pointer->next->next == head){
cout<<pointer->data;
break;
}
}
cout<<endl;
}
这样一来,deleteNodes方法的功能就不局限于删除data值为3的倍数的节点了。而是可以自己制订策略,来删除符合指定条件的所有节点。
我们只需要添加相应的判断方法,返回bool值表示是否符合条件。
然后在IsStrategyFit(int strategyId)中添加相应的分支即可。
可重用性相对而言是不是提高了许多?
最后来一个总结:
1。可重用性:n个通用方法>一个专方法
2。性能:n个通用方法<一个专方法
因为多了函数的调用,所以性能肯定会有一些下降。
这个大家根据实际情况取舍吧。
抛个砖头,如果大家有兴趣,可以继续探讨一下如何让一个简单的作业程序变成一个真正的可以放到项目里去使用的类。
韦恩卑鄙 a-zhewg @waynebaby:
简单的说 还是把问题题分层
什么是问题的模型。
什么是问题的公共需求。
什么是问题的独特需求。
在你的作业中
模型是循环链表
公共需求是 定位 添加 删除
独特需求是隔3删1
这就很清楚的 要你建立一个对外暴露定位 添加 删除借口 内部以循环链表实现的集合类。
至于独特的需求是什么,只需要对这个集合类进行不同的操作就好了,不需要让这个集合类为独特需求做任何调整
By 威老 in cnblogs