What i am looking for? What is the goal in everyone's life?
I always ask myself, and therefore, the goal i am struggling for in this period of my Further education test may be the one i misunderstand.
And today, after a long time when i could not bend myself to this task, i really understand what i am searching for during these meaningful but suffering days.
Every one has gift, may be strong or handsome or with something other, and it dose not matter which other gifts i have possessed or praying for. But the one i really want, is if anything without which i can do nothing even i get all other gifts i want.
Yeah , perseverance is something i have lacked of, and if i would learn such an ability, i can successfully do anything. This is why i have been training myself in this difficult and hopeless task, and since there is still 80 days left, with perseverance , i can get through it and kick the goal.
时间越来越紧了,原定的十月份计划不利于复习。原定的前2周计划顺利完成。

为了赶上进度,从10月15号起的20天定义为“基础集训”,接下来的3周将会是繁忙的3周,并且中途不安排休息天。总目标是,将自己提高到考研的水平。

任务一, 李永乐的高数复习全书2007年版。
任务二, 计算机体系结构,和各书的课后习题,相关试题。
任务三, 胡敏的200阅读和新东方的作文教程,以及单词扩展到8000。
任务四, 政治的复习题一套。

任务很重,也都是关键中的关键,拿下这些才可以安心的安排后面的复习进程。
I was waken up by aboring noises made by drill very early this morning. The big house near my room once used for garbage disposal plant was dismantling, and was anticipated to rebuild which would make even more noises.
It should be some where and some people who come up against it. But we don't know where to go, it seems no department would take charge of such things, because in china government always likes to say something rather than to do something.
So the only settlement is getting up earlier than before, and make sure not going mad with these noises. Maybe it is good for my study.
we went to IKEA for shopping this afternoon by bicycle, as Zhou had had no diet but fruit since three days ago. It was along way to ride to IKEA which sits around the northeast part of SiHuan.
She looked for a comfortable chair, but we have a sofa instead of it, the one can totally involve you.
One afternoon's dissipation made me guilty, and i learned this night late with high efficiency until the classroom was closed.
If you asked me why i went to tsinghua for studing, while there are many well conditioned classrooms in BJMU, i would tell you the truth that is because of canteens.
During National Day, Third Building and Sixth Building were both closed, so they came to BJMU this morning. When they stepped into YiFu Building, they were surprised to find that it is quite good for studing , and asked me why i spent half an hour every day to go to tsinghua.
At lunch time, they found the answer, the food was terrible, and just a morsel.
Zhao said:" We were still lucky, because when we go back to tsinghua after these days, we will find how happy we are!"
Tomorrow is my sister's wedding day, it will be an exciting day. But unfortunately, i must stay in beijing these days, preparing for my big exam, which makes me really sad.
Also, it is National Day tomorrow, on which of 1949 our country was liberated.
However, it will be just a normal day for me, as every busy day that i spent on studing.
十月份任务
第一周:政治;GRE单词。
第二周:计算机组成;操作系统。
第三周:体系结构;阅读理解。
第四周:数据结构;阅读理解。
People have dreams, so do i, but only a few of those can come to truth. Several days ago, when i step into my 24th, i feeled so dejected, for time slipping away, dreams still being dreams.
Yesterday, i don't remember why we come to the topic of dreams, when were having fried chicken around the west gate of Tsinhua. What i only know is i still have my courage to face my dreams, to tell it to my friends, so glad that i havn't been lost in the disappointing world.
Every step was a step towards regaining my life. Fulfiling my dream was becoming a reality.
Mrs Yu is my maths' teacher when i was in elementary school, who had successfully made me believing that i have somewhat gift in mathematics. Such confidence had been a great benifet of me.She is the most repectable teacher i had ever met.
I remembered her when XiaoYuan could not work out a mathematica problem this afternoon, which at last was solved, but he looks dejected. Then i told him he was good at maths, and was the one with great potential in maths, just like what Mrs Yu had told me many and many times.
And i still believe i do have some genius of maths, and i believe i can get through this challenge.
When i rushed into the conventional study-room of Building Six at 7:40, i found there is no seat left, neither do ZhaoWei. so we decided to move to Building Three, a comfortable place, not so many students, quiet and clean, in which the air is much more brisk than that of Building Six.
YangJing came to study in the evening, and She said she like the place too.Ye, we make a wonderful choice, at 9:30 when i left, i found we had already brought many guys here.
My roommate Zhou, take back a box of mooncake, made by DaoXiangCun, which is a famous shop of dessert. It was so delicious, the first mooncake i had ever eaten this year. Mid-autumn fesival is coming soon.
We had my birthday dinner at ShangYuanJu, simply and comfortably.
I recieved a pretty gift that i having been waiting for five months, a piggybank, a symbol of my birthyear, a saying which could bring me good luck.
At all , i am twenty four now.
It began to rain before we go to canteen for supper, a bit cold but not very heavy, just declaring the coming of autumn.
When i was a little bored up with the rain about nine o'clock, my roommate sent me messages in which she worried about the rain.So it became not so cold, making me warm enough for a venture,riding in the rain, the same thing i had done one night last year, lonely.
The soon before i just would head out into the rain, XiaoYuan, one of my learning friends who learn together in the same classroom for the same purpose, caught me up, and gave me his umbrella.
"what about you and your notebook?"I asked.
He said it is much easier for him to go back, there are two guys would walk with him, just a few minutes. Though I still worried about his notebook, but he insist of it.
The way back to home riding with an umbrella was quite easy and different, as though the rain was falling in my hometown and i was still in my childhood, always running into the southern rain.Loneness made me so sensible.
Gigi and Ogre came to me this afternoon,so i had to have a break, putting my maths' exercises aside, which need maybe more than five days to accomplish.
Before supper, we played billiards for about an hour at LanQiXing, and i made a call to LiFei, who was in a basketball match, said sorry for his absence.
Then we have a wonderful dinner at HuangJiHuang, where i just had another dinner the day before yesterday with my roomate, but it is absolutely a good place for dining together. We discussed a trip during National Day, maybe TianJing or BaoDing is a reasonable place for us.
But i won't go out, i even have rejected my sister's wedding invite because of my studying plan, which must be a great pity to me all of my life.
八月份的任务大部分都拖了,一方面效率,一方面任务量可能太大了;为了踏实起见,打算九月份主要就完成这些未完成的任务吧,该堵窟窿了。

第一周
因为研友需要线代的答案,打算这周做掉,估计会因为搬家,拖到下周;
GRE单词

第二周
操作系统英文版;
GRE单词

第三周
高等数学辅导书
从这周开始英语日记

第四周
体系结构
六级卷子
压力越来越大,因为每个计划周都有完不成的任务,事实上这周学习的内容依然属于七月份的计划。

造成计划拖欠的原因,一方面确实来源于人性的脆弱——缺乏意志,直接表现在6000个单词直到这周才可能完全完成,而按照计划,8月份应该拓展到GRE词汇,尽量提高英语,至少考不上,也学了点实在的东西;当然计划的打乱,也来自于不可预计的突发事件和不可估量的任务量,单计算机原理一门课,我已经看了整整2000页的书了,而且还没有真正的接触参考书,只能说制定粗的总计划时,并不了解这门课程,如果将来考上,可以指点别人的时候,会多出很多经验。

不过有一点还是令人高兴的,终于感觉进入状态了,无论是记忆力还是意志力都在恢复。这周的计划比较单纯,只是看《计算机设计与组成》的郑纬民翻译版,以及最后的2000个单词,目前看来这周完成这些任务还是比较乐观的。八月份的主要任务是概率论和数理统计,操作系统和词汇,以及打算新加入的英语阅读训练和高数基础的巩固(尽管sam认为高数辅导应该给本科生准备期末考试用的,我还是打算充分利用它来作为一个基础的巩固,再高的楼离开稳固厚实的地基都是空中楼阁),其中《操作系统概念》因为是英文版,所以必须至少延迟一周,等英语词汇巩固一遍,下面安排接下来三周的具体任务。

第二周
《概率论与数理统计》1-8章 包括习题;
巩固刘毅10000及考研单词,保持每天2个小时单词背诵。
六级考试的英语卷子,做了它!

第三周
《操作系统概念》每天保持8个小时左右,才有可能在6天内看完,不过我对操作系统的周边还是了解比较多,应该不难;
做一些线性代数的习题。一个小时差不多。
利用奇迹英语背 GRE核心词汇。同时每天还是巩固考研单词一组。

第四周
考试虫的《阅读基本功》,为做阅读训练准备;
《高等数学辅导》
GRE核心词汇。

八月份过后,数学基本上算完成了全新的学习,专业课,学习了一半,压力啊,很多人都已经在这个时候完成了第一遍的复习,开始做题了。加油!
8-4 用邻接矩阵表示图,若图中有1000个顶点,1000条边,则形成的邻接矩阵有多少矩阵元素?有多少非零元素?是否稀疏矩阵?


形成的邻接矩阵有10^6个元素;如果是有向图则拥有1000个非零元素,若是无向图则有1000×2=2000个非零元素;是稀疏矩阵。


8-5 用邻接矩阵表示图时,矩阵元素的个数与顶点个数是否相关?与边的条数是否相关?

矩阵元素的个数与顶点个数相关。非零元素与边的条数相关。


8-6 有n个顶点的无向连通图至少有多少条边?有n个顶点的有向强连通图至少有多少条边?试举例说明。

n个顶点连通,如果将n个顶点排成一直线,则很容易知道,至少需要n-1条边才能把它连通。
还是和刚才一样,只不过多一条边,将首尾连起来,使得从每个定点开始都可以回到该顶点。
例子已举。


8-7 对于有n个顶点的无向图,采用邻接矩阵表示,如何判断以下问题:图中有多少条边?任意两个顶点i和j之间是否有边相连?任意一个顶点的度是多少?

图中的边数等于邻接矩阵中非零元素的一半;查看矩阵中E[i][j]或者E[j][i]是否等于零,零的话不联通,反之连通;假设要观察顶点i的度,只要查看i行有多少个非零元素,即为i的度(如果查看i列也一样,因为无向图的邻接矩阵是行列对称的)。


8-9 试扩充深度优先搜索算法,在遍历图的过程中建立生成森林的左子女——右兄弟链表。算法的首部为
Void Graph::DFS(const int v, int visited[], TreeNode< int > *t)
其中,指针t指向生成森林上具有图顶点v信息的根结点。


答案建立生成森林的主函数里的q,定义很奇怪。还是老老实实按照书中DFS的定义来写。
声明:不写模板了。可以直接修改TreeNode的指针.

void Graph::DFS(){ //主过程
int* visited=new int[n]; //n为图中顶点的个数
for(int i=0;i< n;i++)visited[i]=0; //初始化辅助数组
Tree< int > &T; //这里要不要写成 Tree T? 还是迷糊
DFS(0,visited,T.root); //从顶点0开始构建生成森林
delete[] visited;
}

void Graph::DFS(const int v, int visited[], TreeNode< int > *t){
t.SetData(GetValue(v)); //访问该顶点,拷贝值到相应森林结点。
visited[v]=1; //修改为已访问
int w=GetFirstNeighbor(v); //找到顶点v的第一个邻接顶点w
t=t->FirstChild; //t指向t的左子女
while(w!=1){ //有邻接顶点
if(!visited[w]) //如果没有访问过
DFS(w,visited,t); //从该顶点开始建立生成森林
w=GetNextNeighbor(v,w); //找到v的下一个邻接顶点
t=t->NextSibling; //同时把t指向t的右兄弟
}
}



8-10 用邻接表表示图时,顶点个数设为n,边的条数设为e,在邻接表上执行有关图的遍历操作时,时间代价是O(n*e)?还是O(n+e)?或者是O(max(n,e))?

必须要顺邻接表的顶点表挨个检查,并且沿着每条边向下遍历,所以时间代价为O(n+e)。


8-16 试证明在一个有n个顶点的完全图中,生成树的数目至少有2^(n-1)-1

这题有如下疑问
首先生成树的根固定么?如果不固定的话,就相当于将这n个顶点得到一个排序序列,就是生成树了。p(n)显然是答案,当然p(n)永远都大于2^(n-1)-1.这样的解答貌似太简单了。
然后我们假设必须从某个顶点开始,作为生成树的根,那么问题就变成剩下的n-1个顶点,做一个排序序列,那么显然就是比较p(n-1)与2^(n-1)-1。而这个显然必须在n>=5时才能成立,好像又不对。
迷惑中。


8-18 利用Dijkstra算法的思想,设计一个求最小生成树的算法。

计算连通网络的最小生成树的dijkstra算法可描述如下:将连通网络中所有的边以方便的次序逐步加入到初始为空的生成树的边集合T中。每次选择并加入一条边后,需要判断它是否会与先前加入T的边构成回路。如果构成了回路,则从这个回路中将权值最大的边退选。

具体的实现,答案的程序看不太懂。并且从这里开始暂时不把数据结构的答案放到网上了。因为迷糊的东西太多了。
今天已经20号了,7月份满打满算还剩11天,之前的20天,虽然看书的热情很高,但总是各种各样的原因导致许多时间被其他事情占用,又加上最近几天出现了点消极念头,所以本月的计划任务告急。良好的开端就是成功的一半,为了达到这种“开门大吉”的效果,决定将7月份最后11天调整为冲刺计划,史称“吐血大跃进”。

简单的说,本次大跃进的手段就是在一定的时间内不停地看同一种科目,直到吐了为止。

第一个要完成的目标就是高数,目前为止看到完第5章,除2道题有困难外,都还算顺利.上册还剩2章,加上下册的5章,一共是7章。按照之前的高数速度估计,一天12小时计可以完成2章左右,计划从21号到23号,3天时间完成任务。

第二个任务就是单词,这十一天,除了每天仍然要保持250单词/天外,专门抽出24号和25号两天,按最低效率算,每小时100个单词,背15小时,两天可以搞定3000个单词。

接下来的任务更艰巨,26,27号两天之内无论如何都要结束《数据结构》和习题。然后28,29号,完成《计算机原理》,翻过一边就行,不管看不看的懂。30,31号,看完电子版的汇编教材。

完成这些任务后,放风2天。
7-10 假定用一个循环链表来实现一个有序表,并让指针head指向具有最小关键码的结点。指针current初始时等于head,每次搜索后指向当前检索的结点,但如果搜索不成功则current重置为head。试编写一个函数search(head,current,key)实现这种搜索。当搜索成功时函数返回被检索的结点地址,若搜索不成功则函数返回空指针0.请说明如何保持指针current以减少搜索时的平均搜索长度。

思路:定义搜索函数为类的公共函数。并且这个有序循环列表按key值从小到大排列。
 ListNode< Type >* Search(ListNode< Type >*head,ListNode< Type > *current,Type key){
if(key < current->data ) //key小,在前半段,递归调用.
return current=Search(current,head,key);
while(key > current->data && current!=head)
current=current->link;
if(current->data != key)
return NULL;
else return current;
}


7-11 考虑用双向链表来实现一个有序表,使得能在这个表中进行正向和反向的搜索。若指针p总是指向最后成功搜索到的结点,搜索可以从p指示的结点出发沿任一方向进行。试根据这种情况编写一个函数search(head,p,key),检索具有关键码key的结点,并相应的修改p。最后请给出搜索成功和搜索不成功时的平均搜索长度。

思路:类似上题
 ListNode< Type >* Search(ListNode< Type > *head,ListNode< Type > *p,Type key){
if(p->data > key)
while(p->data > key&&p !=NULL)p=p->llink;
if(p->data < key)
while(p->data < key&&p !=NULL)p=p->rlink;
if(p->data == key)
return p;
else{ p=head;reutrn NULL;}
}


7-14 试说明如何利用并查集来计算无向连通图中连通子图的个数。

1.以每个顶点为一个集合,初始化
2.边作为等价对,建立并查集
3.最后得到的集合个数就是连通子图的个数。


7-16 有n个结点的二叉搜索树具有多少种不同形态?

这个题和 问 在给定中序序列下的树,可以有多少种前序遍历。
答案是一样的1/(n+1)Cn/2n


7-18 在二叉搜索树上删除一个有两个子女的结点时,可以采用以下三种方法:
(1)用左子树Tl上具有最大关键码的结点X顶替,再递归地删除X。
(2)交替地用左子树Tl上具有最大关键码的结点和右子树Tr上具有最小关键码的结点顶替,再递归地删除适当的结点。
(3)用左子树Tl上具有最大关键码的结点或者用右子树Tr上具有最小关键码的结点顶替,再递归地删除适当的结点。可随机选择其中一个方案。


声明:均作为类函数加入,为减少篇幅,省略模板结构。并且假设所删除的结点一定是含有两个子女的。
(1)利用左子树上最大关键码结点代替。
remove(BstNode< Type > *ptr){
if(no child)
直接删除
BstNode< Type > *temp;
temp=Max(ptr->leftChild);
ptr->data=temp->data;
remove(temp);
}


(2)
设置一个参数来判断什么 顶替方案
7-1 设A={1,2,3},B={3,4,5},求下列结果:
(1) A+B (2)A*B (3)A-B
(4) A.Contains(1) (5)A.AddMember(1)
(6) A.DelMember(1) (7)A.Min()


(1)A={1,2,3,4,5}
(2)A={3}
(3)A={1,2}
(4)1
(5)A={1,2,3}
(6)A={2,3}
(7)1


7-2 试编写一个算法,打印一个有穷集合中的所有成员。要求使用集合抽像数据类型中的基本操作。如果集合中包含有子集合,各个子集合之间没有重复的元素,采用什么结构比较合适。

采用广义表的结构会比较好,就像广义表的遍历操作一样,采用递归。
template< class Type >class Set{
int Contains(const Type x);
int SubSet(Set< Type >& right);
int operator ==(Set< Type >&right);
int Elemtype();
Type GetData();
char GetName();
Set< Type >* GetSubSet();
Set< Type >* GetNext();
int IsEmpty();
};

ostream& operator<< (ostream& out,Set< Type >){
t.traverse(out,t);return out;
}

void traverse(ostream&out, Set< Type >s){
if(s.IsEmpty()==0){
if(s.Elemtype()==0)out<< s.GetName()<< '{';
else if(s.Elemtype()==1){
out<< s.GetData;
if(s.GetNext()!=NULL)out<< ',';
}
else{
traverse(s.GetSubSet());
if(s.GetNext()!=NULL)out<< ',';
}
traverse(s.GetNext());
}
else out<< '}';
}

除了最后一行外,全部照抄的参考答案。题目没意思,懒得做

7-3 当全集合可以映射成1到N之间的整数时,可以用位数组来表示它的任一子集合。当全集和是下列集合时,应当建立什么样的映射?
(1)整数0,1,...,99
(2)从n到m的所有整数,n<=m
(3) 整数n,n+2,n+4,...,n+2k
(4)字母'a','b','c',...,'z'
(5)两字母组成的字符串,其中每个字母取自'a','b','c',...,'z'.


假设不设置监哨点
(1) i={0,1,...,99}一一对应即可
(2) n->0,n+1->1,n+2->2,...,n+(m-n)->m-n 即可
(3) n->0,n+2->1,n+4->2,...,n+2k->k 即可
(4) 'a'->0,'b'->1,...,'z'->25
(5) 'aa'->0,'ab'->1,...,'zz'->675

7-7 给定一个用无序链表表示的集合,需要在其上执行operator+(),operator*(),operator-(),Contains(x),AddMember(x),DelMember(x),Min(),试写出它的类声明,并给出所有这些成员函数的实现。

思路:模仿教材中有序链表表示集合的类结构,写无序链表表示方法,无序链表在删除和加入时无序做过多操作,但是在求最大最小合并等操作里,要扫描全部链表。交并等集合运算时要注意是否有相同元素.
template < class Type >class SetList;
template< class Type >class SetNode{
//这部分参考教材
friend class SetList< Type >;
public:
SetNode(const Type& item)
:data(item),link(NULL);
private:
Type data;
SetNode< Type >* link;
};

template< class Type >class SetList{
//这部分参考教材
public:
SetList();
~SetList();
SetList< Type > &operator+(SetList< Type >& right);
SetList< Type > &operator*(SetList< Type >& right);
SetList< Type > &operator-(SetList< Type >& right);
int Contains(const Type &x);
int AddMember(const Type &x);
int DelMember(const Type &x);
Type & Min();
private:
SetNode< Type > *first,*last;
}

template< class Type >SetList< Type >& SetList< Type >
::operator+(SetList< Type >& right){
SetNode< Type > *pb=right.first->link; //目标链
SetNode< Type > *tmp=pa=first->link; //tmp暂存first
SetNode< Type > *pc=first; //新加入
int diff; //判断元素是否在A集合中出现
while(pb!=NULL){
diff=1; //初始置为 不在A集合中出现
for(pa=tmp;pa=pa->link;pa!=NULL)
if(pb->data==pa->data){
//如果相等,pa直接到链尾
pa=last->link;
diff=0;
}
if(diff==1)
pc=pc->link=pb; //加入pb
pb=pb->link;
}
pc->link=tmp;
//原来的A链加入新链的链尾
return * this;
}

template< class Type >SetList< Type >& SetList< Type >
::operator*(SetList< Type >& right){
SetNode< Type > *pb=right.first->link; //目标链
SetNode< Type > *tmp=pa=first->link; //tmp暂存first
SetNode< Type > *pc=first; //新加入
int diff; //判断元素是否在A集合中出现
while(pb!=NULL){
diff=1; //初始置为 不在A集合中出现
for(pa=tmp;pa=pa->link;pa!=NULL)
if(pb->data==pa->data){
//如果相等,pa直接到链尾
pa=last->link;
diff=0;
}
if(diff==0)
pc=pc->link=pb; //加入pb
pb=pb->link;
}
return * this;
}

template< class Type >SetList< Type >& SetList< Type >
::operator-(SetList< Type >& right){
SetNode< Type > *pb=right.first->link; //目标链
SetNode< Type > *pa=first; //this链
SetNode< Type > *tmp;
while(pb!=NULL){
for(pa=first;pa=pa->link;pa->link!=NULL)
if(pa->link->data==pb->data){
如果B中有元素与A相等,则删去A中的该元素
tmp=pa->link;
pa->link=pa->link-link;
delete tmp;
pa=last;
}
pb=pb->link;
}
return * this;
}

template< class Type >int SetList< Type >
::Contains(const Type &x){
SetNode< Type > *p=first->link;
while(p!=NULL)
if(p->data==x)
return 1;
else p=p->link;
return 0;
}

template< class Type >int SetList< Type >
::AddMember(const Type &x){
int i=Contains(x);
if(i==1)
return 0;
else{
last->link=new SetNode(x);
last=last->link;
return 1;
}
}

template< class Type >int SetList< Type >
::DelMember(const Type &x){
SetNode< Type > *p=first->link,*q=first;
while(p!=NULL){
if(p->data==x){
q->link=p->link;
if(p==last)last=q;
delete p;
return 1;
}
else{
p=p->link;
q=q->link;
}
}
return 0;
}

template< class Type >Type& SetList< Type >::Min(){
//求集合中的最小元素.
SetNode< Type > *p=first->link;
if(p==NULL){
//如果是空表返回错误;
cout<< "空表"<< endl;
return;
}
Type minnum=p->data;
p=p->link;
while(p!=NULL){
if(minnum > p->data)
minnum=p->data
p=p->link;
}
return minnum;
}
以后每月分为四个阶段,按周分配学习任务。每周学习六天,休息一天,感觉不能老看书。

这个月的内容很重,除去总计划外,还必须完成很多额外的任务,没办法,时间很紧迫,没有学过的东西太多了,真恨不得把书都吃进去算了,必须提高每个学时的学习效率才行。
  • 高等数学同济版教材上下册
  • 80x86汇编语言程序设计教程(电子版)
  • 微型计算机的基本原理与应用
  • 数据结构剩余的四章
  • 英语六级的一些卷子(当基础练了,别浪费)
  • 开始正式背诵6000个考研单词
  • 复习刘毅10000(好久没看了)
  • 开始收集大纲和历年卷子及其他资料

高等数学
每周3章,一天看一章,第二天做相关习题,这部分任务很重。每天大约可利用的共12个学时,打算花4个学时在高等数学上。正好每个学时看2节内容左右。

80x86汇编语言程序设计教程(电子版)
只能在电脑上看,安排在每天晚上,下周开始不再拎着笔记本去图书馆了。这部分内容要等到数据结构搞定後才能开始。安排2个学时。

数据结构剩余的四章
白天把一些不懂的地方再看一遍,晚上回来习题之。每周两章。安排1+2学时。

微型计算机的基本原理与应用
一天一章,2周完成,每天2个学时

英语六级的一些卷子
可以在早上作,每天半套吧。1个学时。

刘毅1000
每天4个list,一组2个,各半个小时,拆开,效率比较高一点。

开始正式背诵6000个考研单词
考虑用 奇迹英语 来背单词,唯一的缺点就是不能乱序,不知道自己能不能忍受。一周必须背1500个单词,6天的话,每天差不多要记住250个,按照我的记忆力的话,至少要每天2个学时。
这又是需要电脑的部分。

另外还有些内容就不列入计划了,比如练字啊,英语精读泛读啊,每天抽个1个学时左右就行了。

好了,这个月任务真的很重,一定要挺住。先去做下周的计划,用google的日历,周一到周六学习,周日休息。
看了sam兄推荐的《当梦想照进现实》后感叹良多,beggarson无疑是幸运的人,每每他频临绝望的时候,总有新的希望出现,怀疑上帝他老人家给他开了后门(因为家庭里有虔诚的信徒)。当然,beggarson能走进梦想里,绝对离不开他的努力,相比而言,他觉悟的比我早的多,我直到最近才发现人生真的需要一些支点,要不然会变得索然无味。就像我一个同事,才30的年纪,却已经开始等死了,人生对于没有支点的人来说太痛苦。
beggarson真的是一个幸运的人,在这么年轻的年纪就能够体悟到生命的许多含义,真的很了不起,也很受命运的眷顾。在面临cs考研上,除了努力,他还有很多别的优点,他有mm的支持,有良好的判断力,有实践基础,有清晰的头脑等等,恰恰是我所缺乏的,在考研这条道路上,我几乎看不见希望。从来没有接触过任何实际的编程,或者甚至没有真正踏进过计算机这个圈子,一直就是个局外人。命运和我开了许多玩笑,岁月已经悄悄地溜走了,今年是我第一次也是最后一次机会了,恩,本命年,我依然不相信命运,在本命年这样被断定有厄运的一年里,我要走出人生中最重要的一步。能不能考上,我并不是像其它研友那样,那么在乎,这一年,这一步,对我来说,已经够沉重了,只要做到了,便无愧于心。
所以当sam问我,如果上了软院的线,去不去时,我的回答显得那样的漫不经心,或许比起beggarson,我更明白了人生无常,毕竟在外头混了这么多年,知道很多东西是不能强求的。我的梦想不是一次考试能够实现的,也不是一个学科能够涵盖的,达则兼济天下,穷则独善其身,通过这次考研,我更希望完善人格上的自我,便仿佛是那个佛字的解释。
我总是害怕孤独,思维就会想脱缰的野马无边无际的纵横,有时候害怕迷失在自己的思绪空间里。孤独来自于空虚,只有空虚的人才会有孤独感,而充实的灵魂时时刻刻可以接受爱与被爱。行走于世间,我们必定有所热爱的事务,所喜爱的人,而很多时候,就像以前的我,总是让这些悄悄地溜走,哪怕只是需要那么一点点努力,错过的便不会再回来了,随着每一份在时间的长河里湮灭的过去,内心也会变得越来越空虚。也许真的是受累于智商,139的智商不算高,却让我在做很多事情的时候,变得比其他人容易得多,渐渐的我越来越懒于付出,直到上个月,其实我还是可以就这么度过了一辈子,但是我真的害怕了,我怕我自己终于会掉进那个空虚的好像可以抽干一切的思绪里。
很小的时候,我便开始问自己一个问题,人生是为了什么?每一个阶段都会有不同的回答,但从来没有一刻像现在这么满意自己的答案。每一个人生都是一次进化,一次升华,是对这个世界,这个宇宙的一次诠释。不管是短暂的,还是绚烂的,成功抑或失败的,每一份生命都用自己的方式在演绎这个过程。也许区别只是在于你是不是尽力地去主宰了这么唯一的一次机会。
6-18 二叉树的双序遍历(Double-order traversal)是指:对于二叉树的每一个结点来说,先访问这个结点,再按双序遍历它的左子树,然后再一次访问这个结点,接下来双序遍历它的右子树。试写出执行这种双序遍历的算法。

声明:类结构按教材的二叉树类定义

双序遍历

template < calss Type >void BinaryTree< Type >::DbOrder(){
DbOrder(root);
}

template< class Type >void BinaryTree< Type >
::DbOrder(BinTreeNode< Type > *current){
if(current!=NULL){
visit();
DbOrder(current->leftChild);
visit();
DbOrder(current->rightChild);
}
}


6-20 已知一棵树的先根次序遍历的结果与其对应二叉树表示(长子-兄弟表示)的前序遍历结果相同,树的后根次序遍历结果与其对应二叉树表示的中序遍历结果相同。试问利用树的先根次序遍历结果和后根次序遍历结果能否唯一确定一棵树?

当然可以. 每一个二叉树可以唯一的转变成一棵树.

6-21 给定权值集合{15 03 14 02 06 09 16 17},构造相应的霍夫曼树,并计算它的带权外部路径长度。

WPL=229
身边没有稿纸,心中建树,+所有的分支结点的权值


6-22 假定用于通讯的电文仅8个字母c1,c2,c3,c4,c5,c6,c7,c8组成,各字母在电文中出现的频率分别为5,25,3,6,10,11,36,4. 试为这8个字母设计不等长Huffman编码,并给出该电文的总码数。

c1:0110 c2:10 c3:0000
c4:0111 c5:001 c6:010
c7:11 c8:0001

总码率为:257


6-23 给定一组权值:23,15,66,07,11,45,33,52,39,26,58,试构造一棵具有最小带权外部路径长度的扩充4叉树,要求该4叉树中所有内部结点的度都是4,所有外部结点度为0.这棵扩充4叉树的带权外部路径长度是多少?

本题关键是11个结点没法构成符合要求的4叉树,需要补充2个节点。补充两个权值为0的节点并不影响最后的外部路径长度。
6-10 一棵高度为h的满k叉树有如下性质;第h层上的结点都是叶结点,其余各层上每个结点都有k课非空子树,如果按层次自顶向下,同层自左向右,顺序从1开始对全部结点进行编号,试问:
(1)各层结点个数是多少?
(2)编号为i的结点的父结点(若存在)的编号是多少?
(3)编号为i的结点的第m个孩子结点(若存在)的编号是多少?
(4)编号为i的结点有右兄弟的条件是什么?其右兄弟结点的编号是多少?


(1)
第0层 1
第1层 k
第2层 k^2
...
第h层 k^h

(2)假设i为第m层元素,那么i层i是第几个 N=i - m层前所有元素个数
而i的父结点在上层的序号位置正好是N/k的上整
那么该父结点的序号是m-1层前所有元素+N/k的上整
上整外取,得到如下公式
上整『(1-k^(m-1))/(1-k)+(i-(1-k^m)/(1-k))/k』
化简得到取上整『(i-1)/k)』


(3)和2相反
(i-1)k+1+m

(4)i结点有右兄弟,条件就是i不是该层子树的最后一个元素。
即(i-1)%k!=0 有兄弟 右兄弟为i+1;

6-11 试用判定树的方法给出在中序线索化二叉树上:
(1) 如何搜索指定结点的在中序下的后继。
(2) 如何搜索指定结点的在前序下的后继。
(3) 如何搜索指定结点的在后序下的后继。


看树的线索化去……
第2小题结果好复杂!!@@

6-12 已知一棵完全二叉树存放于一个一维数组T[n]中,T[n]中存放的是各结点的值。试设计一个算法,从T[0]开始顺序读出各结点的值,建立该二叉树的二叉链表表示.

思路:利用完全二叉树的性质 T[i]应该插入的位置是 下整『(i-1)/2』 (i-1)/2整除则正好是该点的左子女,否则右子女.简化代码,不写类和模板了。

CreatTree(int T[],int n,int i,BinTreeNode *ptr){
if(i >=n)ptr=NULL;
else{
ptr=new BinTreeNode(T[i]);
ConstructTree(T,n,2*i+1,ptr->leftChild);
ConstructTree(T,n,2*i+2,ptr->rightChild);
}
}

程序从CreatTree(t,n,0,root)开始,事先先创建一棵空树.

6-13 试编写一个算法,把一个新结点l作为结点s的左子女插入到一棵线索化二叉树中,s原来的左子女变成l的左子女。
假定是中序线索化二叉树

template< class Type > void ThreadTree< Type >::
InsertRight(ThreadNode< Type > *s,ThreadNode< Type > *l){
l->leftChild=s->leftChild;
l->leftThread=s->leftThread;
l->rightChild=s;L->rightThread=1;
s->leftChild=l;s->leftThread=0;
if(l->leftThread==0){
current=l->leftChild;
ThreadNode< Type > *temp=Last();
temp->rightChild=l;
}
}

发现和右插入简直就是镜像啊

6-15 判断以下序列是否是堆?如果不是,将它调整为堆。
(1) {100,86,48,73,35,39,42,57,66,21}
(2) {12,70,33,65,24,56,48,92,86,33}
(3) {103,97,56,38,66,23,42,12,30,52,06,20}
(4) {05,56,20,23,40,38,29,61,35,76,28,100}


(1)

100
86 48
73 35 39 42
57 66 21

100
86 48
73 21 39 42
57 66 35

100
86 48
57 21 39 42
73 66 35

100
86 39
57 21 48 42
73 66 35

100
21 39
57 35 48 42
73 66 86

21
35 39
57 86 48 42
73 66 100
就做一题了 {21 35 39 57 86 48 42 73 66 100}

6-17 在森林的二叉树表示中,用llink存储指向结点第一个子女的指针,用rlink存储指向结点下一个兄弟的指针,用data存储节点的值。如果我们采用静态二叉链表作为森林的存储表示,同时按森林的先根次序依次安放森林的所有结点,则可以在它们的结点中用只有一个二进位的标志ltag代替llink,用rtag代替rlink。并设定若rtag!=0,则该结点有下一个兄弟。试给出这种表示的结构定义,并设计一个算法,将这种表示存储的森林转换成用llink-rlink表示的森林。

先在草稿纸上画出这样表示的森林和二叉树结构表,理解相互之间的转换方式。

先定义llink-rlink表示的结点定义
template< class Type >class LchRsibNode{
protected:
Type data;
int llink,rlink;
public:
LchRsibNode():llink(-1),rlink(-1){}
LchRsibNode(Type x):llink(-1),rlink(-1),data(x){}
}

双标记类节点定义
template< class Type >class DoublyTagNode{
protected:
Type data;
int ltag,rtag;
public:
DoublyTagNode():ltag(0),rtag(0){}
DoublyTagNode(Type x):ltag(0),rtag(0),data(x){}
}

静态链表类定义
template< class Type >class staticlinkList
:public LchRsibNode< Type >,pubic DoublyTagNode< Type >{
private:
LchRsibNode< Type > *V;
DoublyTagNode< Type > *U;
int MaxSize,CurrentSize;
public:
dstaticlinkList(int Maxsz ):MaxSize(Maxsz),CurrentSize(0){
V=new LchRsibNode< Type >[Maxsz];
U=new DoublyTagNode< Type >[Maxsz];
}

森林的双标记先根次序表示 向 左子女-右兄弟链表示先根次序表示的转换
void staticlinkList< Type >::DtagF-LchRsibF(){
Stack< int >st; int k;
for(int i=0;i< CurrentSize; i++){
switch(U[i].ltag){
case 0:switch(U[i].rtag){
case 0:V[i].llink=V[i].link=-1;
if(!st.IsEmpty())
{k=st.GetTop();
st.Pop();
V[k].rlink=i+1;
}break;
case 1:V[i].link=-1;
V[i].rlink=i+1;
break;
}
case 1: V[i].llink=i+1;
if(U[i].rtag==0)
V[i].rlink=-1;
else
st.Push(i);
break;
}
}
}

感觉用switch结构并不好,不过实在太饿了,懒得改写了。
6-4 用嵌套类写出用链表表示的二叉树的类声明。
把书p170~171页改写成嵌套形式
template< class Type >class BinaryTree{
private:
template< calss Type >class BinTreeNode{
public:
BinTreeNode< Type >* leftChild,*rightChild;
Type data;
}
Type RefValue;
BinTreeNode< Type >* root;
......
结点相关的一些递归操作
......
publick:
//一些构造函数
BinaryTree();
~BinaryTree();
BinTreeNode();
~BinTreeNode();
.......
二叉树的公共操作
.......
}


6-5 在结点个数为n(n>1)的各棵树中,高度最小的树的高度是多少?它有多少个叶结点?多少个分支结点?高度最大的树的高度是多少?它有多少个叶结点?多少个分支结点?

最小高度为1,有两层。n-1个页结点,1个分支结点。
最大高度为n-1,有n层,n-1 个分支结点,1个页结点.

6-7 如果一棵树有n1个度为1的结点,有n2个度为2的结点,...,nm个度为m的结点,试问有多少个度为0的结点?试推导之。

设度为0的结点为n0个。可以想象,每个度必定对应一个结点,或者反过来,除去根结点每个结点都消耗一个度。那么我们可以列出如下等式 n1*1+n2*2+n3*3+...+nm*m=n0+n1+n2+...+nm-1
n0=1+n2*1+n3*2+...+nm*(m-1)

6-8 试分别找出满足以下条件的所有二叉树:
(1) 二叉树的前序序列与中序序列相同;
(2) 二叉树的中序序列与后序序列相同;
(3) 二叉树的前序序列与后序序列相同;


(1)空树,或者所有结点均没有左子树的单支树;
(2)空树,或者所有结点均没有右子树的单枝树;
(3)空树,或者只有根结点的二叉树;

6-9 若用二叉链表作为二叉树的存储表示,试针对以下问题编写递归算法:
(1) 统计二叉树中叶结点的个数。
(2) 以二叉树为参数,交换每个结点的左子女和右子女。


声明:类定义参见教科书
(1)思路:如果有左子女或者右子女,返回左子女或者右子女的叶结点个数,如果没有(本身就是叶结点),返回1.方便起见,作为类成员函数加入。

int count(BinaryTree &t){
count(root);
}

int count(BinTreeNode *current){
if(current==NULL) return 0;
else if(current->leftChild==NULL && current->rightChild==NULL)return 1;
else return count(current->leftChild)+count(current->rightChild);
}


(2)思路同上,另一直想把二叉树作为直接参数,函数作为外部函数,但这样写起来要使用很多类函数,很麻烦,每次都要重新构造一棵树,非常麻烦,上题也是这个困惑。看到参考答案直接忽视题目的要求--二叉树作为参数,无语,直接仿效。
void exchange(BinaryTree & t){
exchange(root);
}

void exchange(BinTreeNode *current){
BinTreeNode *temp;
if(current==NULL)return;
//书里的条件有问题,NULL->link不一定=NULL
temp=current->leftChild;
current->leftChild=current->rightChild;
current->rightChild=temp;
exchange(current->leftChild);
exchange(current->rightChild);
}
6-1 写出用广义表表示法表示的树的类声明,并给出如下成员函数的实现:
(1) operator >>() 接收用广义表表示的树作为输入,建立广义表的存储表示;
(2) 复制构造函数 用另一棵树表示为广义表的树初始化一棵树;
(3) operator ==() 测试用广义表表示的两棵树是否相等;
(4) operator<< () 用广义表的形式输出一棵树;
(5) 析构函数 清除一棵用广义表表示的树。


class GenTree;
class GenTreeNode{
friend class GenTree;
private:
int utype; //标志结点
GenTreeNode* nextSibling;

union(
char RootData; //utype=0
char Childdata; //utype=1
GenTreeNode* firstChild; //utype=2
}
public:
GenTreeNode(int tp,char item):utype(tp),nextSibling(NULL)
{if(tp==0) RootData=item;else ChildData=item;}
//构造函数:构造广义表表示的树的数据结点.
GenTreeNode(GenTreeNode* son=NULL)
:utype(2),nextSibling(NULL),firstChild(son){}
//构造函数:广义表表示的树的子树结点
int nodetype(){return utype;} //返回结点数据类型
char GetData(){return data;} //返回结点的值
GenTreeNode* GetFchild(){return firstChild;}
//返回子树结点的地址
GenTreeNode* GetNsibling(){return nextSibling;}
//返回下一个兄弟结点的地址
void setInfo(char item){data=item;}
void setFchild(GenTreeNode* ptr)
{firstChild=ptr;}
void setNsibling(GenTreeNode* ptr)
{nexSibling=ptr;}
};

class GenTree{
private:
GenTreeNode *first; //根指针
char reValue; //建树时的输入停止标志
GenTreeNode *Copy(GenTreeNode * ptr);
//复制一个ptr指示的子树
void Traverse(GenListNode *ptr);
//对ptr为根的子树遍历并输出
void Remove(GenTreeNode *ptr);
//将以ptr为根的广义树结构释放
friend int Equal(GenTreeNode *s,GenTreeNode *t);
//比较以s和t为根的树是否相等.
void ConstructTree(istream&in,char& value)
//从输入流in接受用广义表表示的非空树,建立广义表的存储表示t
public:
GenTree();
GenTree(GenTree& t);
~GenTree();
friend int operator==(GenTree& t1,GenTree& t2);
//判断两棵树t1和t2是否相等
friend istream& operator >>(istream& in,GenTree& t);
//输入
friend istream& operator<< (istream& out,GenTree& t);
//输出
}

(1) oerator >>() 接收用广义表表示的树作为输入,建立广义表的存储表示

istream& operator >>(istream& in,GenTree& t){
//友元函数,从输入流对象in接受用广义表表示的树,建立广义表的存储表示t
t.ConstructTree(in,reValue);
return in;
}

void GenTree::ConstructTree(istream& in,char& value){
Stack< GenTreeNode* >st;
GenTreeNode * p,q,r;
Type ch;
cin >>value;
cin >>ch;first=q=new GenTreeNode(0,ch);
cin >>ch;if(ch=='(')st.Push(q);
cin >>ch;
while(ch!=value){
switch(ch){
case'(':p=new GenTreeNode< Type >(q);
r=st.GetTop();st.Pop();
r->nextSibling=p;
st.Push(p);
st.Push(q);
break;
case')':q->nextSibling=NULL;
st.Pop();
if(st.IsEmpty()==0)
q=st.GetTop();
else return 0;
break;
case',':break;
default:p=q;
if(isupper(ch))
q=new GenTreeNode(0,ch);
else q=new GenTreeNode(1,ch);
p->nextSibling=q;
}
cin>>ch;
}
}

先去吐血了……
5-5 已知f为单链表的表头指针,链表中存储的都是整型数据,试写出实现下列运算的递归算法:
(1)求链表中的最大整数;
(2)求链表的结点个数;
(3)求所有整数的平均值;


和整型数组A[]的算法一样;另外与参考答案同步,假设是不带表头结点的单链表。
(1)思路:把f->data的值和Max(f->link)比较;套用广义表的说法,就是比较表头和表尾即可,顺便递归定义表尾。
int Max(ListNode *f){
if(f->link == NULL) return f->data;
int tmp=Max(f->link);
if(f->data >= tmp)
return f->data;
else return tmp;
}

(2)求链表长度

int Length(ListNode *f){
if(f == NULL) return 0;
else return 1+Length(f->link);
}

(3)求所有整数的平均值

float Avg(ListNode *f){
if(f->link == NULL) return f->data;
else{int n=length(f->link); //时间代价够高的 呵呵
return (f->data+Avg(f->link)*n)/n;
}


5-7 利用广义表的head和tail操作写出函数表达式,把以下各题中的单元素banana从广义表中分离出来:
(1)L1(apple,pear,banana,orange)
(2)L2((apple,pear),(banana,orange))
(3)L3(((apple),(pear),(banana),(orange)))
(4)L4((((apple))),((pear)),(banana),orange)
(5)L5((((apple),pear),banana),orange)
(6)L6(apple,(pear,(banana),orange))


(1) head(tail(tail(L1)))
(2) head(head(tail(L2)))
(3) head(head(tail(tail(head(L3)))))
(4) head(head(tail(tail(L4))))
(5) head(tail(head(L5)))
(6) head(head(tail(head(tail(L6)))))


5-8 广义表具有可共享性,因此在遍历一个广义表时必须为每一个结点增加一个标志域mark,以记录该结点是否访问过。一旦某一个共享的子表结点被作了访问标志,以后就不再访问它。
(1)试定义该广义表的类结构;
(2)采用递归的算法对一个非递归的广义表进行遍历。
(3)试使用一个栈,实现一个非递归算法,对一个非递归广义表进行遍历。


(1)声明:按照参考答案的思路;广义表中假定只存放了一种元素类型char,统称为原子结点 atom。 这样,广义表中结点类型只有3种:表头结点、char原子结点和子表结点.大写的字母表示表,小写表示原子结点 等同于教材。
class GenList;
class GenListNode{
friend class GneList;
private:
int mark,utype;
GenListNode* link;
union{
char listname; //utype=0,表头结点,存放表名.
char atom; //utype=1,存放原子结点的数据.
GenLisNode* hlink; //utype=2,存放指向子表的指针.
}value;
public:
GenListNode(int tp,char info):mark(0),utype(tp),tlink(NULL)
//表头或者原子结点的构造函数.
{if(utype==0)value.listname=info;
else value.atom=info;
}
GenListNode(GenListNode* hp) //子表构造函数.
:mark(0),utype(2),value.hlink(hp){}
char Info(GenListNode* elem) //返回元素elem的值.
{return(utype==0)?elem->value.listname:elem->value.atom;}
};

class GenList{
private:
GenListNode* first; //表头.
void traverse(GenListNode* ls); //广义表遍历.
void remove(GenListNode* ls); //删除.
public:
GenList(char& value); //构造函数,value停止标记
~GenList();
void traverse();
}

(2)广义表遍历的递归算法

void GenList::traverse(){
if(first==NULL){
cout<< "error"< return;
}
traverse(first);
}

void GenList::traverse(GenListNode* ls){
if(ls!=NULL){
ls->mark=1;
if(ls->utype==0) //表头结点;
cout<< ls->value.listname<< '(';
else if(ls->utype==1){ //原子结点;
cout<< ls->value.atom;
if(ls->linke!=NULL)cout<< ',';
}
else if(ls->utype==2){ //子表结点;
if(ls->value.hlink->mark==0)
traverse(ls->value.hlink);
else cout<< ls->value.hlink->value.listname;
if(ls->tlink!=NULL)cout<< ',';
}
traverse(ls->link);
}
else cout<< ')';
}

(3)按照上题的遍历顺序,改写成利用栈的非递归方式。依然方便处理,pop()直接弹出并返回元素结点.
下面这段程序不同于参考答案,感觉参考答案写的有点乱,修改了。
void GenList::traverse(GenListNode *ls){
Stack< GenListNode* >st;
st.Push(ls);
while(!st.IsEmpty()){
ls=st.Pop(); //取出结点
if(ls==NULL){ //空结点,当前层结束
cout<< ')';
return;
}
else st.Push(ls->link); //压入当前层下一个结点
ls->mark=1;
switch(ls->utype){
case 0:cout<< ls->value.listname<< '(';
//表头结点
case 1:cout<< ls->value.atom;
if(ls->link!=NULL)cout<< ',';
//原子结点
case 2:if(ls->value.hlink->mark==0)
st.Push(ls->value.hlink);
else{
cout<< ls->value.hlink->value.listname;
if(ls->link!=NULL)cout<< ',';
}
//子表结点
}
}

多简洁啊,参考答案的栈用的让人觉着不和谐。
5-3 【背包问题】设有一个背包可以放入的物品的重量为s,现有n件物品,重量分别为w[1],w[2],...,w[n]。问能否从这n件物品中选择若干件放入此背包中,使得放入的重量之和正好为s。如果存在一种符合上述要求的选择,则称此背包问题有解;否则无解。

思路:按照题中所给的背包问题递归定义,可以理解为从w[n]开始检查,直到n和s达到0,检查完毕。

Boolean bag(int s,int n){
if(s< 0||s >0&&n< 1) return False;
if(s==0) return Ture;
if(bag(s-w[n],n-1)==True) {cout<< w[n]<< ',';return Ture}
return bag(s,n-1);
}


5-4 【八皇后问题】设在初始状态下在国际象棋棋盘上没有任何棋子(皇后)。然后顺序在第一行,第2行。...,第8行上布放棋子。在每一行中有8个位置可选择,但在任一时刻,棋盘的合法布局都必须满足3个限制条件,即任何两个棋子不得放在棋盘上的同一行、或者同一列、或者同一斜线上。试编写一个递归算法,求解并输出此问题的所有合法布局。

思路:抄参考答案;书里的方法已经很经典了。

col[i]:标志第i列是否放置了皇后,是1,下同.
md[k]:标志第k条主对角线是否安置了皇后。k=7+i-j-1
sd[k]:标志第k条次对角线是否放置了皇后,k=i+j
q[i]:记录第i行皇后在第几列。

void Queen(int i){
for(int j=0;j< 8;j++){
if(col[j]+md[8+i-j-1]+sd[i+j]==0){//没有被攻击
col[j]=md[8+i-j-1]=sd[i+j]=1; //修改攻击范围
q[i]=1; //安置皇后
if(i==8){ //如果已经是第八个皇后了
for(j=0;j< 8;j++) //这个j不影响外层的j么?
cout<< q[j]<< ','<< endl;
}
else Queen(i+1); //安置下一行
col[j]=md[8+i-j-1]=sd[i+j]=0; //撤销,尝试其他位置
q[i]=0;
}
}
}

执行的时候用函数Queen(1) 从第一行开始.
5-1 已知A[n]为整数数组,试写出实现下列运算的递归算法:
(1)求数组A中的最大整数。
(2)求n个整数的和。
(3)求n个整数的平均值。


解:
(1)思路:求A(n)中的最大整数,等价于比较A[n-1]与A(n-1)中的最大值,谁大就返回谁.A(n-1)看起来有点别扭,其实是指前n-1个数,从A[0]~A[n-2]。
于是我们可以这样设计函数
int max(int n){
if(n == 1) //递归结束条件
return A[0];
else{
int tmp=max(n-1); //返回A(n-1)的最大值
return A[n-1]>=tmp?A[n-1]:tmp;
}


(2)思路:和上题一样
int sum(int n){
if(n == 1)
return A[0];
else return A[n-1]+sum(n-1);
}


(3) 用递归求平均值有意义么?

5-2 已知Ackerman函数定义如下:

|n+1 当m=0时.
akm(m,n)= |akm(m-1,1) 当m!=0,n=0时.
|akm(m-1,akm(m,n-1)) 当m!=0,n!=0时

(1)根据定义,写出它的递归求解算法;
(2)利用栈,写出它的非递归求解算法.


(1)依样画葫芦,相当于直接把函数抄下来
int akm(int m,int n){
if(m != 0)
if(n != 0)
return akm(m-1,akm(m,n-1));
else return akm(m-1,1);
else reurn n+1;
}


(2)看了好久的答案才明白这类题的做法,我的理解如下:
a. 作为一个递归函数什么时候需要栈呢?
如果akm(m,n)能够等价于另一个简单的akm(x,y),那么这时候就不需要工作栈,直接变换就行。比如“斐波那契数列”;只有形如akm(..akm(..akm(..)...)这个时候需要栈,因为m,n的变换必须依靠下一步的结果,也就是说你除了把这一步先保存起来,别无他法,你永远不知道它下一步会变成什么。没有一个简单的变化,这时候就需要工作栈.
b. 哪些变量需要进栈?以及如何判断进栈和出栈
那些与其他参数的下一步结果相关的变量需要进栈。这里便是akm函数的第一个参数m。
在我们得到下一组n的值之前,m必须先被保存起来,我们没有办法先运算m。而n的值恰好是尾递归.

进栈与出栈的条件一般已经在函数或者题意中给出,比如这个函数可以直接按照函数结构来写。
int akm(int m,int n){
int vn=n,vm;
stack st; //就不写最大元素数了.
st.Push(m); //栈,保存一系列参数m
while(!st.IsEmpty()){
vm=st.Pop();
if(vm == 0)vn++; //函数的第一个分支条件
else if(vn == 0){ //第二分支条件
st.Push(vm-1);vn=1;
}
else{ //第三个分支条件
st.Push(vm-1);
st.Push(vm);
vn--;
}
}
return vn;
}

这道题做了我足足两天之久。第一次接触 递归和循环 结构的转换,非常努力的试图搞懂它,最后刹那间明了,欣喜若狂,忍不住糊诌几句。
花了很多时间才看懂参考答案的意思,它是通过找出栈的变换规律,然后具体问题具体分析,总结出来,再写成循环结构。不过这样的规律并不一定好找,我一开始之所以看不懂的原因也在于此,因为我总觉得它应该从普遍性入手。
后来我就一直思考,栈为什么要存在,必要性在哪里,是什么原因导致了函数的无规律变换,而需要一串的地址去存储它的自变量或者中间量。哪些元素又是必须依靠栈去保留呢。
当我凝视着窗外烈日底下在风中轻轻舞动的树叶,交织出婆娑的树影和跃动的光斑时,突然想通了。
于是很快写下了算法,完全依照函数的结构,只保留必须要保留的值,相比参考答案,更简洁明了,更具有普遍性.
4-11 若使用循环链表来表示队列,p是链表中的一个指针。试基于此结构给出队列的插入和删除算法,并给出p为何值时队列为空。

思路:我们可以考虑把p作为入口,每次加入的元素从p加入。而p->link就成为出口,每次出队,都读取p->link,并删去这个结点.

按照书p117的基本类声明改写
isEmpty():p==NULL;
template< class Type >void Queue< Type >::EnQueue(const Type& item){
//将新元素item插入到队列的入口.
QueueNode *out;
if(isEmpty()) //如果队空,则p作为第一个结点并且链向自身
p->link=p=new QueueNode(item,NULL);
else
{out=p->link; //保存出口指针
p->link=new QueueNode(item,NULL); //新元素到入口
p=p->link;p->link=out; //修改入口指针,并指向出口
}
}

template< class Type >Type Queue< Type >::DeQueue(){
//从出口取出元素,并返回该元素值.
assert(!IsEmpty());
QueueNode *out=p->link; //从出口取出元素
Type retvalue = out->data; //元素值
p->link=out->link; //修改出口指针
delete out;
return retvalue;
}


4-12 若将一个双端队列顺序表示在一维数组V[m]中,两个端点设为end1和end2,并组织成一个循环队列。试写出双端队列所用指针end1和end2的初始化条件以及队列空和队列满的条件,并编写基于此结构的相应的插入和删除操作。

恩,双端队列,看了参考答案才明白什么叫双端队列。丫就一无赖双头栈~
思路:end1和end2为队列的两头,但不同于普通的循环队列,这两头不分first和rear,既能进,又能出,双向通道,类似于腔肠动物……
为了和参考答案保持一致,定义入队时end1向右,end2向左,简单点理解就好像某些时候数组的中间段空的。其实我更喜欢反过来。
那么很显然和循环队列一样,队空队满都是end1==end2,为了以示区别,可以定义end2永远指向第二个端口实际向前的一个位置,多出一个空位。如此我们有
队满:end1+1==end2 考虑到循环效果,end1可能会从V[0]恰好退到v[m],而此时 end2指向v[0],队列也是满的。所以表打成 (end1+1)%m==end2
队空:end1==end2

初始化,一定是置空队列和数组,所以有end1=end2=0 指向v[0]

同以前的题,我么假设判断队空和队满的函数以及类结构都已完成。
template< class Type >void DblQueue< Type >::EnQueue(Type& item,const int end){
//元素进队,end为1或者2,表示进队的方向.
assert(!IsFull());
if (end == 1){
end1 = (end1+1)%m;
V[end1]=item;
}
else{ //end1和end2的操作有区别,原因在于end2实际指向空
V[end2]=item;
end2=(end2-1+m)%m;
//莫非模不能做负数?前面我好像有地方取负数的模了
}
}

template< class Type >Type DblQueue< Type >::DeQueue(const int end){
//元素出队,end为1或者2,表示出队的方向.
assert(!IsEmpty());
Type temp;
if(end==1){
temp=V[end1];
end1=(end1+m-1)%m;
}
else{
end2=(end2+1)%m;
temp=V[end2]; //从这里可以看出end2指向的位置
}
return temp;
}


4-13 设用链表表示一个双端队列,要求可在表的两端插入,但限制只能在表的一端删除。试编写基于此结构的队列的插入和删除算法,并给出队列空和队列满的条件。

思路:
先描述一个用链表表示的双端队列的数据结构,两端用指针first和last表示,其中first端允许删除。为使链表的操作简化一致,同样使first作为头结点,first->link指向第一个结点。初始化条件first=last;first->link=last->link=NULL;
队满?不是链表么?还考虑队满啊 哎 太麻烦 无视之

感觉参考答案有问题,首先它把这个链设计成了一个循环链,然后end1->link=end1,那么如果一直只是从空表的end2端插入,end2->link指向end1,但是这样的链却没法删除,因为end1->link依然=end1.没有元素,事实上已经从end2端插入了很多元素.并且是从NULL开始的,不知道这样的表有没有意义

enum Direct{firstin,lastin}
EnQueue(const &item,Direct a){
//插入函数,a作为插入的方向,可选firstin或者lastin
QueueNode *p,*newnode;
newnode =new QueueNode(item,NULL); //新加入结点
p= a==firsin?first:last; //p作为指针
newnode->link=p->link; //仿照书p75页,统一各种情况
if(p->link == NULL)last=newnode;
p->link=newnode;
}

DeQueue(){
assert(first!=last); //确定队不空
QueueNode *q=first->link;
Type value=q->data; //懒得写模板了……用Type代替
first->link=q->link;
delete q;
if(first->link == NULL)last=first; //如果删最后一个元素
return value;
}


队空条件 first==last
4-6 根据课文中给出的优先级 ,回答以下问题:
(1)在函数postfix中,如果表达式e含有n个运算符和分界符,那么栈中可能存入元素的最大个数是多少?
(2)如果表达式e含有n个运算符,且括号嵌套的最大深度为6层,那么栈中可能存入元素的最大个数是多少?


(1)我想参考答案应该是错的。
题中的元算符指操作符,分界符在课文中有优先级定义么?
按照优先级表,从+,—开始往右依次进栈时,都不会导致退栈,一直到(,然后可以继续循环,如此可以保证最多的操作符进栈,一次进栈3个操作符和“(”,然后循环,但是(需要“)”对应,设有x个“(”,那么4x+3+x=n。x=(n-3)/5 那么最多进栈的操作符是 4(n-3)/5+3+1 1是指栈底的#

(2)括号深度最大6个,那么如果n足够大的话,最多存入的元素是
4*6+3再进来就是)了,要退栈。加上# 一共是28个。此时的n应该 >=33
如果n& lt;33的话,答案还是4(n-3)/5+3+1=4(n+2)/5

4-7 设表达式的中缀表示为a*x-b/x^2,试利用栈将它改为后缀表示ax*bx2^/-。写出转换过程中栈的变化。

步序 扫描项 类型项 动 作 栈变化 输出
0 '#'进栈 #
1 a 操作数 #  a
2 * 操作符 isp* >icp#,进栈 #* a
3 x 操作数 #* ax
4 - 操作符 isp-< icp*,退栈 # ax*
isp- >icp#,进栈 #- ax*
5 b 操作数 #- ax*b
6 / 操作符 isp/ >icp-,进栈 #-/ ax*b
7 x 操作数 #-/ ax*bx
8 ^ 操作符 isp^ >icp/,进栈 #-/^ ax*bx
9 2 操作数 #-/^ ax*bx2
10 # 操作符 isp#< icp^,退栈, #-/ ax*bx2^
isp#< icp/,退栈, #- ax*bx2^/
isp#< icp-,退栈, # ax*bx2^/-
结束


4-9 假设以数组Q[m]存放循环队列中的元素,同时以rear和length分别指示环形队列中的队尾位置和队列中所含元素的个数。试给出该循环队列的队空条件和队满条件,并写出相应的插入(enqueue)和删除(dlqueue)元素的操作。

队空条件:length==0;
队满条件:length==maxsize;

template< class Type >void Queue< Type >::EnQueue(const Type& item){
//若队列不满,则将元素item插入该队列的队尾,否则出错处理.
assert(!isFull()); //假设isFull()函数已经能够正确判断
rear=(rear+1)%MaxSize; //对为指针加1
elements[rear]=item; //在队尾插入item
length++;
}

template< class Type >Type Queue< Type >::DeQueue(){
//若队列不空则函数返回该队列队头的元素的值,同时将该队头元素删除.
assert(!isEmpty()); //同样假设已经修正isEmpty()函数.
length--; //队列长度减1
return element[(rear-length)%MaxSize]; //返回原队头元素
}


4-10 假设以数组Q[m]存放循环队列中的元素,同时设置一个标志tag,以tag==0和tag==1来区别在队头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“满”。试编写出此结构相应的插入和删除函数。

加入标志tag,则循环队列结构中不需要空一个元素位置了。front依然指向第一个元素前的队头
改写isEmpty()和isFull()
队空:front==rear&&tag==0
队满:front==rear&&tag==1

template< class Type >void Queue< Type >::EnQueue(const Type& item){
//若队列不满,则将元素item插入该队列的队尾,否则出错处理.
assert(!isFull()); //假设isFull()函数已经能够正确判断
rear=(rear+1)%MaxSize; //对为指针加1
elements[rear]=item; //在队尾插入item
tag=1; //队列不空
}

template< class Type >Type Queue< Type >::DeQueue(){
//若队列不空则函数返回该队列队头的元素的值,同时将该队头元素删除.
assert(!isEmpty()); //同样假设已经修正isEmpty()函数.
front=(front+1)%MaxSize; //队头往前移1
tag=0; //队列不满
return element[front]; //返回原队头元素
}
4-1 在下题中,s是栈的名字,a、b是栈中的元素,操作PUSH返回栈s的栈顶元素地址,POP返回从栈中退出的元素。试说明下列运算的结果:
(1)POP(PUSH(s,a));
(2)PUSH(s,POP(s));
(3)PUSH(s,POP(PUSH(s,b)));


1)返回a;
2)s栈先退出元素,后又将退出的元素压回栈中,返回栈顶元素,栈顶元素无变化;
3)b压入了栈中,并返回栈顶元素地址。

4-2 改写顺序栈的进栈成员函数Push(x),要求当栈满时执行一个stackFull()操作进行栈满处理。其功能是:动态创建一个比原来的栈数组大二倍的新数组,代替原来的栈数组,原来栈数组中的元素占据新数组的前MaxSize位置。

思路:将p105页的Push()函数改成if结构的;调用stackFull函数。创建stackFull函数。
template < class Type >void Stack< Type >::Push(const Type& item){
//若栈满执行stackFull。再执行压栈操作.
if(IsFull())
stackFull();
elements[++top]=item;
}

template < class Type >void Stack< Type >::stackFull(){
maxSize*=3; //最大元素扩大2倍
Type *temp=new Type[maxSize];
for(int i=0;i <= top;i++) //复制数据
temp[i]=elements[i];
delete[]elements;
elements=temp;
}


4-3 铁路进行列车调度时,常把站台设计成栈式结构的站台,如右图所示。试问:
(1)设有编号1,2,3,4,5,6的六辆车,顺序开入栈式结构的站台,则可能的出栈顺序有多少种?
(2)若进站的六辆列车顺序如上述,那么是否能够得到435612,325641,154623,135426的出战顺序,如果不能,请说明为什么不能;如果能,说明如何得到。


1)第一题不会做 答案也看不懂
然后上水木请教了,不过一般大侠都很忙,给了三字锦囊 catalan google之
然后google到了一些东西,h(n)=c(2n-2,n-1)/n
一个c++学习者对于atalan的总结
这个网站上,其他一些学习编程的心得也不错
组合数学中的catalan数
我的理解:
可以对这6辆车的出栈次序计数作如下分析
我们把这6辆车分为如下5种分组:
前1辆车后5辆车,前2后4,前3后3(123 456),前4后2,前5后1(12345 6)
我们总是让前组的车完成出栈后 再让后组车进栈,并且我们人为的规定后组车的第一辆车进栈后不会立刻弹出,要不然会和后一种情形重复,得少算一种情况。最后654321这样的出栈顺序并未包含在上述分组中。
至此,我们将6辆车的出栈次序全部列出,并令其为函数f(k),k=1,2...6
那么f(6)=f(1)*(f(5)-1)+f(2)*(f(4)-1)+f(3)*(f(3)-1)+f(4)*(f(2)-1)+f(5)*f(1)
好像不对
还是很晕,得回去查一下组合数学的书,恩,得好好看。
答案应该是h(n+1)=c(2n,n)/(n+1)
后注:在二叉树计数一章有详细的讲解

2)不可能得到435612和154623这两种出栈序列,问题出在最后的12和23不可能实现。
325641:1进-2进-3进-3出-2出-4进-5进-5出-6进-6出-4出-1出
135426:1进-1出-2进-3进-3出-4进-5进-5出-4出-2出-6进-6出

4-4试证明:若借助栈可由输入序列1,2,3,...,n得到一个输出序列p1,p2,p3...pn(它是输入序列的某种排列),则在输出序列中不可能出现以下情况,即存在i< j< k,使得pj< pk< pi。

假设,存在这样的pj< pk< pi
首先i< j,即pi先于pj出栈,而我们根据题意知道输入序列从小到大进栈,pj< pi,那么pj先于pi是先进栈的。所以pi和pj之间的进出栈关系是pj进栈,pi进栈,pi出栈,pj出栈。---1
然后我们看j< k,同样pj先于pk出栈,而pj< pk,那么pj先于pk入栈,那么pj和pk之间的关系是:pj进栈,pj出栈,pk进栈,pk出栈。---2
再考察i< k,pi先于pk出栈,pk< pi,pk先于pi入栈,那么:pk入栈,pi入栈,pi出栈,pk出栈.--3
把序列3代入2,得到 pj进,pj出,pk进,pi进,pi出,pk出。其结果和序列1矛盾.
故不存在这样的出栈序列

4-5写出下列中缀表达式的后缀形式:
(1)A×B×C
(2)-A+B-C+D
(3)A×-B+C
(4)(A+B)×D+E/(F+A×D)+C
(5)A&&B||!(E >F)
(6)!(A&&!((B< C)||(C >D)))||(C< E)
3-10 如果用循环链表表示一元多项式,试编写一个函数Polynominal::Calc(x),计算多项式在x处的值。
思路:模仿书里用单链表的方式表示一元多项式,ListNode代表多项式中的一项,类型Type实例化为Term。Term用struct定义,包括coef(系数)和exp(指数),他们都是共有数据成员,所有能够使用Term对象的函数都可以存取它们。并且把term对象声明为polynominal的私有成员。

struct Term{ //链表结点data的数据类型
int coef; //系数
int exp; //指数
Term(int c,int e){coef=c;exp=e;}
};

class Polynominal{
//多项式按指数从小到大排列,不声明构造函数等其他函数了
public:
Polynominal(); //构造函数,不声明了
~Polynominal();
double Calc(double x);
private:
CircList poly; //循环链表结构,data部分数据类型为Term
};

//以下实现Cacl函数
double Polynominal::Calc(double x){
Term current; //当前项
double sum=0.0; //存放最后的结果
int len; //多项式的项数
poly.First(); //当前指针指向第一项
len=poly.Length(); //求项数
for(int i=1;i<=len;i++){
current=poly.getData();
sum+=current->coef * pow(x,current->exp)
//pow(x,y)函数,求x的y次幂函数
poly.Next(); //下一项
}
}


3-12 试设计一个实现下述要求的locate运算的函数。设有一个带有表头结点的双向链表L,每个结点有4个数据成员:指向前驱结点的指针prior、指向后继结点的指针next、存放数据的成员data和访问频度freq。所有结点的freq初始时都为0。每当在链表上进行一次Locate(L,x)操作时,令元素值为x的结点的访问频度freq加1,并将该结点前移,链接到与它的访问频度相等的结点后面,时的链表中所有结点保持按访问频度递减的顺序排列,以使访问频繁的结点靠近表头。

思路:Locate函数参数为双向链表L和元素值x,通过双向链表的公共操作实现该函数的功能。
声明:为双向链表结点类加入 freq域,同时在双向链表类中加入两个公共操作
int getfreq();取得当前结点的freq值,返回
addfreq(); 当前结点的freq值增加1
同时原Insert函数,加入新结点时默认将freq置为0

void Locate(DblList< Type > L,Type& x){
if(!Find(x))
{cout << "Not find!\n";return}
int i; Type tmp;
i=getfreq(); //取得原freq值
tmp=getData(); //该结点的值
Remove(); //删去该结点
while(Prior())
/*寻找应该插入的位置,如果到了first,那么prior()返回0,current指向first*/
if(getfreq() > i)
return;
Insert(tmp); //插入
for(int k=0;k<=i;k++)
addfreq(); //设定freq,比原先大1
}
http://tel6.800disk.com/index.aspx
密码:tsinghuacs


大伙弄得,以后有东西也传上去点
3-4 设计一个算法,通过一趟遍历在单链表中确定值最大的结点。

声明:在单链表类的基础上加入一个操作(公共函数)
思路:设置一个变量max暂存当前找到的最大值的结点,然后从单链表的第一个结点开始比较,如果找到比max值大的点则,替换max值。

template< class Type > ListNode< Type > *List< Type >::Max(){
//在当前的单链表中找出值最大的结点,并返回该结点的地址.
ListNode *p=first->link;
ListNOde *max=p;
while(p != NULL){
if(p->data > max->data)
max=p;
p=p->link; //遍历
}
return max;
}


3-5 设计一个算法,在非递减有序的单链表中删除值相同的多余结点。

声明:在单链表类的基础上加入一个操作(公共函数)。
思路:同上题,依然是一次遍历,因为单链表本身已经按照非递减顺序排好,只需要检查p->link是否和p的值一样,如果一样的话,就删除。

template< class Type > void List< Type >::Zip(){
//将非递减有序链表压缩,删去拥有相同值的多余结点。
ListNode *p=first->link,*q=NULL;
while(p != NuLL&&p->link != NULL){
if(p->data==p->link->data){ //相邻两点是否相等
q=p->link;p->link=q->link; //重新拉链
delete q;
}
eles p=p->link; //指针p进到下一位
}
}


3-6 设有一个表头指针为h的单链表。试设计一个算法,通过遍历一趟链表,将链表中所有结点的链接方向逆转。要求逆转结果链表的表头指针h指向原链表的最后一个结点。

声明:和参考答案的思路有区别。
思路:与3-3类似,p循链检测链表,并将当前指针p所指向的结点插到第一个结点位置,再重置p=pnext。pnext为预先保留的指针,指向原链中p的下一个结点。

void Inverse(ListNode *h){
ListNode *p=h->link,*pnext;
while(p!=NULL){
pnext=p->link; //保留p的下一个指针
p->link=h->link;h->link=p; //插到第一个节点位置
p=pnext; //p再往前走一位
}
}


3-7 从左到右及从右到左遍历一个单链表是可能的,其方法是在从左向右遍历的过程中将连接方向逆转,如p102页图所示。在图中的指针p指向当前正在访问的结点,指针pr指向指针p所指结点的左侧的结点。此时,指针p所指结点左侧的所有结点的链接方向都已逆转。
(1)编写一个算法,从任一给定的位置(pr,p)开始,将指针p右移k个结点。如果p移出链表,则将p置为0,并让pr停留在链表最右边的结点上。
(2)编写一个算法,从任一给定的位置(pr,p)开始,将指针p左移k个结点。如果pr移出链表,则将pr置为0,并让p停留在链表最左边的结点上。
(ps:题目应该把p和pr弄反了)

(1)思路:用tmp暂存p,然后p右移一位,tmp->link指向pr,逆转连,然后pr=tmp。检查p有没有溢出。
void moveright(ListNode *pr,ListNode *p,int k){
ListNode *tmp;
for(int i=1;i <= k;i++){
if(p==NULL||p==0){
p=0;
return;
}
tmp=p;p=p->link; //向右逆转
tmp->link=pr;pr=tmp;
}
}


(2)和上一样 p和pr对换
void moveleft(ListNode *pr,ListNode *p,int k){
ListNode *tmp;
for(int i=1;i <= k;i++){
if(pr==NULL||pr==0){
pr=0;
return;
}
tmp=pr;pr=pr->link; //向左逆转
tmp->link=p;p=tmp;
}
}


3-8 试写出适合循环链表的游标类定义,并编写它的3个成员函数First()、Next()和NextNotNull()的实现程序。这些函数的功能应该和单链表的相应操作相同。

思路:模仿单链表的Iterator类

ListNode前视定义 CLIterator类为友元
CircList前视定义 CLIterator类为友元
……
enum Boolean{False,True};
temple< class Type > class CLIterator{
public:
CLIterator(const CircList< Type > &l):list(l),current(l.first){}
Boolean NextNotNull();
Type *First();
Type *Next();
private:
const CircList< Type > &list;
ListNode< Type > *current;
}

template< class Type > Boolean CLIterator< Type >::NextNotNull(){
//检查链表中下一个元素是否非空.
if(current!=NULL&¤t->link!=NULL)
return Ture;
else return False;
}

template< class Type > Type * CLIerator< Type >::First(){
//返回指向链表中第一个结点的指针.
if(list.first->link!=NULL){
current=list.first;
return & current->data;
}
else{current=NULL;return NULL;}
}

template< class Type > Type * CLIerator< Type >::Next(){
//返回当前指针的下一个结点的指针.
if(current!=NULL){
current=current->link;
return & current->data;
}
else{ current=NULL;return NULL;}
}
3-3 设ha和hb分别是两个带表头结点的非递减有序单链表的表头指针,试设计一个算法,将这两个有序链表合并成一个非递增有序的单链表。要求结果链表仍使用原来两个链表的存储空间,不另外占用其它的存储空间。表中允许有重复的数据。

思路:以ha为表头,比较a和b链的元素,依次将当前的较小值插入到第一个结点位置,正好可以逆序合并。

ListNode * Merge(ListNode *ha,ListNode *hb){     
ListNode *pa, *pb; //a和b的pointer
ListNode *tmp; //暂存待链入的节点
LIstNode *left; //剩余部分
pa=ha->link; //初始化
pb=hb->link;
ha->link=NULL;
while(pa!=NULL && pb!=NULL){
if(pa->data <= pb->data)
{tmp=pa; pa=pa->link;}
else {tmp=pb;pb=pb->link;}
tmp->link=ha->link; //链入ha
ha->link=tmp;
}
left=(pa != NULL)?pa:pb;
while(left != NULL){ //处理剩下的链
tmp=left;left=left->link;
tmp->link=ha->link;
ha->link=tmp;
}
}
心有多大,舞台就有多大!
如果没有记错的话,很久以前在我还看电视的时候,这是央视3套经常用来自我标榜的广告。

我很清楚自己,心比天高,运气却比狗屎还狗屎,无论我做的多好,老天总是会跟我开一些不愉快的玩笑;最近老是梦想能中个500万,结果彩票站的老板却很惊讶的问我,“按理说,你应该至少能中几次5块啊!”是的,按十六分之一的概率来说,我至少能中5-8次了。用同事的话说,我属于那种直接中500万的,恩有道理,不过除非那500万是堆××。

我想要的太多,想学当然只是想学的也很多,那么我的舞台到底在哪呢?我具备了前提,总该有个答案。今天在操场上跑圈,我就一直思考这个问题,是计算机么?考计算机的研究生,并不意味着我想成为一个encoder,事实上我想成为一个老板(#¥%@#¥……%¥……)。回过头来看看,我学的东西确实也不少了,涉足了很多领域,虽然都很肤浅,或者说我具备了一些综合能力,可以站在一个宏观的角度去看待这些学科,也许这就是我的舞台,而这个视角就是computer science。我甚至可以妄断,将来绝大多数领域的突破都会是借助于计算机实现的,而我也许可以把目光放在这样的舞台上,试图去创造它,让那些和我一样有着绝世idea的奇才(唉,自p~),不再因为一张文凭而去考研究生。
2-14 字符串的替换操作replace(String &s, String &t, String &v) 是指:若t是s的子串,则用串v替换t在串s中的所有出现;若t不是s的子串,则串s不变。试利用字符串的基本运算实现这个替换操作。
基本思路:s串中寻找t的匹配,找到後,在t处将t去掉,正好把s串一分为二,上半段接上目标串v,下半段继续寻找t的匹配,然后重复以上操作,并把前半段加入上一次操作的上一段。最后将上下两段合并,即完成所需要的replace操作。
所有操作均利用书上字符串类所给的公共函数实现

void Replace(String &s, String &t, String &v){
String tmp; //建立临时子串,存放上半段
while (int pos=s.Find(t) != -1){
tmp += s(0,pos) += v; //链入上半段和v
s=s(pos+t.length(),s.length()-pos-t.length());//产生s下半段
}
if (tmp.length()){ //如果没有替换声明一下
cout << "未找到可替换的子串" << endl;return;
}
else { s = tmp += s;return;} //整合
}

与参考答案相比,几乎完全不一样,这里的replace操作是一个独立的操作,s也作为一个变量。
另外题目要求利用字符串的基本运算操作,我的理解是利用那些公共函数,而不该去用存储结构部分。在一般情况下,这个replace函数不会放在类里。或者会成为一个新的类的函数。

2-16 设串s为“aaab”,串t为“abcabaa” ,串r 为"abcaabbabcabaacbacba",试分别计算他们的失效函数f(j)的值。
解:
"aaab" f(0)=-1 f(1)=0 f(2)=1 f(3)=-1
"abcabaa" f(0)=-1 f(1)=-1 f(2)=-1 f(3)=0
f(4)=1 f(5)=0 f(6)=0
"abcaabbabcabaacbacba"
f(0)=-1 f(1)=-1 f(2)=-1 f(3)=0 f(4)=0 f(5)=1
f(6)=-1 f(7)=-1 f(8)=1 f(9)=2 f(10)=3 f(11)=-1
f(12)=0 f(13)=0 f(14)=-1 f(15)=-1 f(16)=0 f(17)=-1
f(18)=-1 f(19)=0

ps:题目里有个空格,不过我想空格也只不过相当于个符号,去之。练习。

2-17 没太理解题目的意思,是再抄一遍p66 p67 呢 还是要用纯粹的数学上的方法证明?
感觉这离开模式匹配的环境就没有意义了。
[合集] 大家推荐些有助于考研的英文阅读材料吧

恩,回头找找这几样,加到google reeder里去,7月份可以看。

Science American或Newsweek之类的,号称考研英语阅读很多都是从那上面来

推荐小印的那个200篇,至少材料还不错,而且还有翻译。有电子板的

newyorktime
2-9 设有一个n×n的对称矩阵A,如教材p69页a图所示。为了节约存储,可以只存对角线及对角线以上的元素,或者只存对角线或对角线以下的元素。前者称为上三角矩阵,后者称为下三角矩阵。我们把它们按行存放于一个一维数组B中,如图(b)和图(c)所示。并称之为对角矩阵A的压缩存储方式。试问:
(1)存放对称矩阵A上三角部分或下三角部分的一维数组B有多少元素?
(2)若在一维数组B中从0号位置开始存放,则如图a所示的对称矩阵中的任一元素a(ij)在只存上三角部分的情形下(图b)应存于一维数组的什么下标位置?给出计算公式。
(3)若在一维数组B中从0号位置开始存放,则a(ij)只存下三角时,对应在c数组中的下标计算公式?


(1) n是矩阵A对角线元素的个数 那么 B的元素个数就是 (n×n-n)/2+n=n(n+1)/2

(2) 矩阵元素a(ij)的编号是从1开始的,只存上三角的话,j肯定不小于i。
a(ij)前面有i-1行,第一行有n个元素,后依次是n-1,n-2,...,n-(i-2).然后第i行,a(ij)前有j-i个元素。所以
b数组的下标k=(n+n-(i-2))*(i-1)/2+j-i+0=(2n-i)*(i-1)/2+j-1
如果a(ij)不处于上三角位置时,只需将i与j对换即可。

(3) 思考方法同2
i>=j时 k=(1+(i-1))*(i-1)/2+j=i(i-1)/2+j
i < j时 k=j(j-1)/2+i



2-10 设A和B均为n*n的下三角矩阵,二维数组C,有n行n+1列。试设计一个方案,将A的下三角区域中的元素存放于C的下三角区域中,B先转置后存放于C的上三角区域中。给出计算A的矩阵元素a(ij)和B的矩阵元素b(ij)在C中的存放位置下标的公式。

对于A矩阵和B矩阵,只考虑i >= j的情形。
设在C中存放的位置为c[p][q] 因为是二维数组,所以均从0开始。同时为方便起见,矩阵A和B我们也假设是从0号还是计数。

那么对于a(ij)来说
p=i q=j;

对于b(ij)来说
首先是转置,那么i与j对换;b(ji)=b(ij)
然后这个上三角矩阵存入C中时,要右移一个位置,以保证不覆盖C的下三角区域。所以
p=j q=i+1;

2-11 三对角矩阵的定义:在该矩阵中除了主对角线及在主对角线上下最临近的两条对角线上的元素外,所有其他元素均为0.现在要将这样的三对角矩阵A中的非零元素按行存入一维数组B中,且a(11)存放在B[0]。给出a(ij)(1<=i<=n,i-1<=j<=i+1)在一维数组B中的存放位置的计算公式。

问题可以转化为a(ij)前有几个元素。
1) i=1时 j-i;
2) 1 < i < n时 (i-1)*3-1+j+1-i
3) i=n时 (i-1)*3-1+j+1-i
最后可以统一这三种情况
j+2i-3


2-12 设带状矩阵是n×n阶的方阵,其中所有的非零元素都在有主对角线及主对角线上下各b条对角线构成的带装区域内,其他元素都为零。试问:
(1)该带状矩阵中有多少个非零元素?
(2)设a11存放在B[0]中,试给出所有非零元素a(ij)在一维数组B中的存放位置。



1)只需求出下三角区域内有多少个零元素即可。(1+(n-1-b))*(n-1-b)/2=(n-b)(n-b-1)/2
这样的区域有2个 (n-b)(n-b-1)
非零元素个数为 n*n-(n-b)(n-b-1)=(2b+1)n-b(b-1)

2)同上题 必定有 1 <=i<=n i-b<=j<=i+b
感觉应该存在可以用通式把各种情况下的结果都写出来,但是找不到这样的通式,继续思考中。
答案给的好复杂。
2-5 顺序表的插入和删除要求仍然保持各个元素原来的次序。设在等概率情形下,对有127个元素的顺序表进行插入,平均需要移动多少个元素?删除一个元素,又平均需要移动多少个元素?

插入:一个有128个位置可以插入,平均移动元素个数为
n=(127+126+125+...+2+1+0)/128=(127+0)*128/2/128=63.5个
删除:一共127个元素可以删除,平均移动元素个数为
n=(126+125+...+2+1+0)/127=63个

2-6 若矩阵A(m×n)中的某一元素A[i][j]是第i行中的最小值,同时又是第j列中的最大值,则称此元素为该矩阵的一个鞍点。假设以二维数组存放矩阵,试编写一个函数,确定鞍点在数组中的位置(若鞍点存在时),并分析该函数的时间复杂度。

如果写成 z=A[x][y] 那么就可以在空间坐标中,画出这些点,并用光滑的曲面连接这些点,就可以得到一个曲面。比较容易想像鞍点的样子。同时这个鞍点只能有一个,这和连续曲面有所不同。
感觉没有什么特别的办法,只能一行一行的扫描,然扫描这些行最小值的列号。用s[i]来存储。

int saddle(int A[][],const int m,const int n){
int *s=new int[m]; //s[i]用来存储行最小值的列号
int *c=new int[n]; //c[j]用来存储列最大值的行号
int i, j,k;
for (i=0;i < m;i++;){
s[i]=0; //用来存j
for (j=1;j < n;j++) // 扫描各行,将最小值的j存入s[i]
if (A[i][j] < A[i][s[i]]) s[i]=j;
}
for (j=0;j < n;j++) c[j]=-1; //-1标记没有访问过
for (i=0;i < m;i++){ //循s[i]
tmp=0;
if (c[s[i]] == -1){
for (k=0;k < m;k++) //扫描s[i]列,找出最大的行号
if (A[k][s[i]] > A[tmp][s[i]]) tmp=k;
c[s[i]]=tmp;
}
if (c[s[i]]==i){ //扫描了s[i]列如果A[i][s[i]]是鞍点
cout << "The saddle point is :(" << i << "," << s[i] << ")" << endl;
return 1; //找到鞍点
}
}
return 0; //未找到鞍点
}

当m远小于n时,这段程序的执行效率略高于答案。
算法的基础是考虑,首先找出各行的最小列号。然后,我们要比较的列,只有这几个出现的列号,而不需寻找所有的列(答案就搜索了所有列)。同时会出现不同行的最小列号有可能相等,用c[j]数组去标记该列有没有被查找过,如果查过就存入最大行号。答案似乎没有认识到鞍点只有一个

该算法的总时间复杂度还是O(m×n)

2-7 设有一个二维数组A[m][n],假设A[0][0]存放在位置644(十进制,后同),A[2][2]存放位置在676,每个元素占一个空间,问A[3][3]存放在什么位置?

如果是行优先的话,那么数组的存储方式一定是
A[0][0] A[0][1] A[0][2]...A[1][0]A[1][1]A[1][2]...A[2][0]A[2][1]...
所以loc(2,2)-loc(0,0)=2*m+2 m=15
A[3][3]=3*15+3+644=692
列优先与行优先的情况时一样的。

2-8 计算多项式Pn(x)=a0x^n+a1x^(n-1)+a2x^(n-2)+...+a(n-1)x+an的值。可以用递归的方法求解Pn(x)=x*P(n-1)(x)+an.试写出这个递归函数。

系数存储在double coef[n+1]中,不另作声明

double poly(int n,double x){
if (n == 0) return coef[n];
else return x*poly(n-1,x)+coef[n];
}
这个是pkblog提供的getway
通过这个域名就可以自由访问了,哈!
http://www.pkblogs.com/zzswang
现在是双域名 但愿GFW不会同时把俩都封了。
老域名,只要不在中国大陆都是可以链接的
http://zzswang.blogspot.com

至于bloggerspace的ftp发布功能还是暂时不用了,太麻烦.
好了,呼,终于可以继续做算法题了。
Sigh,写这个标题,自己都哭笑不得了。还打算利用这个页面和研友讨论下习题的做法之类的,现在又该如何呢。唉~ 我是突破封锁上来了,别人呢?这又不是什么受欢迎的大站。还要别人学一学hack么。

主要的方法来源于
http://groups.google.com/group/ggpi/web/hostwiki
=================================================================================
通常情况下,我们可以通过修改Windows系统下的Hosts文件,以正常访问blogspot。

  以XP为例,用记事本打开下面的文件:

C:\WINDOWS\system32\drivers\etc\hosts

  再手动添加下面的内容即可:

72.14.219.190 blogspot地址

  比如:

72.14.219.190 googleblog.blogspot.com

  用这个方法,将你经常访问的blogspot blog给添加进去,每行一个,即可以正常访问它们了。记得修改完后,保存一下。

  读者"GG GG"在邮件里建议大家共同参与编辑下面的Hosts wiki页面:

  http://groups.google.com/group/ggpi/web/hostwiki

  即把自己的blogspot blog地址添加进去。理论上,当所有blogspot用户都参与了编辑后,就得出了一个"无敌"的Hosts文件,拥有它,blogspot就可完全正常访问了。虽然有点"愚公移山"的味道,但总比什么都不做要好一些。
=====================================================================================

我只是添加了自己blog的 host ip。另外暂时在blogger未被解封前不打算更新这里的blog了。
还未公布的blog,就这样几乎要胎死腹中了。
2-1 设n个人围坐在一个圆桌的周围,现在从第s个人开始报数,数到第m个人,就让他出局;然后从出局的下一个人重新开始报数,数到第m个人,再让他出局,……,如此反复直到所有的人全部出局为止。下面要解决的Josephus问题是:对于任意给定的n,s和m,求出这n个人的出局序列。请以n=9,s=1,m=5为例,人工模拟Josephus的求解过程以求得问题的解。

解:1,2,3,4,5,6,7,8,9
第一轮5 1.2.3.4.'6'.7.8.9
第二轮1 '2'.3.4.6.7.8.9
第三轮7 2.3.4.6.'8'.9
第四轮4 2.3.'6'.8.9
第五轮3 2.'6'.8.9
第六轮6 2.'8'.9
第七轮9 '2'.8
第八轮2 '8'
第九轮8

2-2 试编写一个求解Josephus问题的函数。用整数序列1,2,3……,n表示顺序围坐在圆桌周围的人,并采用数组表示作为求解过程中使用的数据结构。然后使用n=9,s=1,m=5,以及n=9,s=1,m=0,或者n=9,s=1,m=10作为输入数据,检查你的程序的正确性和健壮性。最后分析所完成算法的时间复杂度。
其实参考答案已经很好了,只是想给出一种不同的方法练习一下。
利用table[1]=2,table[2]=3,table[3]=4,...,将table表串起来,每次报数淘汰后,比如3号淘汰,那么修改table[2]=4,继续报数。
同时引入table[0]=3,表示第一个淘汰的人,然后再将淘汰的人存入table[3],则最后在输出出局顺序时可以比较方便。当然也可以让table[3]=1,表示第一轮被淘汰的,可以让数组直观的表示该人是第几局出局的。视程序需要而定。这两种方法在输出结果和程序的直观性方面要比参考答案的好一点,而且不需要用%运算.
接下来的程序里使用table[0]的方法。

void jparray(int n,int s,int m){
if(m==0||s>n||s==0||n==0){ //参数检查
cerr << "参数无效!要求m,n,s为自然数,且开始人序号s要小于等于n!" << endl;
return;
}
int i,k,j=0;
int table[n+1];
for (i=0;i < n;i++)table[i]=i+1; //把人链起来
table[n]=1; //让尾回到第一个人
int pre=n; //指向前一个人
for (i=s;){ //开始报数的人
for(k=1;k < m;k++){
pre=i;
i=table[i]; //向后走m-1步,报数从1到m.i为报数到m的人。
}
j=table[j]=i; //j为从table[0]开始的出局顺序表。
i=table[pre]=table[i]; //删掉原i,并重建下一轮开始报数人i。
if (i == pre) { //剩下最后一个人了。
table[j]=i; //链上最后一个人
table[i]=0; //结束标志。
return;
}
//以下输出出局顺序。
cout << "圆桌" << n << "个人,从第" << s << "个人开始报数" << m << "的出局顺序是:/n" << endl;
for (i=0;table[i]!=0;i=table[i])cout << table[i] << " " << endl;
}


算法的时间复杂度,n×m+n 为O(nm),这个方法比较适合在n大,m小的时候,此时比参考答案的方法要小很多。
好事不出门,坏事传千里
考研未必是件坏事,但若是辞掉每天200元的工作还考不上,那绝对是件丢脸的蠢事。
本来打算静悄悄的试一次,免得再多一份遗憾离开北京。
但我太低估了自己的受关注度,从向公司提起辞职到现在也就一周,甚至在辞职里我一句都未提考研的事,老总和同事深情的挽留,我都三缄其口,只是表示要回家,孝子为先。但就这一周的时间,现在也不管是猜测,还是朋友的传递扩大效应,一下子似乎所有关心我或者和我保持联系的人,都知道这个天大的蠢事了。
现在唯一能做的,而且必须做的,绝对不能让它成为蠢事。
samara对此事的评价是,这件事要看结果而定论。
彻底颠覆了我所谓的 为了完成一个7年来没走完的一个过程而已 的想法或者借口。
突然之间,压力排山倒海而至。
(1) 在下面所给函数的适当地方插入计算count的语句:

void d (ArrayElement x[],int n){
int i = 1;
count++; //针对i赋值
do{
x[i]+=2; count++; i+=2;
count++;
count++; //针对do while
}while(i<=n);
i=1;
count++;
while(i<=(n/2)){
count++; //针对while
x[i]+=x[i+1]; count++; i++; count++;
}
count++; //针对while的最后一次比较
}


在上程序段中,用桔黄语句表示插入的count句。

(2) 将由1得到的程序简化。使得化简后的程序与化简前的程序具有相同的count值。
2,3小题很没劲,不做了。
1-8 设n为正整数,分析下列各程序段中斜线部分语句的执行次数。
(1)

for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
c[i][j]=0.0;
for (int k=1;k<=n;k++)
c[i][j]=c[i][j]+a[i][k]*b[k][j];
}

执行了n^3次。

(2)

x=0;y=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=i;j++)
for (int k=1;k<=j;k++)
x=x+y;

执行次数为1+(1+2)+(1+2+3)+...+(1+2+3+...+n)
计算得n^3/6+n^2/2+n/3
ps:这个程序段也太搞笑了,加来加去x还是0.

(3)

int i=1,j=1;
while(i<=n&&j<=n){
i=i+1; j=j+1;
}

j随着循环次数k的递增是j=1+2+3+...+k+k+1
即(k+2)(k+1)/2<=n
解不等方程得
k <=(开根(8n+1)-3)/2
最后一次执行i=i+1必定是第一次导致j>n的结果,所以
执行次数为 取下整((开跟(8n+1)-3)/2)+1

(4)

int i=1;
do{
for (int j=1;j<=n;j++)
i=i+j;
}while(i < 100+n);

分析,
j=1,2,3,4……
i=2,4,7,11……
正好符合递推公式i=1+(n+1)n/2
而当n=14时,i=106< 100+n
当n=15时,i=121 >100+n
程序句的执行次数分如下情况
当n>=15时,程序的执行次数由内循环for决定,而外循环do while只能执行一次,所以程序的执行次数为n次;
然后计算n=1~14的情况
设k为外循环while的执行次数,则程序结束前一步,i的值
i=1+k(n+1)n/2< 100+n 其中k为满足不等式的最大值
此时,外循环将再执行一次,所以语句共执行次数为(k+1)*n
ps:我感觉这里配套教材给出的答案是错的。

下月可以正式离开公司,这个月也基本上是全天看书的状态。是时候该安排一下,未来这6个月(天呐,只有6个月了)的复习总计划。

这个月就不另作安排了,还是按照原来计划,完成四方面的内容。
数据结构的习题;《什么是数学》;英语初级语法知识点;英语阅读《达芬奇密码》.


七月份
  • 高等数学
  • 计算机原理
  • 英语六级试卷
  • 收集大纲及资料

八月份
  • 数理统计
  • 操作系统
  • 完成GRE核心词汇

九月份
  • 毛概,马哲
  • 计算机习题
  • 数理统计和线代习题
  • 英语

十月份
  • 邓论、三个代表及当前国际政治
  • 英语考研卷子
  • 数学考研卷子
  • 计算机考研卷子

十一月份
  • 根据卷子反应出来的不足补充
  • 政治开始背及卷子
  • 英语

十二月份
  • 政治冲刺
  • 英语冲刺
  • 数学冲刺
  • 计算机冲刺
白忙活了一早上,输入的代码都被自动转换掉了……
看了几页blogger的源代码,大致猜了几个输入常用的代码
< code > 好像给编码有特定的格式
< pre > 预格式化,保留空格和回车之类的吧
<输入方式----& lt;
>输入方式——& gt;

同时切换了一个比较容易辨识code的模板
先凑合着,等哪天有兴趣,自己搞一个模板
1-6 什么是算法?算法的5个特性是什么?试根据这些特性解释算法与程序的区别。

Algorithm,算法的定义为一个有穷的指令集,这些指令集为解决某一特定任务规定了一个运算序列。一个算法应当具有以下5个特性:
1.输入
2.输出
3.确定性
4.有穷性
5.有效性
算法与程序不同,程序不满足上述特性4.


1-7 试编写一个函数计算n!×2^n的值,结果存放于数组A[arraySize]的第n个数组元素中,0<=n<=arraySize.若设计算机中允许的整数最大值为maxInt,则当n>arraySize或者对于某一个k(0<=k<=n),使得k!*2^k>maxInt时,应按出错处理。可有如下三种不同的出错处理方式:
(1)用cerr << 及exit(1)语句来终止执行并报告错误;
(2)用返回整数函数值0,1来实现算法,以区别是正常返回还是错误返回;
(3)在函数的参数表设置一个引用型的整型变量来区别是正常返回还是某种错误返回。 试讨论这三种方法各自的优缺点,并以你认为是最好的方式实现它。


(1)函数直观易懂,表示简洁;

const int maxInt=某一个整数
const int arraySize=某一个整数
int calculate(int n){ //函数主体
if(!0<=n<=arraySize) { //如果n超出范围,出错返回
cerr << "n is out of the range!" << endl; exit(1);
}
int *A=new int[n]; //A[n]
A[0]=1;
for(i=1;i<=n;i++){
A[i]=A[i-1]*i*2;
if(A[i]>=maxInt){ //如果某个k!*2^k>maxInt出错返回
cerr << "n is out of the range!" << endl; exit(1);
}
return A[n]; //返回函数计算结果
}

(2)通过函数返回0或者1来判断函数运行的结果,但是函数的运算结果需要另外查找A[arraySize]数组的结果。

const int maxInt=某一个整数
const int arraySize=某一个整数
int calculate(int n){ //函数主体
if(!0<=n<=arraySize) //如果n超出范围,出错返回
return 0;
int *A=new int[n]; //A[n]
A[0]=1;
for(i=1;i<=n;i++){
A[i]=A[i-1]*i*2;
if(A[i]>=maxInt) //如果某个k!*2^k>maxInt出错返回
return 0;
return 1; //返回函数计算结果
}

(3)函数是否运行成功,不能从函数本身得到结果,需要另外考查ret变量,如果变量在函数运行後依然是1,则运行成功,反之失败。函数直接返回运算结果。

const int maxInt=某一个整数
const int arraySize=某一个整数
int ret=1; //函数return状态,0错误,1正常
int calculate(int n,int& ret){ //函数主体
if(!0<=n<=arraySize){ //如果n超出范围,出错返回
ret=0;
return;
}
int *A=new int[n]; //A[n]
A[0]=1;
for(i=1;i<=n;i++){
A[i]=A[i-1]*i*2;
if(A[i]>=maxInt){ //如果某个k!*2^k>maxInt出错返回
ret=0;
return;
}
return A[n]; //返回函数计算结果
}

这年头,商机都被人抓疯了,水木考研资料版简直就一集市。
可惜像我这样的人,总是要先问一下,网上有不?
恩,姑且先当作复习资料的目录吧

【转让】08年清华大学计算机考研全套复习资料(最新超全版)
【转让】清华cs专业课考研资料

还是比较喜欢水到渠成的学习方式,恩,先从基础打起,这些先放一放。

参考书目录
http://166.111.4.136:8080/yjsy/main.nsf/0/A7A3A5361F60FAC7C82572210006CFDB
1-1 什么是数据?它与信息是什么关系?

数据(data)是信息的载体,是描述客观事物的数、字符、以及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。

数据是信息的抽象表示。


1-2 什么是数据结构?有关数据结构的讨论涉及哪三个方面?

数据结构由某一数据对象及该对象中所有数据成员之间的关系组成,记为:Data_Structure={D,R}。其中,D是某一数据对象,R是该对象中所有数据成员之间的关系的有限集合。

通常我们讨论数据结构涉及三个方面:
1.各种在解决问题时可能遇到的典型的逻辑结构——数据结构;
2.这些逻辑结构的存储映像——存储实现;
3.数据结构的相关操作及其实现。


1-3 数据结构分为线性结构和非线性结构两大类。线性结构包括数组、链表、栈、队列、优先级队列等;非线性结构包括树、图等,这两类结构各自的特点是什么?

线性结构中各个数据成员依次排列在一个线性序列中,有且仅有一个开始成员和一个终端成员,并且所有数据成员都最多有一个直接前驱和一个直接后继;非线性结构中各个数据成员不再保持在一个线性序列中,每个数据成员可能与零个或多个其他数据成员发生联系。


1-4 什么是数据抽象类型?试用C++的类声明定义“复数”的抽象数据类型。要求:
(1)在复数内部用浮点数定义它的实部和虚部。
(2)实现3个构造函数:缺省的构造函数没有参数;第二个构造函数将双精度浮点数赋给复数的实部,虚部置为0;第三个构造函数将两个双精度浮点数分别赋值给复数的实部和虚部。
(3)定义获取和修改复数的实部和虚部,以及+、-、*、/等运算的成员函数。
(4)定义重载的流函数来输出一个复数。


抽象数据类型通常是指由用户定义,用以表示应用问题的数据模型。抽象数据类型由基本的数据类型构成,并包括一组相关的服务。

//在头文件Cnumber.h中定义的复数类
#ifndef_Cnumber_h_
#define_Cnumber_h_
#include< iostream.h > //不知道该如何输入"<"iostream.h">"只好多出空格

class Cnumber{ //complex number类
private:
double a; //复数的实部
double b; //复数的虚部
public:
Cnumber():a(0),b(0){} //无参数构造函数
Cnumber(double x):a(x),b(0){} //只有实部的构造函数
Cnumber(double x,double y):a(x),b(y){} //实部和虚部的构造函数
~Cnumber(); //析构函数
double getreal(){return a;} //获取实部
double geti(){return b;} //获取虚部
setreal(double x){a=x;} //设定实部
seti(double y){b=y;} //设定虚部
Cnumber operator = (Cnumber y); //两复数=运算重载
Cnumber operator + (Cnumber y); //两复数+运算重载
Cnumber operator - (Cnumber y); //两复数-运算重载
Cnumber operator * (Cnumber y); //两复数*运算重载
Cnumber operator / (Cnumber y); //两复数/运算重载
friend ostream& operator << (ostream& outstream,Cnumber& z); //输出一个复数
}

#endif

//复数类Cnumber的相关服务的实现放在C++源文件Cnumber.cpp中
#include<>
#include<>
#include"Cnumber.h"

Cnumber operator = (Cnumber y){
a=y.a;
b=y.b;
return this;
}

Cnumber Cnumber::operator + (Cnumber y){
Cnumber z;
z.a=a+y.a;
z.b=b+y.b;
return z;
}

Cnumber Cnumber::operator - (Cnumber y){
Cnumber z;
z.a=a-y.a;
z.b=b-y.b;
return z;
}

Cnumber Cnumber::operator * (Cnumber y){
Cnumber z;
z.a=a*y.a-b*y.b;
z.b=a*y.b+b*y.a;
return z;
}

Cnumber Cnumber::operator / (Cnumber y){
Cnumber z;
z.a=(a*y.a+b*y.b)/(y.a*y.a+y.b*y.b)
z.b=(b*y.a-a*y.b)/(y.a*y.a+y.b*y.b)
return z;
}

ostream& operator << (ostream& OutStream,Cnumber& y){
OutStream << y.a << (Y.b>=0.0)?"+":"-" << fabs(Y.b) << "i";
//fabs()取绝对值函数
return OutStream; }

华山的奇险秀丽,已经超出我的描绘能力了。
于是整理了几张华山上拍摄的照片,留作纪念。


遥看秦岭


西山落日


朝阳峰上观日出


云梯——武当梯云纵的灵感?



苍龙岭,当年韩愈爬到这里,把书一扔,往地上一坐,开始哭着求救。
看到一篇热心的考研成功者,留下的牛经验
圆梦清华:2007年研究生考试英语81分经验谈

作者从7月份开始正式复习,居然与我的复习安排不谋而合,6月是我在公司的最后一个月,过了这个月我的生活将会变得无比的充实,我想充实这个词要比刻苦、紧张之类的要好的多。

看到作者留下的英语学习方法和如何背单词,不禁想到了自己的背单词方法。

是该回过头来总结一下了。看书到现在也有2个月了,因为一些工作上的羁绊,效率总体上来说不好。本该两周自学完成的线性代数,结果花了一个月的时间,又加上第一次接触,还来不及做习题。5月份的数据结构,到昨天晚上为止,算是看到了最后的80%,不过也是最难的部分,每一页都要花掉我很多时间,已经是5月的最后一天。计划总是赶不上变化。

最满意的部分就是英语学习,底子太差了,好像还停留在高中的水平,前进的也比较快,最近才觉得有点难以往前推进了,可能需要大量的阅读来铺展一下吧。
看到作者讲如何背单词的部分,我不禁有点自鸣得意,心想比起他的方法,我自己的安排,效率应该高上许多倍,也省却许多烦恼。既然是考cs,我背单词的方法也是充分利用了cs——软件。

第一个使用的软件是词汇大爆炸,好像又叫斯宾浩斯曲线记忆法之类的。很不错的软件,通过它可以先做到熟悉单词,我设置的是4秒一个单词,选中文意思,软件会根据记忆曲线自动安排这个单词下一次出现的时间。就这样,我第一周就背掉了1000个单词,那一个月(4月份)无论看到什么,听到什么,第一个反映就是这是什么单词,以至于吃饭的时候在盘子里的菜都要先确认是什么单词……不过我想我还是过于冒进,大爆炸选词汇集的时候,选的是1万3000的全部GRE词汇。以至于在背了4000多个单词后(算上反复出现的话,应该背了4万多单词次),出现了4月底5月初,长达3周的罢工,真的要吐了,一天吃不成一个胖子。打算下一次选择7000个的GRE核心词汇。

5月20号开始,订制了新的计划,因为罢工的原因,开始着急了,暂时先放下先熟悉单词的念头,直接用上了我爱背单词,选择了考研词汇,共2500个,理由是无论多高的楼都要有核心的支柱。到今天共背了2周不到,只在公司背,也就是只有8,9天的样子,每天三个30分钟时间,每组时间一个list。浏览,听音听写,看意默写。其实我的词汇量本来很小,也就2,3k(高中水平,6级没过),但这几天背的还是超快,因为很多单词在上个月看到过,虽然不太会写,但有印象,所以很快就背了一半了。再有两周时间这部分核心词汇,就可以比较熟练了。

这几天开始训练听力和阅读了,单词这个东西光背,还是很表面的,很容易就忘记了,要有充分的训练。基础听力和阅读部分,安排在了每天的早晚,听力用的是podcast,算是和cs搭边了,呵呵。ELS 的podcast非常简单,介绍美英和美国人文之类的,估计高中生就听得懂,偶就一边听一边锻炼身体或者练练字啥的。阅读打算用大学的英语教材吧,除了第一本看过几页外,其他都没动过呢。(非常庆幸高中的英语还是蛮好的……)

还有一种阅读方式,巧妙的借用了金山词霸的两大功能。我最近开始看 《The.Da.Vinci.Code》,里面可以说每一句都有一个甚至好几个我不认识的单词,天呐。不过还好,我们有金山词霸,里面有些法文的地名可以用google翻译。不懂的单词,用金山的屏幕取词,出来的小框框有一个很小的按钮,加入到生词本,对了,就是这个。哈哈,所有遇到的不懂得单词都在这里了。我每天看半章,然后打开生词本,把遇到的不懂的单词过一遍,效果好极了。可能选的这本书难了点(但我想我还是坚持下去了,发现自己对法文还挺感兴趣),用这个方法,甚至可以选择任何阅读材料,可以挑一些简单的。只要保证你的生词本里没有陌生度大于0的单词,就过关了。网上应该有各种各样的英语阅读资料,新闻,小说,甚至是新概念,只要你想得到的。

同事昨天还批评我,说我一点都不像考研的人,身边都没有红宝蓝宝的,也没什么重点突击之类的。其实,对于考研,我只是把它当成一种历练,我只是觉得自己浪费了7年,真正需要在各方面给自己充下电了。英语,我希望它能变成我的一种自由的语言。
尽管计划了很久,但提交辞呈的那一瞬间,还是有点伤感,毕竟在这里工作了三年。

吴老总是很惋惜的跟我说,可惜,可惜,我本来打算怎么怎么地~

我心里想说,三年了,该用的你不用,说了的你也不听。

三年了,我自认为还是有点才能和眼光的,却楞是没地方发挥,没人看得上啊。

于是我终于等不下去了。

不仅仅是这三年,我甚至为这所有在北京的七年后悔。

这世上又哪里有后悔药呢。除了往前走,别无选择。

于是在我的计划里,我选择了我曾经无可奈何的,以为被命运安排而放弃了的梦想,我突然想努力了。七年,也许给我最深刻的道理,就是人只能做好自己想做的事。

决定了去追寻,就好好的去努力。就像爱情,决不能再犹豫。
把公司电脑上的照片都整理了一边

放在了google的网络相册里,建立公开和不公开的相册

其中公开相册的地址是
http://picasaweb.google.com/zzswang
我自己都很惊讶,在看完正统的教材《线性代数》后,《什么是数学》成了我下一个计划内的数学学习内容了,而放着那么多的教材不看。

我承认我比较崇拜这些国外的科学家写的书,尤其是理论方面的,他们写的很精彩,引人入胜,看着看着就喜欢上了。而不是像一些国内的教材,及其枯燥。

这本书的作者是Richard Courant & Herbert Robbins & Ian Stewart,其中R.柯朗这个人比较牛,书里面是这么介绍的,20世纪杰出的数学家,哥廷根学派重要成员。他生前是纽约大数学系和数学科学研究院的主任,该研究院后被重命名为柯朗数学科学研究院。他写的书《数学物理方程》为每一个物理学家所熟知,而他的《微积分学》已被认为是近代写的最好的该学科的代表作。

够牛的一个人,他的《微积分学》我要是能找到中译本的话,说不定就拿它当教材了。

《什么是数学》,爱因斯坦是这么评论这本书的,“对整个数学领域中的基本概念及方法的透彻清晰的阐述”。虽然我要应付的是考试,但我想,掌握数学,最好的方法还是透彻的理解它,所以在看其他冲刺、满分之类的书前,我打算先知道什么是数学。
Google日历简直太符合我的要求了。
以后可以在家里或者公司,都能随时了解自己的安排。

花了半天时间,在网上做了份计划。goole日历可以随心所欲的安排,真的很棒。
时间排的紧紧的,希望自己能够坚持下去。
大雁塔,原名慈恩塔,最早由唐僧主持修建的。当然经过无数次的修整,早已物是人非。
在大雁塔东侧回廊厢房内,有一座千手观音的玉浮雕屏风。
这堪称一件国宝级的艺术品,静静的立在大庭广众之下,观音千手千面,千手尽执人间屠戮,千面尽显人世百态,因其长期浸润在香火之中隐隐然似有佛光。
当然在我的眼里,它依然是一件艺术品;显然有一位女士和我的看法不一样,她觉得是一件吉祥物。上前抚摸之,应是招财许愿之流,同时似乎也受其佛光影响,赞叹,“这东西果然比我们单位的那座好多了,手感真好!”于是呼唤同伴,有福同享。
旁边的大和尚终于不能忍,义正言辞,“你们单位的,不过是一件玩物,一件东西,但这里的不是,这是我们供奉的佛祖,容不得亵渎,不是一个层次的,根本没法比较。”并再三强调,佛祖是受供奉的。
女游客们再傻,也立刻意识到在这个佛教圣地,自己犯下了一个愚蠢的错误,慌忙缩回手,退开一丈,解释自己的无知,以期减轻自己对佛祖的冒犯之罪。大和尚唱个诺,又做回原座,周围的一切又与他无关了,好像一下子又从红尘回到了菩提树下。
当我重新审视千手观音,不禁想起来一句话,“佛如人,人如佛。”那个我自在的佛又在哪里呢。
既到世间,不论是佛还是人,不过都是这尘世的一粒沙。
拥有梦想是一件幸福的事!
但是不肯为梦想付出,整日徘徊在彷徨的边缘,那么即便是再快乐的游戏,也会变成痛苦的煎熬和自责!
快乐与梦想同行!