实验一:栈和队列 实验目的:
掌握栈和队列特点、逻辑结构和存储结构
熟悉对栈和队列的一些基本操作和具体的函数定义。 利用栈和队列的基本操作完成一定功能的程序。 实验任务
1.给出顺序栈的类定义和函数实现,利用栈的基本操作完成十进制数N与其它d进制数的转换。(如N=1357,d=8)
实验原理:将十进制数N转换为八进制时,采用的是“除取余数法”,即每次用8除N所得的余数作为八进制数的当前个位,将相除所得的商的整数部分作为新的N值重复上述计算,直到N为0为止。此时,将前面所得到的各余数反过来连接便得到最后的转换结果。 程序清单
#include success,overflow,underflow }; class stack { public: stack(); bool empty()const; error_code get_top(DATA_TYPE &x)const; error_code push(const DATA_TYPE x); error_code pop(); bool full()const; private: }; stack::stack() { count=0; } bool stack::empty()const { return count==0; } error_code stack::get_top(DATA_TYPE &x)const { if(empty()) return underflow; else { x=data[count-1]; return success; } } error_code stack::push(const DATA_TYPE x) DATA_TYPE data[MAXLEN]; int count; { if(full()) return overflow; else { data[count]=x; count++; } } error_code stack::pop() { if(empty()) return underflow; else { count--; return success; } } bool stack::full()const { return count==MAXLEN; } void main() { stack S; int N,d; cout<<\"请输入一个十进制数N和所需转换的进制d\"< cout<<\"输出转换结果:\"< cout< 2.给出顺序队列的类定义和函数实现,并利用队列计算并打印杨辉三角的前n行的内容。(n=8) 实验原理:杨辉三角的规律是每行的第一和最后一个数是1,从第三行开始的其余的数是上一行对应位置的左右两个数之和。因此,可用上一行的数来求出对应位置的下一行内容。为此,需要用队列来保存上一行的内容。每当由上一行的两个数求出下一行的一个数时,其中的前一个便需要删除,而新求出的数就要入队。 程序清单: #include success,underflow,overflow }; class queue { public: queue(); bool empty()const; error_code get_front(DATA_TYPE &x)const; error_code append(const DATA_TYPE x); error_code serve(); bool full()const; private: }; queue::queue() { rear=0; front=0; } bool queue::empty()const { } error_code queue::get_front(DATA_TYPE &x)const return (front%MAXLEN==rear%MAXLEN); int front,rear; DATA_TYPE data[MAXLEN]; { if(empty()) return underflow; else { x=data[front%MAXLEN]; return success; } } error_code queue::append(const DATA_TYPE x) { if(full()) return overflow; else { data[rear%MAXLEN]=x; rear++; } } error_code queue::serve() { if(empty()) return underflow; else { front++; return success; } } bool queue::full()const { return((rear+1)%MAXLEN==front); } void main() { queue Q; int num1,num2; int i=0; cout<<1< for(j=0;j<=i;j++) { (num2); (); cout< cout<<1< 3.给出链栈的类定义和函数实现,并设计程序完成如下功能:读入一个有限大小的整数n,并读入n个数,然后按照与输入次序相反的次序输出各元素的值。 实验原理:依次将栈中的元素出栈,因为栈的一个特点就是先进后出,。这样,当将原栈为空时,输出与输入次序相反,从而实现了本题的要求。 程序清单: #include typedef struct LNode { DATA_TYPE data; LNode *next; }LNode; enum error_code { range_error,success,underflow }; class linkstack { public: linkstack(); ~linkstack(); bool empty()const; error_code push(const DATA_TYPE x); error_code get_top(DATA_TYPE &x)const; error_code pop(); private: }; linkstack::linkstack() { top=NULL; count=0; LNode *top; int count; DATA_TYPE data; } bool linkstack::empty()const { return (count==0); } error_code linkstack::push(const DATA_TYPE x) { LNode *s=new LNode; s->data=x; s->next=top; top=s; count++; return success; } error_code linkstack::get_top(DATA_TYPE &x)const { if(empty()) return underflow; else { x=top->data; return success; } } error_code linkstack::pop() { if(empty()) return underflow; else { LNode *u=new LNode; u=top; top=top->next; delete u; count--; return success; } } linkstack::~linkstack() { while(!empty()) { pop(); } } void main() { linkstack L; int n; cout<<\"请任意输入一个整数n:\"< for(int i=1;i<=n;i++) { (i); } while(!()) { (i); cout<测试数据:n=9 i=1 运行结果: 实验二:单链表 实验目的: 理解线性表的链式存储结构。 熟练掌握动态链表结构及有关算法的设计。 根据具体问题的需要,设计出合理的表示数据的链表结构,并设计相关算法。 实验任务: 在一个递增有序的链表L中插入一个值为x的元素,并保持其递增有序特性。 1.实验数据:链表元素为(10,20,30,40,50,60,70,80,90,100),x分别为25,85,110和8。 实验原理:给出了要插入的条件,但没有给定插入位置。因此,需要搜索满足这一条件的插入位置的前驱结点而不是序号。 程序清单: #include int data; struct snode *next; }node; enum error_code{arrange_error,success}; class list { public: list(); void create2(); int length() const; error_code get_element(const int i,int &x) const; error_code insert(const int &x); error_code delete_element(const int i); node *locate(const int x) const; node *get_head(){return head;} void print(); private: }; list::list() { } void list::create2() { } int list::length() const { } return count; int x; node *p=head; node *s; cout<<\"输入一个值:\"; cin>>x; while(x!=-1) { } s=new node; s->data=x; s->next=NULL; p->next=s; p=s; cin>>x; cout<<\"输入一个值:\"; head=new node; head->next=NULL; count=0; int count; node *head; error_code list::get_element(const int i,int &x) const { int j=1; node *p=head->next; while(p!=NULL&&j!=i) { p=p->next; j++; } if(p==NULL) return arrange_error; x=p->data; return success; } node *list::locate(const int x) const{ node *p=head->next; while(p!=NULL) { if(p->data==x) return p; p=p->next; } return NULL; } error_code list::insert(const int &x){ node *s; node *q=head; while(p!=NULL&&p->data } { } if(p==NULL) { } else{ } return success; s=new node; q->next=s; s->data=x; count++; s->next=q->next; s=new node; s->data=x; q->next=s; count++; q=p; p=p->next; s->next=NULL; error_code list::delete_element(const int i) { } node *u; node *p=head; int j=0; while(j!=i-1&&p!=NULL) { } if(i<1||i>count) return arrange_error; p->next=u->next; count--; p=p->next; j++; u=p->next; delete u; return success; void list::print() { } void main() { } list l; int x; cout<<\"创建一个链表(输入‘-1’结束):\"< (x); cout<<\"输入一个数:\"; cin>>x; node *p=head->next; while(p!=NULL) { } cout< 测试数据:链表元素为(10,20,30,40,50,60,70,80,90,100),x分别为25,85,110和8。 运行结果: 2.将单链表L中的奇数项和偶数项结点分解开,并分别连成一个带头结点的单链表,然后再将这两个新链表同时输出在屏幕上,并保留原链表的显示结果,以便对照求解结果。 实验原理:依据题目的要求,需要再创建两个新链表来存储分离后的奇偶项,而奇偶项可以根据数字来控制,把他们取出来并重新连起来。 程序清单: #include int data; struct snode *next; }node; enum error_code{arrange_error,success}; class list { public: list(); void create2(); int length() const; error_code get_element(const int i,int &x) const; error_code insert(const int &x); error_code delete_element(const int i); node *locate(const int x) const; node *get_head(){return head;} divide(list &B,list &C); void print(); private: }; list::list() { } void list::create2() { int x; node *p=head; node *s; cout<<\"输入一个值:\"; cin>>x; head=new node; head->next=NULL; count=0; int count; node *head; } while(x!=-1) { } s=new node; s->data=x; s->next=NULL; p->next=s; p=s; cin>>x; cout<<\"输入一个值:\"; int list::length() const { } error_code list::get_element(const int i,int &x) const { } node *list::locate(const int x) const { node *p=head->next; int j=1; node *p=head->next; return count; while(p!=NULL&&j!=i) { } if(p==NULL) return arrange_error; p=p->next; j++; x=p->data; return success; } while(p!=NULL) { } return NULL; if(p->data==x) return p; p=p->next; void list::divide(list &B,list &C) { } error_code list::insert(const int &x) node *u; node *pa=head->next; node *pc=(); node *pb=(); for(int i=0;pa!=NULL;i++,pa=pa->next) { } u=new node; if(i%2==0) { } else { } pb->next=NULL; pc->next=NULL; pc->next=u; pc=pc->next; pb->next=u; pb=pb->next; u->data=pa->data; { } error_code list::delete_element(const int i) { node *u; node *p=head; int j=0; node *s; node *q=head; node *p=head->next; while(p!=NULL&&p->data return success; s=new node; q->next=s; s->data=x; count++; s->next=q->next; s=new node; s->data=x; q->next=s; count++; q=p; p=p->next; s->next=NULL; while(j!=i-1&&p!=NULL) { } if(i<1||i>count) return arrange_error; p->next=u->next; p=p->next; j++; u=p->next; } delete u; return success; count--; void list::print() { } void main() { } 测试数据:第一组数据:链表元素为 (1,2,3,4,5,6,7,8,9,10,20,30,40,50,60) 第二组数据:链表元素为 (10,20,30,40,50,60,70,80,90,100) 运行结果: list A,B,C; (); (B,C); (); (); (); int x,y,z; node *p=head->next; while(p!=NULL) { } cout< cout<<\"原表:\"; cout<<\"奇数表:\"; cout<<\"偶数表:\"; 3.求两个递增有序链表L1和L2中的公共元素,并以同样方式连接成链表L3。 实验原理:设置两个指针怕,pa,pb分别依次指示A,B表中的元素,其初始值分别为>next和>next。在pa,pb均非空时,根据其值的大小关系可能有如下三种情况。 (1).pa->data==pb->data:搜索到公共元素,应在C表表尾插入一个结点,其值为 pa->data,然后继续A表中下一个元素的搜索,即pa=pa->next,同时pb也往后移。 (2). pa->data>pb->data:表明A表中这一元素可能在B表当前元素的后面,因此要往B 表的后面搜索,故而执行pb=pb->next,然后继续搜索。 (3). pa->data 继续对A表中下一个元素的判断。 反复执行上述比较,直到pa,pb至少有一个为空为止。此时,剩余的非空部分没有所 需要的公共元素,因而搜索结束。 程序清单: #include int data; struct snode *next; }node; enum error_code{arrange_error,success}; class list { public: list(); void create2(); int length() const; error_code get_element(const int i,int &x) const; error_code insert(const int &x); error_code delete_element(const int i); node *locate(const int x) const; node *get_head(){return head;} void list::gongyou(list &L1,list &L2) void print(); private: }; list::list() { } void list::create2() { int x; node *p=head; head=new node; head->next=NULL; count=0; int count; node *head; } node *s; cout<<\"输入一个值:\"; cin>>x; while(x!=-1) { } s=new node; s->data=x; s->next=NULL; p->next=s; p=s; cin>>x; cout<<\"输入一个值:\"; int list::length() const { } error_code list::get_element(const int i,int &x) const { } void list::gongyou(list &L1,list &L2) int j=1; node *p=head->next; return count; while(p!=NULL&&j!=i) { } if(p==NULL) return arrange_error; p=p->next; j++; x=p->data; return success; { node *p1=>next; node *p2=>next; node *p3=head; node *u; while(p1!=NULL&&p2!=NULL) { if(p1->data==p2->data) { u=new node; u->data=p1->data; p1=p1->next; p2=p2->next; } else{ if(p1->data p1=p1->next; else p2=p2->next; } } p3->next=NULL; } node *list::locate(const int x) const { node *p=head->next; while(p!=NULL) { if(p->data==x) return p; p=p->next; p3->next=u; p3=p3->next; } } return NULL; void list::divide(list &B,list &C) { } error_code list::insert(const int &x) { node *s; node *q=head; node *p=head->next; node *u; node *pa=head->next; node *pc=(); node *pb=(); for(int i=0;pa!=NULL;i++,pa=pa->next) { } u=new node; if(i%2==0) { } else { } pb->next=NULL; pc->next=NULL; pc->next=u; pc=pc->next; pb->next=u; pb=pb->next; u->data=pa->data; while(p!=NULL&&p->data p=p->next; } } if(p==NULL) { } else{ } return success; s=new node; q->next=s; s->data=x; count++; s->next=q->next; s=new node; s->data=x; q->next=s; count++; s->next=NULL; error_code list::delete_element(const int i) { } void list::print() { node *u; node *p=head; int j=0; while(j!=i-1&&p!=NULL) { } if(i<1||i>count) return arrange_error; p->next=u->next; count--; p=p->next; j++; u=p->next; delete u; return success; node *p=head->next; while(p!=NULL) { cout< } cout< void main() { list L1,L2,L3; (); (); (L1,L2); cout<<\"共有的元素为:\"; } 测试数据:第一组数据: 第一个链表元素为 第二个链表元素为 第二组数据: 第一个链表元素为 第二个链表元素为运行结果: (); 1,3,6,10,15,16,17,18,19,20) 1,2,3,4,5,6,7,8,9,10,18,20,30)1,3,6,10,15,16,17,18,19,20) 2,4,5,7,8,9,12,22) ( ( ( ( 实验三:二叉树 一、 实验目的 1. 掌握二叉树的动态链表存储结构及表示。 2. 掌握二叉树的三种遍历算法(递归和非递归两类)。 3. 运用二叉树三种遍历的方法求解有关问题。 二、实验任务 1. 建立一棵采用二叉链表结构存储的二叉树。 2. 分别采用递归和非递归两种方式对该二叉树进行先序、中序和后序遍历。 3. 求二叉树的高度以及二叉树中叶子结点的数目。 实验原理:在二叉链表存储结构中,每个结点应包括存储结点值的数据部分及指向两个孩子结点的指针,不妨设为data,lchild和rchild。对二叉树的遍历是在对各子树分别遍历的基础之上进行的。由于各子树的遍历和整个二叉树的遍历方式相同,因此,可借助对整个二叉树的遍历算法来实现对左、右子树的遍历。 程序清单: #include<> #define maxlen 200 enum tagtype{L1,L2}; typedef struct node { char data; struct node *lchild,*rchild; }bnode; typedef struct{ bnode *ptr; tagtype tag; }stacknode; enum error_code{success,underflow,overflow}; class stack { public: stack(); bool empty()const; bool full()const; error_code get_top(stacknode &x); error_code get_top(bnode* &x); error_code push(stacknode x); error_code push(bnode* x); error_code pop(); private: int count; bnode* data_xian[maxlen]; stacknode data_hou[maxlen]; }; stack::stack() { count=0; } bool stack::empty()const { if(count==0) return true; return false; } bool stack::full()const { if(count==maxlen) return true; return false; } error_code stack::get_top(stacknode &x) { if(empty()) return underflow; x=data_hou[count-1]; return success; } error_code stack::get_top(bnode* &x) { if(empty()) return underflow; x=data_xian[count-1]; return success; } error_code stack::push(stacknode x) { if(full()) return overflow; data_hou[count]=x; count++; return success; } error_code stack::push(bnode* x) { if(full()) return overflow; data_xian[count]=x; count++; return success; } error_code stack::pop() { if(empty()) return underflow; count--; return success; } #include\"\" class bitree { public: bitree(); bnode *create(); bnode *get_root(){return root;} int max(int a,int b); void preorder1(){preorder1(root);} void inorder1(){inorder1(root);} void postorder1(){postorder1(root);} void preorder2(){preorder2(root);} void inorder2(){inorder2(root);} void postorder2(){postorder2(root);} int high(bnode *T); int leaf(bnode *T); private: bnode *root; void visite(bnode *T); void preorder1(bnode *T); void inorder1(bnode *T); void postorder1(bnode *T); void preorder2(bnode *T); void inorder2(bnode *T); void postorder2(bnode *T); }; bitree::bitree() { root=NULL; } bnode* bitree::create() { char ch; bnode *p; cin>>ch; cout<<\"输入二叉树的值:\"; if(ch=='#') return NULL; p=new bnode; if(root==NULL) root=p; p->data=ch; p->lchild=create(); return p; } p->rchild=create(); int bitree::max(int a,int b) { if(a>=b) return a; return b; } void bitree::preorder1(bnode *T) { if(T!=NULL) { } } void bitree::inorder1(bnode *T) { visite(T); preorder1(T->lchild); preorder1(T->rchild); if(T!=NULL) { preorder1(T->lchild); visite(T); preorder1(T->rchild); } } void bitree::postorder1(bnode *T) { if(T!=NULL) { preorder1(T->lchild); preorder1(T->rchild); } } void bitree::preorder2(bnode *T) { stack s; if(T!=NULL) { (T); while(!()) { (T); (); visite(T); if(T->rchild!=NULL) (T->rchild); if(T->lchild!=NULL) (T->lchild); }cout< visite(T); } void bitree::inorder2(bnode *T) { stack s; if(T!=NULL) { } } void bitree::postorder2(bnode *T) { stack s; stacknode x; do{ while(T!=NULL) while(T!=NULL||!()) { while(T!=NULL) { } if(!()) { } (T); (); T=T->rchild; (T); T=T->lchild; visite(T); }cout< } =T; (x); =L1; T=T->lchild; int continue1=1; while(!()&&continue1) { (x); (); T=; switch { case L1: =L2; T=T->rchild; continue1=0; (x); } break; case L2:visite(T); break; } } int bitree::high(bnode *T) { if(T==NULL) return 0; }while(!()); cout< int bitree::leaf(bnode *T) return max(high(T->lchild),high(T->rchild))+1; { if(T==NULL) return 0; if(T->lchild==NULL&&T->rchild==NULL) return 1; return leaf(T->lchild)+leaf(T->rchild); } void bitree::visite(bnode *T) { cout< void main() { bitree b; int x; (); cout<<\"创建一个先序二叉树(输入‘#’为空):\"< cout<<\"先序遍历为:\"; cout<<\"中序遍历为:\"; cout<<\"后序遍历为:\"; cout<<\"树的高度为:\"; cout<<\"叶子结点数为:\"; break; (); (); (); cout< cout<<())< case 2: cout<<\"先序遍历为:\"; cout<<\"中序遍历为:\"; cout<<\"后序遍历为:\"; cout<<\"树的高度为:\"; cout<<\"叶子结点数为:\"; break; (); (); (); cout<<())< 运行结果: 实验四:图 一、 实验目的 1. 掌握图的基本概念。 2. 掌握图的存储结构的设计与实现,基本运算的实现。 3. 掌握图的两种遍历算法,以及遍历算法的应用。 二、实验任务 1.分别以邻接矩阵和邻接表的存储结构建立图。 2.分别对图进行深度优先遍历和广度优先遍历。 3.求图中边的数目。 实验原理:邻接矩阵是表示图中顶点之间邻接关系的矩阵,即表示各顶点之间是否有边关系的矩阵。因此,对有n个顶点的图来说,其邻接矩阵A为n*n阶的,其中Aij表示顶点vi到vj之间是否有边或弧:若存在,则Aij为1,否则为0。邻接表的表示方式是将每个顶点的邻接点连成链表,并将各链表的表头指针合在一起,其中每个头指针与该结点的信息合为一个整体结点。在执行遍历dfs(v)时,搜索下一个访问顶点是从当前访问顶点v的邻接表中搜索的,因此,每搜索到一个邻接点即意味着搜索到一条以v为一个端点的边或弧,故应在dfs算法中计数。 程序清单: #include const int maxvertex=100; class graph { public: graph(); void createadj(); void trave_dfs(); void trave_bfs(); void dfs(int v); void bfs(int v); int firstadj(int v); int nextadj(int v,int m); void visit(int v); void edgenum(); void dijkstra(int v0); private: }; int vertex[maxvertex]; int edge[maxvertex][maxvertex]; int currentvertex; bool visited[maxvertex]; graph::graph() { } void graph::createadj() { int i,j,k; cout<<\"输入当前顶点数:\"; cin>>currentvertex; int i,j; for(i=0;i vertex[i]=0; for(k=0;k edge[i][j]=edge[j][i]=1; cout<<\"输入两个顶点的值(输入-1,-1结束):\"; cin>>i>>j; cin>>i>>j; cout<<\"输入第\"< } } void graph::trave_dfs() { } void graph::trave_bfs() { } void graph::dfs(int v) { int w; visit(v); w=firstadj(v); int i; for(i=0;i bfs(vertex[i]); visited[i]=false; int i; for(i=0;i dfs(vertex[i]); visited[i]=false; visited[v]=true; while(w!=-1) { } if(!visited[w]) w=nextadj(v,w); dfs(w); } void graph::bfs(int v) { } int graph::firstadj(int v) { if(v!=-1) { for(int i=0;i return i; queue Q; int w,x; visit(v); (v); visited[v]=true; while(!()) { } (x); (); v=x; w=firstadj(v); while(w!=-1) { } if(!visited[w]) { visit(w); (w); visited[w]=true; }w=nextadj(v,w); } }return -1; int graph::nextadj(int v,int m) { } void graph::visit(int v) { } void graph::edgenum() { } void main() { int num=0,i,j; for(i=0;i num++; cout< return i; }return -1; cout< graph G; cout<<\"用邻接矩阵存储建立图:\"; (); cout<<\"对图的深度优先遍历:\"; cout<<\"对图的广度优先遍历:\"; cout<<\"该图的边数为:\"; (); cout< 实验五:查找 一、 实验目的 1. 掌握顺序表的查找方法,尤其是二分查找方法。 2. 掌握二叉排序树的建立与查找。 二、实验任务 1. 对下列数据表,分别采用二分查找算法实现查找,给出查找过程依次所比较的元素(的下标),并以二分查找的判定树来解释。 实验原理:设查找区域的首尾下标分别用变量low和high表示,将待查关键字x和该区域的中间元素的关键字进行比较。 程序清单: #include<> int bin_search(int a[],int n,int x); int bin[25]; void main() { int int i=0; a[]={1,2,3,4,6,7,8,9,10,11,12,13,17,18,19,20,24,25,26,30,35,40,45,50,100}; int x,n,num; n=sizeof(a)/4; cout<<\"二分查找为(输入-1查找结束):\"< cout<<\"查无此数。\"< else{ } cout<<\"要查找的数的下标为:\"< } } cout<<\"输入要查找的数:\"; cin>>x; int bin_search(int a[],int n,int x) { } 测试数据: 数据表为 (1,2,3,4,6,7,8,9,10,11,12,13,17,18,19,20,24,25,26,30,35,40,45,50,100) 查找的元素分别为: 2,8,20, 30,50,5,15,33,110 运行结果: int mid,low=0,high=n-1; while(low<=high) { mid=(low+high)/2; bin[i]=mid; i++; if(a[mid]==x) return mid; else if(a[mid] }return -1; 实验六:排序 一、 实验目的 1. 掌握各种内部排序算法。 2. 理解各种内部排序算法的特性、时间性能和空间性能,在此基础上能根据具体情况 选择合适的排序算法。 二、实验任务 1. 实现希尔排序算法,并观察在采用不同的步长选取方法对排序过程中数据的比较和 移动次数的影响。 实验原理:将待排序列划分为若干组,在每组内进行直接插入排序,以使整个序列基本有序,然后再对整个序列进行直接插入排序。 程序清单: #include<> void shell_sort(int a[],int n); void main() { int n; int a[]={180,203,32,46,25,76,17,58,99,100,11,102,13,54,75,6,27,18,19,29,2,82}; } void shell_sort(int a[],int n) { } 运行结果: int i,j,temp,d=n/2; while(d>0) { }