中南大学
《数据结构》课程设计
题 目一 运动会记分系统
题 目二 猴子选大王
题 目三 航班订票系统
学生姓名 兰 清 指导教师 盛 羽
学 院 信息科学与工程学院
专业班级 计算机科学与技术0403班
学 号 0902040319
完成时间 2006 年1 月12 日
目 录
第一章 课程设计目的.............................................. 3
第二章 课程设计内容和要求........................................ 3
第三章 课程设计分析................................................ 4
第四章 结束语......................................................28
第五章 参考文献.................................................28
.
.
.
第一章 课程设计目的
通过课程设计题目的练习,强化学生对所学知识的掌握及对问题分析和任务定义的理解,对每到题目作出了相应的逻辑分析和数据结构的选择,通过对任务的分析,为操作对象定义相应的数据结构,以过程化程序设计的思想方法为原则划分各个模块,定义数据的抽象数据类型。分模块对题目进行设计,强化学生对C语言的掌握和对数据结构的选择及掌握。通过程序的编译掌握对程序的调试方法及思想,并且让学生学会使用一些编程技巧。促使学生养成良好的编程习惯,
以及让学生对书本上的知识进行了实践。
第二章 课程内容设计和要求
(一)问题分析和任务定义
对问题的描述应避开具体的算法和涉及的数据结构,它是对要完成的任务作出明确的回答,强调的是做什么,而不是怎么做。
(二)详细的设计和编码
算法的具体描述和代码的书写。
(三)上机调试
源程序的输入和代码的调试。
要求:设计中要求综合运用所学知识,上机解决一些与实际应用结合紧密的、规模较大的问题,通过分析、设计、编码、调试等各环节的训练,深刻理解、牢固的掌握数据结构和算法设计技术,掌握分析、解决实际问题的能力。
第三章 课程设计分析
3.1 题目一
首先声明,我不想按要求上的格式来写这个报告,因为他的条条框框太限制人的思维了,请见谅。另外,我也不会用一大堆的代码来凑字数,或者用一两个截图来炫耀程序界面,代码本身并不重要,重要的是实现功能的思想,或者是程序本身的创新,而且我不得不承认了一个友好的界面对于一个产品的成功是至关重要的,但是其决定因素还是你的产品所提供的功能。从本质上来讲这是一篇编程的反思,而绝对不是一份好的报告,下面我主要介绍介绍我编程的一些感想和收获。
猴子选王
这是此次实习的选作题目,题目如下:
5、猴子选大王
任务:一堆猴子都有编号,编号是1,2,3 ...m ,这群猴子(m个)按照1-m的顺序围坐一圈,从第1开始数,每数到第N个,该猴子就要离开此圈,这样依次下来,直到圈中只剩下最后一只猴子,则该猴子为大王。
要求:
输入数据:输入m,n m,n 为整数,n<m
输出形式:中文提示按照m个猴子,数n 个数的方法,输出为大王的猴子是几号 ,建立一个函数来实现此功能
因为刚学mfc觉得写一个windows界面的程序一定挺酷的,所以先前都把心思放在界面上了,是后来才优化的。
拿到这个题目很自然的想法是用一个循环的链表来实现它,假设猴子的个数是n,m是要淘汰的编号,那么建立一个n长的链表,链表最后一个元素的next指针指向第一个元素,这样就形成一个循环链表,而链表的数据域储存的就是猴子的编号。好那就顺着这种自然的想法我们来实现他。
首先是实现循环链表这个数据结构下面用c++的方式来实现:
下面给出我的实现,只给出定义,和一些重要的方法的实现:
template <class T> class CirList;//使用的是类模版
template <class T> class Node//结点定义
{
friend class CirList<T>;//定义友元是为了使用其私有的数据
private:
Node <T> *next;
T data;
public:
Node(Node<T> *pnext = NULL ):next(pnext){}
~Node(const T &item,Node <T> *pnext = NULL):data(item),next(pnext){}
void setnext(Node<T> * p){next = p;}
void setdata(T d){data = d;}
T getdata(){return data;}
~Node(){};
};//class Node
template <class T> class CirList//循环链表
{
private:
Node<T> *head;//头结点
Node<T> *current;//当前结点
int len;
public:
CirList(){ head=NULL; current=head; len=0;}
//编译器报错:HEAP[Data.exe]: Invalid Address specified to RtlValidateHeap( 00360000, 00366198 )
virtual ~CirList()//定义了指针并且为指针分配了空间的的类,一定要记得释放空间,否则会造成内存泄露。
{
if(head == NULL) return;
current=head;
Node<T> *work;
while(current->next != head)
{ work=current->next;
delete current;
current = work;
}
delete current;
}
T GetData();//返回当前结点的值
int Lenght();
void ToHead();//把当前结点移动到头结点
void PushBack(T d);//压入链表的尾部
void PopBack();//把尾元素弹出
void DelCur();//删除当前结点,并把后面一个结点补充上来
void Next();//当前结点后移
};template <class T>
//这里的堆分配有点奇怪
//删除一个元素后,原来的分配会变化
//也许系统会自动把后面的元素往前移动
//微软就是喜欢自作聪明
//
//Node<T> *work1=new Node<T>(0,NULL);
//Node<T> *work2=new Node<T>(1,NULL);
//Node<T> *work3=new Node<T>(2,NULL);
//delete work2;
//刚刚作了一个实验,证明实际上情况不是如此
//原来搞了那么久错误是:if(current = head)因该是if(current == head)
//好冤枉啊,也错怪了我们的盖茨兄
//在程序中很容易放此类错误,不过《专家编程》有一个很好的建议//就是,变量和常量比较是把常量放在==左边,这样如果你错写为//=号的时候编译器就会报错(试图为一个常量负值在c/c++中是非//法的),可见,好的编程习惯对一个程序员是多么重要
template <class T>
void CirList<T>::DelCur()
{
Node<T> *work;
work = head;
while(work->next != current)
work = work->next;
work->next = current->next;
if(current == head)//出错的地方(写成了current = head)
head = current->next;//删除表头的时候表头后移.不然会报错
delete current;
current = work->next;
len--;
}
基于这个结构的猴子选王的算法如下:(具体的说明在代码中解释)
//算法的主要部分,iTotal是猴子总数m,iChoose是要被淘汰的猴子编号n,
//返回值是猴子王的编号
//时间复杂度就是m+(m-1)X(n-1)了,而空间复杂度就是存m个数据的cirList用的空间了
//具体来说就是m X ( 4 + 4 ) + 8个字节了,
//其中4+4是结点Node<int>中data + next的空间,8是cirList中head + current的空间
//不过我想有更好的办法,想想吧
//改进想法但n很大的时候要经历很多次无用的循环
//然他对链表的长度取余数可以减少很多次循坏即(iChoose-1)%cirList.Lenght()
//大约n*(n-1)/2次
int MonkeyDlg::ChooseKing(int iTotal,int iChoose)//改进算法
{
m_Progress.SetRange32(0,iTotal-1);m_Progress.SetPos(0);
m_MProgress.SetRange32(0,iTotal);
m_MProgress.SetPos(0);//进度条的初始化
int i;
CirList<int> cirList;
for(i=0;i<iTotal;i++)//循环次数m
{
cirList.PushBack(i+1);//构建一个循环链表
m_MProgress.StepIt();//这里是设置进度条的位置用于显示进度