数据结构实验指导
转自:http://www.cnblogs.com/wc1903036673/p/3413006.html
《 — 数据结构 —》
实验指导书
朱素英 编 写
适用专业: 计算机科学与技术
计算机网络工程
湖南人文科技学院计算机科学技术系
2008 年 8 月
前 言
《数据结构》课程是计算机科学与技术专业的一门必修的专业基础课。这门课程的主要特点是实践性很强,不仅要学习基本理论知识,更要注重上机实践,通过上机实践验证算法的正确性,掌握和巩固所学理论知识。通过对本课程中算法设计和上机实践的训练,培养学生的数据抽象能力和程序设计的能力,为后续课程,特别是软件课程打下坚实的知识基础。要求学生掌握各种常用数据结构的逻辑结构,存储结构及有关操作的算法。
通过本课程的学习,要求学生了解数据结构及其分类、数据结构与算法的密切关系; 熟悉各种基本数据结构及其操作,学会根据实际问题要求来选择数据结构; 掌握设计算法的步骤和算法分析方法; 掌握数据结构在排序和查找等常用算法中的应用。
为了使学生更好地理解和深刻地把握这些知识,并在此基础上,训练和培养了解数据结构及其分类、数据结构与算法的密切关系; 熟悉各种基本数据结构及其操作,学会根据实际问题要求来选择数据结构; 掌握设计算法的步骤和算法分析方法; 掌握数据结构在排序和查找等常用算法中的应用等方面的技能,设置的以下十二个的具体实验项目,这些实验项目中有验证性实验、综合性实验与设计性实验,在每一个具体实验中都有标明。各项实验主要了解、掌握的具体知识,在每个实验中都有说明。
本实验指导书对计算机科学与技术专业与网络工程专业均适应。
目录
实验一:顺序表的基本操作 1
实验二:单链表的基本操作 9
实验三:栈的基本操作 14
实验四:队列的基本操作 16
实验五:串的模式匹配 19
实验六:矩阵的基本运算 22
实验七:二叉树的基本操作 29
实验八:哈夫曼树与哈夫曼编码 34
实验九:图的最短路径算法 38
实验十:哈希表的基本操作 40
实验十一:各种排序算法 44
实验十二:银行模拟 48
实验一:顺序表的基本操作
实验学时:2
实验类型:验证
实验要求:选修
一、实验目的
1.掌握使用VC++进行控制台应用程序编写的基本方法
2.掌握顺序表的初始化、销毁、数据元素的插入和删除以及顺序表的输出等基本操作。
二、实验内容
顺序表的初始化、插入和删除
三、 程序清单
1、运行环境
Visual c++ 6.0的微机一台
2、程序清单
//线性表的顺序结构算法实现
#include "stdio.h"
#include "stdlib.h"
# define OVERFLOW -2
# define OK 1
#define ERROR 0
//数据类型说明
typedef
int
ElemType;
typedef
int
Status;
# define List_init_size 100
//线性表存储空间初始分配量
# define Listincrement 10
//线性表存储空间分配增量
typedef
struct
{
ElemType *elem;
//存储空间基址
int
length;
//当前长度
int
listsize;
//当前分配的存储容量
// (以sizeof(ElemType)为单位)
}sqlist;
//初始化线性表:
Status InitList(sqlist &L)
{
//构造一个空线性表L
L.elem=(ElemType *)
malloc
(List_init_size*
sizeof
(ElemType));
if
(!L.elem)
exit
(OVERFLOW);
L.length=0;
L.listsize= List_init_size;
return
OK;
}
//在一个空的线性表中输入N个数据:
Status sqlistinput(sqlist &L,
int
n)
{
int
i=0;
if
(n>L.listsize)
return
ERROR;
for
(;i<n;i++)
{
scanf
(
"%d"
,&L.elem[i]);
}
L.length=n;
return
OK;
}
//判线性表是否为空
Status ListEmpty(sqlist L)
{
if
(!L.length)
return
ERROR;
else
return
OK;
}
//求线性表的长度
Status ListLength(sqlist L)
{
return
L.length;
}
//将线性表L 的数据输出:
Status sqlistoutput(sqlist L)
{
int
i;
for
(i=0;i<ListLength(L);i++)
printf
(
"%4d"
,L.elem[i]);
printf
(
"\n"
);
return
OK;}
//取线性表的第i个元素,其结果保存在e中
Status GetElem(sqlist l,
int
i,ElemType &e)
{
if
(i<1 || i>l.length+1)
return
ERROR;
e=l.elem[i-1];
return
OK;
}
//定义两个数据元素相等的比较函数
Status equal(ElemType e1,ElemType e2)
{
if
(e1==e2)
return
OK;
else
return
ERROR;
}
//根据compare()函数在线性表中定位元素e的位置
int
LocateElem_sq(sqlist L,ElemType e,Status (*compare)(ElemType,ElemType))
//成功返回位序,否则返回0
{
int
i=1;
ElemType *p;
p=L.elem;
while
(i<=L.length &&!(*compare)(*p++,e)) ++i;
if
(i<=L.length)
return
i;
else
return
0;
}
// locateElem_sq
//在线性表中求某元素的前趋结点,如存在则返回其前趋结点pre_e的值,否则返回出错信息
Status PriorElem(sqlist L,ElemType cur_e,ElemType &pre_e)
{
int
pos;
pos=LocateElem_sq(L,cur_e,equal);
if
(pos==0)
return
ERROR;
else
if
(pos==1)
return
OVERFLOW;
//overflow 表示位于第一个
else
{
GetElem(L,pos-1,pre_e);
return
OK;
}
}
//在线性表中求某元素的后继结点
Status NextElem(sqlist L,ElemType cur_e,ElemType &next_e)
{
int
pos;
pos=LocateElem_sq(L,cur_e,equal);
if
(pos==0)
return
ERROR;
else
if
(pos==L.length)
return
OVERFLOW;
//overflow 表示最后一个
else
{
GetElem(L,pos+1,next_e);
return
OK;
}
}
//在线性表中插入一个元素
Status Listinsert_sq(sqlist &L,
int
i,ElemType e) {
ElemType *p,*q,*newbase;
if
(i<1 || i>L.length+1)
return
ERROR;
if
(L.length>=L.listsize) {
newbase=(ElemType *)
realloc
(L.elem, (L.listsize+Listincrement) *
sizeof
(ElemType));
if
(!newbase)
exit
(OVERFLOW);
L.elem=newbase; L.listsize+=Listincrement ;}
q=&(L.elem[i-1]);
for
(p=&(L.elem[L.length-1]);p>=q;--p) *(p+1)=*p;
*q=e; ++L.length;
return
OK;
}
// listinsert_sq;
//在线性表中删除第i个元素,其结果保留在e中
Status Listdelete_sq(sqlist &l,
int
i,ElemType &e)
{
ElemType *p,*q;
if
(i<1||i>l.length+1)
return
ERROR;
p=&(l.elem[i-1]);
e=*p;
q=l.elem+l.length-1;
for
(++p;p<=q;++p) *(p-1)=*p;
--l.length;
return
OK;
}
// listdelete_sq;
//将la和lb线性表归并到lc
void
mergelist_sq(sqlist la,sqlist lb,sqlist &lc)
{ ElemType *pa,*pb,*pc,*pa_last,*pb_last;
pa=la.elem;
pb=lb.elem;
lc.listsize=lc.length=la.length+lb.length;
pc=lc.elem=(ElemType*)
malloc
(lc.listsize*
sizeof
(ElemType));
if
(!lc.elem)
exit
(OVERFLOW);
pa_last=la.elem+la.length-1; pb_last=lb.elem+lb.length-1;
while
((pa<=pa_last)&& (pb<=pb_last))
if
(*pa<=*pb) *pc++=*pa++;
else
*pc++=*pb++ ;
while
(pa<=pa_last) *pc++=*pa++;
while
(pb<=pb_last) *pc++=*pb++;
}
//mergelist_sq;
//对线性表的元素进行排序
Status sortsqlist(sqlist &L)
{
//冒泡排序
int
i,j,len;
ElemType t;
len=ListLength(L);
for
(i=len-1;i>=1;i--)
for
(j=0;j<i;j++)
{
if
(L.elem[j]>L.elem[j+1])
{t=L.elem[j];
L.elem[j]=L.elem[j+1] ;
L.elem[j+1]=t;
}
}
return
OK;
}
void
main()
{sqlist la,lb,lc;
int
n,m,i,e,k,cur_e,pre_e,next_e;
//建立线性表,并输入输出线性表的数据
InitList(la);InitList(lb);
printf
(
"please input la's numbers:n(请输入线性表la的元素个数n)\n"
);
scanf
(
"%d"
,&n);
printf
(
"please input la n numbers:( 请输入线性表la的n个元素)\n"
);
sqlistinput(la,n);
sqlistoutput(la);
printf
(
"\n"
);
//调用插入函数,对线性表进行插入操作
printf
(
"请输入要插入的元素的位置和插入的值 \n"
);
scanf
(
"%d%d"
,&i,&e);
Listinsert_sq(la,i,e);
sqlistoutput(la);
//调用删除函数,对线性表进除删操作
printf
(
"请输入要删除的元素的位置\n"
);
scanf
(
"%d"
,&i);
Listdelete_sq(la,i,e);
printf
(
"the dele data is %d\n"
,e);
sqlistoutput(la);
printf
(
"please input the get data's locate\n"
);
scanf
(
"%d"
,&i);
//调用GetElem()函数,取第I个位置的元素的值。
GetElem(la,i,e);
printf
(
"the get data is %d\n"
,e);
printf
(
"please input the locateelem's data :cur_e\n"
);
//调用LocateElem_sq()函数,求元素cur_e的位置。
scanf
(
"%d"
,&cur_e);
k=LocateElem_sq(la,cur_e,equal);
printf
(
"the locate is %d\n"
,k);
//调用PriorElem()函数,求元素cur_e的前驱。
printf
(
"please input the cur_e data\n"
);
scanf
(
"%d"
,&cur_e);
PriorElem(la,cur_e,pre_e);
printf
(
"the pre_e is %d\n"
,pre_e);
//调用NextElem()函数,求元素cur_e的后继。
printf
(
"please input the cur_e data\n"
);
scanf
(
"%d"
,&cur_e);
NextElem(la,cur_e,next_e);
printf
(
"the next_e is %d\n"
,next_e);
//建立两个线性表并排序然后归并
printf
(
"please input lb's numbers:m\n"
);
scanf
(
"%d"
,&m);
printf
(
"please input lb m numbers:\n"
);
sqlistinput(lb,m);
printf
(
"\n"
);
sqlistoutput(lb);
sortsqlist(la);
printf
(
"the sort list la is:\n"
);
sqlistoutput(la);
sortsqlist(lb);
printf
(
"the sort list lb is:\n"
);
sqlistoutput(lb);
mergelist_sq(la,lb,lc);
printf
(
"la and lb's mergelist is:\n"
);
sqlistoutput(lc);
}
四、思考题
1.如何实现顺序表的逆置
2.每次删除操作时,都会使得大量的数据元素移动,删除多个数据元素时,就需多次移动数据元素。能否一次进行删除多个数据元素的操作,使得数据元素的移动只进行一次。
实验二:单链表的基本操作
实验学时:2
实验类型:验证
实验要求:必修
一、 实验目的
1.定义单链表的结点类型。
2.熟悉对单链表的一些基本操作和具体的函数定义。
3.通过单链表的定义掌握线性表的链式存储结构的特点。
4.掌握循环链表和双链表的定义和构造方法
二、实验内容
链表的创建、插入与删除操作
三、程序清单
1、运行环境
装有Visual c++6.0的微机一台
2、程序清单
//链表的创建及插入、删除操作
#include "stdio.h"
#include"stdlib.h"
#define NULL 0
#define error 0
#define ok 1
#define overflow -2
#define infeasible -1
//类型定义
typedef
int
Status;
typedef
int
ElemType;
//定义链表的存储结构
typedef
struct
LNode
{
int
data;
//数据域
struct
LNode *next;
//指针域
}LNode,*LinkList;
//链表的类型
Status GetElem_l(LinkList L,
int
i , ElemType &e)
//L为带头结点的单链表,当第i 个元素存在时,其值赋给e.
{
int
j;
LinkList p ;
p=L->next; j=1;
while
(p&&j<i)
//顺序找第i个元素.
{p=p->next; ++j;}
if
(!p||j>i)
return
error;
e=p->data;
return
ok;
}
//逆序创建链表
void
CreatList_L1(LinkList &L,
int
n)
//n为元素个数,L为头结点
{
int
i;
LinkList p;
L=(LinkList)
malloc
(
sizeof
(LNode));
//生成头结点
L->next=NULL;
for
(i=n;i>0;i--)
//链头插入法
{ p=(LinkList)
malloc
(
sizeof
(LNode));
scanf
(
"%d"
,&p->data);
p->next=L->next;
L->next=p;
}
}
//正序创建单链表
void
CreatList_L2(LinkList &L,
int
n )
///n为元素个数,L为头结点
{
int
i ;
LinkList p,q;
L=(LinkList )
malloc
(
sizeof
(LNode));
q=L;
for
(i=0;i<n;i++)
//链尾插入法
{ p=(LinkList )
malloc
(
sizeof
(LNode));
scanf
(
"%d"
,&p->data);
q->next=p;
q=p;
}
q->next=NULL;
}
//输出链表
void
print(LinkList L)
{LinkList p;
p=L->next;
while
(p)
{
printf
(
"%d "
,p->data);
p=p->next;
}
}
//链表的插入操作
int
ListInsert(LinkList &L,
int
i,
int
e)
{LinkList p,s;
int
j;
p=L;j=0;
while
(p&&j<i-1)
{p=p->next; ++j;}
if
(!p||j>i-1)
return
error;
s=(LinkList)
malloc
(
sizeof
(LNode));
s->data=e; s->next=p->next;
p->next=s;
return
ok;
}
//链表的删除操作
int
ListDelete(LinkList &L,
int
i,
int
&e)
{LinkList p,q;
int
j;
p=L; j=0;
while
(p->next&&j<i-1)
{ p=p->next; ++j;}
if
(!(p->next)||j>i-1)
return
error;
q=p->next;p->next=q->next;
e=q->data;
free
(q);
return
ok;
}
//对链表的元素进行排序
Status sortlinklist(LinkList &L)
{LinkList p,q,r;
ElemType t;
p=L->next;
//p指向链表第一个元素结点
while
(p->next!=NULL)
{q=L->next;
//q指向链表第一个元素结点
while
(q->next!=NULL)
{r=q->next;
if
(q->data>r->data)
//相邻两个元素比较、交换
{t=q->data; q->data=r->data; r->data=t; }
q=q->next;
}
p=p->next;
}
return
ok ;
}
void
mergelist_l(LinkList la, LinkList &lb, LinkList &lc)
{LinkList pa,pb,pc;
pa=la->next; pb=lb->next ;
lc=pc=la;
while
(pa&&pb)
if
(pa->data <=pb->data)
{pc->next=pa;pc=pa;pa=pa->next;}
else
{pc->next=pb;pc=pb;pb=pb->next;}
pc->next=pa?pa:pb;
free
(lb);
}
//主函数通过调用创建、插入、删除用输出函数完成链表的基本操作
void
main()
{LinkList L1,L2,L3;
int
n,ins,del,i;
//创建一个先进先出单链表
printf
(
"please input fifo linklist's node number n:\n"
);
scanf
(
"%d"
,&n);
printf
(
"please input the linklist %d nodes data \n"
,n);
CreatList_L2(L2,n);
print(L2);
printf
(
"\n"
);
//创建一个后进先出单链表
printf
(
"please input lifo linklist's node number n:\n"
);
scanf
(
"%d"
,&n);
printf
(
"please input the linklist %d nodes data \n"
,n);
CreatList_L1(L1,n);
print(L1);
printf
(
"\n"
);
//对链表进行插入操作
printf
(
"please input the insert node's locate i and value e\n"
);
scanf
(
"%d%d"
,&i,&ins);
ListInsert(L1,i,ins);
print(L1);
printf
(
"\n"
);
//对链表进行删除操作
printf
(
"please input the delete node's locate i\n"
);
scanf
(
"%d"
,&i);
ListDelete(L1,i,del);
print(L1);
printf
(
"\n%d\n"
,del);
//对链表进行排序
sortlinklist(L1);
printf
(
"\n the L1 list's sort is:\n"
);
print(L1);
printf
(
"\n the L2 list's sort is:\n"
);
sortlinklist(L2);
print(L2);
//对链表进行合并
printf
(
"\n the merge result is : \n"
);
mergelist_l(L1,L2,L3);
print(L3);
}
四、思考题
l.如果需要将新结点插入到第i个数据元素之后,算法将如何改动?
2. 双向链表和循环链表的定义和构造方法。
实验三:栈的基本操作
实验学时:2
实验类型:验证
实验要求:选修
一、实验目的
1.会定义顺序栈和链栈的结点类型。
2.掌握顺序栈的插入和删除结点在操作上的特点。
3.熟悉对顺序栈的一些基本操作和具体的函数定义。
二、实验内容
栈的初始化、进栈与出栈等基本操作
三、程序清单
1、运行环境
装有Visual 6.0的微机一台
2、程序清单
#define stackinitsize 20
#define stackincrement 8
#include <stdlib.h>
#include <stdio.h>
typedef
struct
{
int
*base;
int
*top;
int
stacksize;
}sqstack;
int
initstack(sqstack &s)
{s.base=(
int
* )
malloc
(stackinitsize*
sizeof
(
int
));
s.top=s.base;
s.stacksize=stackinitsize;
return
1;
}
int
push(sqstack &s,
int
e)
{
s.top)=e;
s.top++;
return
1;
}
int
gettop(sqstack s)
{
return
*(s.top-1);
}
int
emptystack(sqstack s)
{
if
(s.top==s.base)
return
1;
else
return
0;
}
int
pop(sqstack &s,
int
&e)
{
if
(emptystack(s))
return
0;
--s.top;
*e=*s.top;
return
1;
}
Void main()
{
Sqstack s;
Int n,I,e;
initstack(s);
scanf
(“%d”,&n);
for
(i=1;i<=n;i++)
{
scanf
(“%d”,&e);
Push(s,e);
}
While(!emptystack(s))
{pop(s,e);
Printf(“%d ”,e);
}
}
四、思考题
如果两个栈共用一个存储空间,该如何解决?
实验四:队列的基本操作
实验学时:2
实验类型:验证
实验要求:选修
一、实验目的
1.会定义循环队列的结点类型。
2.循环队列的插入和删除结点在操作上的特点。
3.熟悉对循环队列的一些基本操作和具体的函数定义
二、实验内容
循环队列的插入与删除
三、程序清单
1、运行环境
装有Visual 6.0的微机一台
2、程序清单
//--------------对列的顺序存储结构------------------
# include "stdlib.h"
# include "stdio.h"
# include "time.h"
//函数结果状态代码
# define TURE 1
# define FALSE 0
# define OK 1
# define ERROR 0
# define OVERFLOW -2
# define maxqsize 100
typedef
int
status;
typedef
int
qelemtype;
typedef
struct
{
qelemtype *base;
int
front;
int
rear;
}sqqueue;
//----------循环队列的基本操作的算法描述--------
status initqueue(sqqueue &Q){
//构造一个空队列Q
Q.base=(qelemtype*)
malloc
(maxqsize*
sizeof
(qelemtype));
if
(!Q.base)
return
ERROR;
Q.front=Q.rear=0;
return
OK;
}
int
queuelength(sqqueue Q){
//返回Q的元素个数,即对列的长度
return
(Q.rear-Q.front+maxqsize)%maxqsize;
}
status enqueue(sqqueue &Q,qelemtype e){
//插入元素e为Q的新的队尾元素
if
((Q.rear+1)%maxqsize==Q.front)
return
ERROR;
//队列满
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%maxqsize;
return
OK;
}
status dequeue(sqqueue &Q,qelemtype &e){
//若队列不空,则删除Q的队头元素,用e返回其值,并返回OK
//否则返回ERROR
if
(Q.front==Q.rear)
return
ERROR;
e=Q.base[Q.front];
Q.front=(Q.front+1)%maxqsize;
return
OK;
}
void
main()
{
//测试基本操作
int
i,e;
sqqueue Q;
initqueue(Q);
printf
(
"\n"
);
for
(i=1;i<=10;i++)
{
e=i;
enqueue(Q,e);
}
printf
(
"the length of queue is :%d\n"
,queuelength(Q));
for
(i=1;i<=10;i++)
{
dequeue(Q,e);
printf
(
" %d"
,e);
}
}
四、思考题
1. 如果循环队列的下标不是从0开始,而是是从1开始,那么头指针加l的操作应如何修改?
2. 在循环队列中判断队空和队满的条件能否一样,为什么?
3. 用另一种不同与上面算法的方法解决“假上溢”问题。
实验五:串的模式匹配
实验学时:2
实验类型:验证
实验要求:选修
一、实验目的
1.会定义定长顺序串的存储结构。
2.掌握定长顺序串的基本运算。
3.了解KMP算法。
二、实验内容
串的模式匹配算法
三、程序清单
1、运行环境
2、程序清单
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <dos.h>
#define maxstrlen 255 //用可以在255以内定义最大串长
typedef
unsigned
char
SString[maxstrlen+1];
//0好单元可以存放串的长度
int
index(SString S,SString T,
int
pos) {
//利用模式串T的next函数求T在主串S中第pos个字符之后的位置
//其中T非空,1<=pos<=strlength(s).
int
i,j;
i=pos;j=1;
while
(i<=S[0]&&j<=T[0]) {
if
(S[i]==T[j]) {++i;++j;}
else
{i=i-j+2;j=1;}
}
if
(j>T[0])
return
i-T[0];
else
return
0;
}
//index_kmp
void
main()
{
SString S={17,
'a'
,
'c'
,
'a'
,
'b'
,
'a'
,
'a'
,
'b'
,
'a'
,
'a'
,
'b'
,
'c'
,
'a'
,
'c'
,
'a'
,
'a'
,
'b'
,
'c'
};
SString T={6,
'a'
,
'b'
,
'a'
,
'a'
,
'b'
,
'c'
};
printf
(
"\nit is :%d "
,index(S,T,1));
}
//-----------改进的模式匹配算法-------------
//-----------本算法在BC++3.1下调试通过------
//-----------调试时间2002年4月14日----------
#include <stdio.h>
#include <stdlib.h>
#define maxstrlen 255 //用可以在255以内定义最大串长
int
next[7];
typedef
unsigned
char
SString[maxstrlen+1];
//0好单元可以存放串的长度
/********************************************
*********************************************/
void
get_next(SString T) {
//求模式串T的next函数值并存入数组next。
int
i,j;
i=1; next[1]=0; j=0;
//
while
(i<T[0]){
if
(j==0||T[i]==T[j]) {++i; ++j; next[i]=j;}
else
j=next[j];
}
printf
(
"\nnext[j] is:"
);
for
(i=1;i<=6;i++)
printf
(
"%d"
,next[i]);
}
//get_next
int
index_kmp(SString S,SString T,
int
pos) {
//利用模式串T的next函数求T在主串S中第pos个字符之后的位置
//kmp算法。其中T非空,1<=pos<=strlength(s).
int
i,j;
i=pos;j=1;
while
(i<=S[0]&&j<=T[0]) {
if
(j==0||S[i]==T[j]) {++i;++j;}
else
j=next[j];
}
if
(j>T[0])
return
i-T[0];
else
return
0;
}
//index_kmp
void
main()
{
SString S={17,
'a'
,
'c'
,
'a'
,
'b'
,
'a'
,
'a'
,
'b'
,
'a'
,
'a'
,
'b'
,
'c'
,
'a'
,
'c'
,
'a'
,
'a'
,
'b'
,
'c'
};
SString T={6,
'a'
,
'b'
,
'a'
,
'a'
,
'b'
,
'c'
};
//S[0]=17; T[0]=6;
get_next(T);
printf
(
"\nit is :%d "
,index_kmp(S,T,1));
}
四、思考题
1.如何使得在串插入和联接时不会上溢。
2.串的其它存储结构的实现。
实验六:矩阵的基本运算
实验学时:2
实验类型:设计
实验要求:选修
一、实验目的
1.了解多维数组的顺序存储结构及其地址计算方式
2.了解特殊矩阵和稀疏矩阵的概念。
3.掌握疏矩阵的压缩存储方式——三元组表。
4.掌握稀疏矩阵的两种转置运算算法。
二、实验内容
数组的稀疏矩阵的三元组存储表示与实现
三、程序清单
1、运行环境
2、程序清单
//—————稀疏矩阵的三元组顺序表存储表示一———
#define MAXSIZE 100 //假设非零元个数的最大值为100
#define ROW 7
#define COL 7
#define OK 1
#define FALSE 0
#include "stdlib.h"
#include "stdio.h"
#include "conio.h"
int
a[ROW][COL]={{0,12,9,0,0,0,0},
{0,0,0,0,0,0,0},
{-3,0,0,0,0,14,0},
{0,0,24,0,0,0,0},
{0,18,0,0,0,0,0},
{15,0,0,-7,0,0,0},
{0,0,0,0,0,0,-5}};
typedef
int
ElemType;
typedef
int
Status;
typedef
struct
{
int
i,j;
//该非零元的行下标和列下标
ElemType e;
}Triple;
typedef
union
{
Triple data[MAXSIZE+1];
//非零元三元组表, data[0]未用
int
mu,nu,tu;
//矩阵的行数、列数和非零元个数
}TSMatrix;
void
InitTSMatrix(TSMatrix &T)
{ T.tu=0;
}
Status ChangeArrayToMS(
int
a[][COL],TSMatrix &T)
{
int
i,j,k=0;
for
(i=0;i<ROW;i++)
for
(j=0;j<COL;j++)
if
(a[i][j])
{++k;
T.data[k].i=i+1;T.data[k].j=j+1;T.data[k].e=a[i][j];
}
T.mu=ROW;T.nu=COL;T.tu=k;
return
OK;
}
void
PrintTSmatrix(TSMatrix T)
{
//以三元组格式输出稀疏矩阵
int
k;
if
(T.tu>0)
{
printf
(
"\n row col val\n"
);
printf
(
"------------------\n"
);
for
(k=1;k<=T.tu;k++)
printf
(
"(%4d%5d%5d)\n"
,T.data[k].i,T.data[k].j,T.data[k].e);
}
}
Status TransposeSMatrix(TSMatrix M, TSMatrix &T) {
//采用三元组表存储表示,稀疏矩阵M的转置T
int
q,p,col;
T.mu=M.nu;T.nu=M.mu;T.tu =M.tu;
if
(T.tu) {
q = 1;
for
(col=1 ;col<=M.nu; ++col)
for
(p=1; p<=M.tu; ++p)
if
(M.data[p].j==col){
T.data[q].i=M.data[p].j ; T.data[q].j=M.data[p].i;
T.data[q].e=M.data[p].e; ++q;}
}
return
OK;
}
// TrazlsposeSMatrix
Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T){
//采用三元组表存储表示,稀疏矩阵M的转置T(快速转换)
int
t,col,p,q,num[COL+1],cpot[COL+1];
T.mu=M.nu;T.nu=M.mu;T.tu= M.tu;
if
(T.tu) {
for
(col = 1; col<= M.mu;++col) num[col] = 0;
for
(t=1;t<=M.tu;++t) ++num[M.data[t].j];
//求M中每一列含非0元素的个数
cpot[ 1 ] = 1 ;
// 求第 col列中第一个非0元素在 b. data 中的序号
for
(col = 2;col<= M.nu; ++col) cpot[col]=cpot[col-1] + num[col-1];
for
(p=1; p<=M.tu;++p)
{ col=M.data[p].j;q=cpot[col];
T. data[q].i=M.data[p].j; T.data[q].j=M.data[p].i;
T. data[q].e=M.data[p].e; ++cpot[col];
}
}
return
OK ;
}
// FastTransposeSMatrix
Status AddTSMatrix(TSMatrix A,TSMatrix B,TSMatrix &C)
{
//A+B==>C 两个稀疏矩阵相加结果存于C中
//此算法类似于顺序表的归并算法
int
p,q,k;
p=q=k=1;
if
(A.mu!=B.mu||A.nu!=B.nu)
return
FALSE;
if
(A.tu==0&&B.tu==0) {C.tu=0;
return
OK;}
C.mu=A.mu;C.nu=A.nu;
while
(p<=A.tu&&q<=B.tu)
{
if
((A.data[p].i==B.data[q].i)&&(A.data[p].j==B.data[q].j))
{
if
(A.data[p].e+B.data[q].e)
{ C.data[k].i=B.data[q].i;C.data[k].j=B.data[q].j;
C.data[k].e=A.data[q].e+B.data[q].e;
}
p++;q++;k++;
}
else
if
((A.data[p].i>B.data[q].i)||
((A.data[p].i==B.data[q].i)&&(A.data[p].j>B.data[q].j)))
{C.data[k].i=B.data[q].i;C.data[k].j=B.data[q].j;
C.data[k].e=B.data[q].e;q++;k++;}
else
{C.data[k].i=A.data[p].i;C.data[k].j=A.data[p].j;
C.data[k].e=A.data[p].e;p++;k++;}
}
while
(p<=A.tu)
{C.data[k].i=A.data[p].i;C.data[k].j=A.data[p].j;
C.data[k].e=A.data[p].e;p++;k++;}
while
(q<=B.tu)
{C.data[k].i=B.data[q].i;C.data[k].j=B.data[q].j;
C.data[k].e=B.data[q].e;q++;k++;}
C.tu=k-1;
return
OK;
}
void
main()
{ TSMatrix T,T1,T2;
InitTSMatrix(T);getch();
ChangeArrayToMS(a,T);
PrintTSmatrix(T);getch();
TransposeSMatrix(T,T1);
PrintTSmatrix(T1);getch();
FastTransposeSMatrix(T,T1);
PrintTSmatrix(T1);getch();
AddTSMatrix(T,T1,T2);
PrintTSmatrix(T2);
}
四、思考题
1.稀疏矩阵的十字链表又是如何实现的?
实验七:二叉树的基本操作
实验学时:2
实验类型:设计
实验要求:必修
一、实验目的
1.熟悉二叉树结点的结构和对二叉树的基本操作。
2.掌握对二叉树每一种操作的具体实现。
3.学会利用递归方法编写对二叉树这种递归数据结构进行处理的算法。
二、实验内容
二叉树的创建及各种周游
三、程序清单
1、运行环境
2、程序清单
/* ****************二叉树有关算法*************** */
#include "alloc.h"
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
#define stackinitsize 100
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef
int
TElemType ;
typedef
int
Status;
//一一一一一二叉树的二叉链表存储表示一一一一一
typedef
struct
BiTNode{
TElemType data;
struct
BiTNode *lchild,*rchild;
//左右孩子指针
}BiTnode,*SElemType,*BiTree;
typedef
struct
{
//该堆栈的元素是指针类型的
//base和top均是指向指针的指针
SElemType *base;
SElemType *top;
int
stacksize;
}sqstack;
//堆栈结构
//一一一一一基本操作的函数原型说明(部分)一一一一一
Status CreateBitree(BiTree &T);
//按先序次序输入二叉树中结点的值(一个字符),空格字符表示空树。
//构造二叉链表表示的二叉树T.
Status PreOrderTraverse(BiTree T,Status(*Visit)(TElemType e));
//采用二叉链表存储结构,visit是对结点操作的应用函数。
//先序遍历二叉树T,对每个结点调用函数Visit一次且仅一次。
//一旦visit()失败,则操作失败。
Status InorderTraverse(BiTree T,Status(*Visit)(TElemType e));
//采用二叉链表存储结构,Visit是对结点操作的应用函数。
//中序遍历二叉树T,对每个结点调用函数Visit一次且仅一次。
//一旦visit()失败,则操作失败。
Status PostorderTraverse(BiTree T,Status(*Visit)(TElemType e));
//采用二叉链表存储结构,visit是对结点操作的应用函数。
//后序遍历二叉树T,对每个结点调用函数Visit一次且仅一次。
//一旦visit()失败,则操作失败。
Status LevelIOrderTraverse(BiTree T,Status(*Visit)(TElemType e));
//采用二又链表存储结构,Visit是对结点操作的应用函数。
//层序遍历二叉树T,对每个结点调用函数Visit一次且仅一次。
//一旦visit()失败,则操作失败
sqstack *InitStack()
//初始化堆栈
{sqstack *s;
s->base=(SElemType*)
malloc
(100*
sizeof
(SElemType));
if
(!s->base)
return
NULL;
s->top=s->base;
s->stacksize=100;
return
s;
}
int
StackEmpty(sqstack *s)
//栈空判别
{
return
(s->top==s->base);
}
void
Pop(sqstack *s,SElemType &e)
//弹栈
{
e=*--s->top;
}
Status GetTop(sqstack *s,SElemType &e)
{
if
(s->top==s->base)
return
ERROR;
e=*(s->top-1);
return
OK;
}
void
Push(sqstack *s,SElemType e)
//将元素压入堆栈
{SElemType t;
*s->top++=e;
}
Status CreateBiTree(BiTree &T){
//按先序次序输入二叉树中结点的值(一个字符),空格字符表示空树。
//构造二叉链表表示的二叉树T.
char
ch;
ch=getche();
if
(ch==
' '
) T=NULL;
else
{
if
(!(T=(BiTNode *)
malloc
(
sizeof
(BiTNode))))
return
(OVERFLOW);
T->data=ch;
//生成根结点
CreateBiTree(T->lchild);
//构造左子树
CreateBiTree(T->rchild);
//构造右子树
}
return
OK;
}
//CreateBiTree
Status PreOrderTraverse(BiTree T,Status(*Visit)(TElemType e))
//采用二叉链表存储结构,visit是对数据元素操作的应用函数,
//先序遍历二叉树T的递归算法,对每个数据元素调用函数visit。
//调用实例: PreOrderTraverse(T,printElement);
{
if
(T){
if
(Visit(T->data))
if
(PreOrderTraverse(T->lchild,Visit))
if
(PreOrderTraverse(T->rchild,Visit))
return
OK;
return
ERROR;
}
else
return
OK;
}
//preOrderTraVerse
Status InOrderTraverse(BiTree T,Status(*Visit)(TElemType e))
//采用二叉链表存储结构,visit是对数据元素操作的应用函数,
//中序遍历二叉树T的递归算法,对每个数据元素调用函数visit。
{
if
(T){
if
(InOrderTraverse(T->lchild,Visit))
if
(Visit(T->data))
if
(InOrderTraverse(T->rchild,Visit))
return
OK;
return
ERROR;
}
else
return
OK;
}
//preOrderTraVerse
Status PostOrderTraverse(BiTree T,Status(*Visit)(TElemType e))
//采用二叉链表存储结构,visit是对数据元素操作的应用函数,
//后序遍历二叉树T的递归算法,对每个数据元素调用函数visit。
{
if
(T){
if
(PostOrderTraverse(T->lchild,Visit))
if
(PostOrderTraverse(T->rchild,Visit))
if
(Visit(T->data))
return
OK;
return
ERROR;
}
else
return
OK;
}
//preOrderTraVerse
Status PrintElement(TElemType e)
{
//输出元素e的值
printf
(
"%c"
,e);
return
OK;
}
Status InorderTraverseNoRecursion1(BiTree T,Status(*Visit)(TElemType e))
//采用二叉链表存储结构,visit是对数据元素操作的应用函数。
//中序遍历二叉树T的非递归算法,对每个数据元素调用函数visit。
{sqstack *s;
BiTree p;
s=InitStack();p=T;
while
(p||!StackEmpty(s))
{
if
(p){ Push(s,p);p=p->lchild;}
//根指针进栈,遍历左子树
else
{
//根指针退栈,访问根结点,遍历右子树
Pop(s,p);
if
(!Visit(p->data))
return
ERROR;
p=p->rchild;
}
//else
}
//while
return
OK;
}
//InorderTraVerse1
Status InorderTraverseNoRecursion2(BiTree T,Status(*Visit)(TElemType e))
//采用二叉链表存储结构,visit是对数据元素操作的应用函数。
//中序遍历二叉树T的非递归算法,对每个数据元素调用函数visit。
{sqstack *s;
BiTree p;
s=InitStack();Push(s,T);
while
(!StackEmpty(s))
{
while
(GetTop(s,p)&&p) Push(s,p->lchild);
//向左走到尽头
Pop(s,p);
//空指针退栈
if
(!StackEmpty(s)) {
//访问结点,向右一步
Pop(s,p);
if
(!Visit(p->data))
return
ERROR;
Push(s,p->rchild);
}
//if
}
//while
return
OK;
}
//InorderTraVerse1
void
main()
{
BiTree t;
printf
(
"\n请按先序遍历输入二叉树(当左右子树为空时用空格输入)\n"
);
CreateBiTree(t);
printf
(
"\n该二叉树的先序遍历为:\n"
);
PreOrderTraverse(t,PrintElement);
printf
(
"\n该二叉树的中序遍历为:\n"
);
InOrderTraverse(t,PrintElement);
printf
(
"\n该二叉树的后序遍历为:\n"
);
PostOrderTraverse(t,PrintElement);
printf
(
"\n该二叉树的中序遍历为:(用非递归调用1)\n"
);
InorderTraverseNoRecursion1(t,PrintElement);
printf
(
"\n该二叉树的中序遍历为:(用非递归调用2)\n"
);
InorderTraverseNoRecursion2(t,PrintElement);
}
四、思考题
1.如何实现二叉树的层次遍历?
2. 如何实现二叉树的先序遍历、中序遍历和后序遍历的非递归算法。
实验八:哈夫曼树与哈夫曼编码
实验学时:2
实验类型:设计
实验要求:选修
一、实验目的
1.了解创建哈夫曼树的基本方法
2.掌握通过赫夫曼树进行赫夫曼编码的基本原理和方法。
二、实验内容
哈夫曼树与哈夫曼编码
三、程序清单
1、运行环境
2、程序清单
#include "stdlib.h"
#include "stdio.h"
#include "conio.h"
#include "string.h"
#define ERROR 0;
#define OK 1;
typedef
int
Status ;
//哈夫曼树的存储和哈夫曼编码的存储
typedef
struct
{
unsigned
int
weight;
unsigned
int
parent,lchild,rchild;
}HTNode,*HuffmanTree;
//动态分配数组存储哈夫曼树
typedef
char
**HuffmanCode;
//动态分配数组存储哈夫曼编码表
Status Select(HuffmanTree HT,
int
n,
int
&s1,
int
&s2) {
//在哈夫曼树HT[1..n] 搜索最大权值和最小权值并用s1,s2 返回它们的下标
unsigned
int
temp=9999;
int
i;
s1=0;s2=0;
for
(i=1;i<=n;i++)
if
((HT[i].weight<temp)&&(HT[i].parent==0))
{
s1=i;temp=HT[i].weight;
}
temp=9999;
for
(i=1;i<=n;i++)
if
((HT[i].weight<temp)&&(HT[i].parent==0)&&(i!=s1))
{
s2=i;temp=HT[i].weight;
}
if
((s1==0)&&(s2==0))
return
ERROR;
return
OK;
}
//select
//求huffman编码的算法:
void
HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,
int
w[],
int
n)
{
//w存放N个字符的权值(均?>0),构造hufmantree HT,并求N个字符有huffman编码HC
HuffmanTree p;
char
*cd;
int
s1,s2,i,c,m,start,f;
if
(n<1)
return
;
m=2*n-1;
//哈夫曼树的结点数
HT=(HuffmanTree)
malloc
((m+1)*
sizeof
(HTNode));
//0号单元未用
p=HT;p++;
for
(i=1;i<=n;++i)
{
p->weight=w[i-1];
p->parent=0;
p->lchild=0;
p->rchild=0;
p++;
}
//将各结点赋初值
for
(;i<=m;++i,++p)
{
p->weight=0;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
//后续结点赋初值
for
(i=n+1;i<=m;++i)
{ Select(HT,i-1,s1,s2);
//在HT[1..i-1]选择parent为0且weight最小的两个结点,其序号为S1,S2
//每次创建的树放在i的位置其中(i>n)
HT[s1].parent=i;HT[s2].parent=i;
HT[i].lchild=s1;HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
printf
(
"\nthe huffmantree is:\n"
);
printf
(
" NO [weight parent lchild rchild]\n"
);
printf
(
" --------------------------------\n"
);
for
(i=1;i<=m;i++)
printf
(
"%6d [%6d,%6d,%6d, %6d ]\n"
,i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
//从叶子到根逆向求每个字符的Huffman 编码
HC=(HuffmanCode)
malloc
((n+1)*
sizeof
(
char
*));
cd=(
char
*)
malloc
(n*
sizeof
(
char
));
cd[n-1]=
'\0'
;
for
(i=1;i<=n;++i)
{ start=n-1;
for
(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)
if
(HT[f].lchild==c) cd[--start]=
'0'
;
else
cd[--start]=
'1'
;
HC[i]=(
char
*)
malloc
((n-start)*
sizeof
(
char
));
strcpy
(HC[i],&cd[start]);
}
free
(cd);
}
//end huffmancoding
void
main()
{
HuffmanTree HT;
int
n,i,w[20];
HuffmanCode HC;
printf
(
"please intput n=\n"
);
scanf
(
"%d"
,&n);
printf
(
"please input w[%d]:\n"
,n);
for
(i=0;i<n;i++)
scanf
(
"%d"
,&w[i]);
HuffmanCoding(HT,HC,w,n);
getch();
printf
(
"\nthe HuffmanCoding is:\n"
);
for
(i=1;i<=n;i++)
printf
(
"%s\n"
,HC[i]);
}
实验九:图的最短路径算法
实验学时:2
实验类型:验证
实验要求:选修
一、实验目的
1.了解无向图的邻接表的存储表示
2.掌握通过无向图的邻接表进行无向图的深度优先搜索的基本原理和方法
二、实验内容
图的dijkstra算法
三、程序清单
1、运行环境
2、程序清单
/*************dijkstra算法********/
#define max 1000
#define n 6
typedef
int
Graph[n][n];
typedef
int
vertex;
void
shortp(Graph G,vertex v,
int
dist[n])
{
int
i,wm,u,num=1,S[n];
for
(i=0;i<n;i++)
{
dist[i]=G[v][i];
S[i]=0;
/*数组dist及集合S赋初值*/
}
S[v]=1;
/*把顶点v加入集合S中*/
do
{
wm=max;
u=v;
for
(i=0;i<n;i++)
/*选择顶点u*/
if
(S[i]==0)
if
(dist[i]<wm)
{
u=i;
wm=dist[i];
}
S[u]=1;
for
(i=0;i<n;i++)
if
(S[i]==0)
if
(dist[u]+G[u][i]<dist[i])
dist[i]=dist[u]+G[u][i];
num++;
}
while
(num!=n-1);
}
main()
{
Graph G;
vertex v=0;
int
dist[n],i,j;
printf
(
"please input weight of Graph:\n"
);
for
(i=0;i<n;i++)
for
(j=0;j<n;j++)
scanf
(
"%d"
,&G[i][j]);
shortp(G,v,dist);
for
(i=0;i<n;i++)
printf
(
"the shortest path of v[%d]->v[%d] is:%d\n"
,v,i,dist[i]);
}
实验十:哈希表的基本操作
实验学时:2
实验类型:设计
实验要求:选修
一、实验目的
1.熟悉有关哈希表的基本概念。
2.熟悉构造哈希表的方法。
3.掌握处理哈希冲突的开放定址法。
二、实验内容
哈希表的动态生成与查找
三、程序清单
//定义开放定址哈希表的存储结构
int
hashsize[]={13,19,29,37};
/*哈希表容量递增表,一个合适的素数序列*/
int m=0;/*哈希表表长,全局变量*/
typedef int ElemType;
typedef int Status;
typedef struct
{
ElemType *elem;/*数据元素存储基址,动态分配数组*/
int count;/*当前数据元素个数*/
int sizeindex;/*hashsize[sizeindex]为当前容量*/
}HashTable;
#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1
#define EQ(a,b) ((a)一(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
//哈希表的初始化
Status InitHashTable(HashTable * H)
{/*操作结果:构造一个空的哈希表*/
int i;
(*H).count=0;/*当前元素个数为0*/
(*H).sizeindex=0;/*初始存储容量为hashsize[0]*/
m=hashsize[0];
(*H).elem=(ElemType*)malloc(m*sizeof(ElemType));
If(!(*H).elem)
exit(OVERFLOW);/*存储分配失败*/
for(i-0;i<m;i++)
(*H).elem[i].key=NULLKEY;/*未填记录的标志*/
return OK;
}
//哈希表的销毁
void DestroyHashTable(HashTable*H)
{/*初始条件:哈希表H存在。操作结果:销毁哈希表H*/
free((*H).elem);
(*H).elem=NULL;
(*H).count=0;
(*H).sizeindex=0;
}
//确定哈希函数
unsigned Hash(KeyType K)
{/*一个简单的哈希函数(m为表长,全局变量)*/
return K%m:
}
//冲突解决方法(线性探测再散列)
void collision(int*p,int d)/*线性探测再散列*/
{/*开放定址法处理冲突*/
*p=(*p+d)%m;
}
//查找(若该数据元素不在表中,则插入)
Status SearchHash(HashTable H,KeyType K,int*p,int*c)
{/*在开放定址哈希表H中查找关键码为K的元素,若查找成功,以P指示待查
数据元素在表中位置,并返回SUCCESS;否贝,以P指示插入位置,并返回
UNSUCCESS*/
/*C用以计冲突次数,其初值置零,供建表插入时参考。
*p=Hash(K)/*求得哈希地址*/
while(H.elem[*p】.key!=NULLKEY&&!EQ(K,H.elem[*p].key))
{/*该位置中填有记录.并且关键字不相等*/
(*c)++;
If(*c<m)
collision(p,*c);/*求得下一探查地址P*/
else
break;
}
If EQ(K,H.elem[*p].key)
return SUCCESS;/*查找成功,P返回待查数据元素位置*/
else
return UNSUCCESS;/*查找不成功(Helem[p].key==NULLKEY),P返回
的是插入位置*/
)
//哈希表的重建
Status InsertHash(HashTable *,ElemType);/*对函数的声明*/
void RecreateHashTable(HashTable*H)/*重建哈希表*/
{/*重建哈希表*/
int i,count=(*H).count;
ElemType *p,*elem=(ElemType*)malloc(count*sizeof(ElemType));
p=elem;
printf(“重建哈希表\n”);
for(i=0;i<m;i++1/*保存原有的数据到elem中*/
if(((*H).elem+i)->key!=NULLKEY)/*该单元有数据*/
*p++=*((*H).elem+i);
(*H).count=0;
(*H).sizeindex++;/*增大存储容量*/
m=hashsize[(*H).sizeindex];
p=(ElemType*)realloc((*H).elem,m*sizeof(ElemType));
if(!p)
exit(OVERFLOW);/*存储分配失败*/
(*H).elem=p;
for(i=0;i<m;i++)
(*H).elem[i].key=NULLKEY;/*未填记录的标志(初始化)*/
for(p=elem;p<elem+count;p++)/*将原有的数据按照新的表长插入到重建
的哈希表中*/
InsertHash(H,*p);
}
//在哈希表中插入数据元素
Status InsertHash(HashTable *H,ElemType e)
{/*查找不成功时插入数据元素e到开放定址哈希表H中,并返回OK; */
/*若冲突次数过大,则重建哈希表。*/
int c,p;
c=0:
if(SearchHash(*H,e.key,&p,&c))/*表中已有与e有相同关键字的元素*/
return DUPLICATE;
else if(c<hashsize[(*H).sizeindex]/2)/*冲突次数c未达到上限,(c的阀值可
调)*/
{/*插入e*/
(*H).elem[p]=e;
++(*H).count;
return OK:
}
else
RecreateHashTable(H);/*重建哈希表*/
return ERROR;
}
//哈希表的遍历
void TraverseHash(HashTable H)
{/*按哈希地址的顺序遍历哈希表*/
int i:
printf(”哈希地址O~%d\n',m-1);
for(i=0;i<m;i++)
if(H.elem[i].key!=NULLKEY)/*有数据*/
printf(“(%d, %d), ”,i,H.elem[i]);
}
//.查找
Status Find(HashTable H,KeyType K,int*p)
{/*在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查
数据元素在表中位置,并返回SUCCESS;否则返回UNSUCCESS*/
int c=O:
*p=Hash(K);/*求得哈希地址*/
while(H.elem[*p].key!=NULLKEY&&!EQ(K,H.elem[*p].key))
{/*该位置中填有记录.并且关键字不相等*/
C++;
if
(c<m)
collision(p,c);/*求得下一探查地址p*/
else
return
UNSUCCESS;/*查找不成功(H.elem[p].key==NULLKEY)*/
}
If EQ(K,H.elem[*p].key)
return
SUCCESS;
/*查找成功,P返回待查数据元素位置*/
return UNSUCCESS;/*查找不成功(H.elem[p].key==NULLKEY)*/
}
Void main()
{int key[12]={19,01,23,14,55,20,84,27,68,11,10,77}
HashTable * H ;
ElemType e;
InitHashTable(&H);
For(i=0;i<12;i++)
{e=key[i];
InsertHash(&H, e)
}
TraverseHash(H);
}
四、思考题
1.如何用链地址法来处理冲突?
实验十一:各种排序算法
实验学时:2
实验类型:验证
实验要求:必修
一、实验目的
1.掌握排序的基本概念及操作过程。
2.熟悉各种内部排序的基本原理和操作方法
二、实验内容
插入排序、希尔排序 、冒泡排序、选择排序 、快速排序算法
三、程序清单
//-------------五种排序算法演示
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "dos.h"
#define Max 100
typedef int sqlist[Max+1];
void insertsort(sqlist a,int n)
{
int i,j;
for(i=2;i<=n;i++)
{
if(a[i]<a[i-1])
{
a[0]=a[i];
for(j=i-1;a[0]<a[j];--j)
a[j+1]=a[j];
a[j+1]=a[0];
}
}
}
void shellsort(sqlist r,int n)
{
int i,j,gap,x;
gap=n/2;
while(gap>0)
{
for(i=gap+1;i<=n;i++)
{
j=i-gap;
while(j>0)
if(r[j]>r[j+gap])
{
x=r[j];
r[j]=r[j+gap];
r[j+gap]=x;
j=j-gap;
}
else j=0;
}
gap=gap/2;
}
}
void bubblesort(sqlist r,int n)
{
int i,j,w;
for(i=1;i<=n-1;i++)
for(j=n;j>=i+1;j--)
if(r[j]<r[j-1])
{
w=r[j];
r[j]=r[j-1];
r[j-1]=w;
}
}
void selectsort(sqlist r,int n)
{
int i,j,k,temp;
for(i=1;i<=n-1;i++)
{
k=i;
for(j=i+1;j<=n;j++)
if(r[j]<r[k]) k=j;
temp=r[i];
r[i]=r[k];
r[k]=temp;
}
}
int partion( sqlist a,int n,int low,int high)
{
int p,i;
p=a[low];
a[0]=a[low];
while(low<high)
{
while(low<high&&a[high]>=p) --high;
a[low]=a[high];
while(low<high&&a[low]<=p) ++low;
a[high]=a[low];
}
a[low]=a[0];
/* for(i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n\n");*/
return
low;
}
void
quicksort(sqlist a,
int
n,
int
low,
int
high)
{
int
p,i;
if
(low<high)
{
p=partion(a,n,low,high);
quicksort(a,n,low,p-1);
quicksort(a,n,p+1,high);
}
}
main()
{
int
i,n=10;
char
ch;
sqlist a;
for
(i=1;i<=10;i++)
a[i]=11-i;
printf
(
"\n\n"
);
printf
(
" ┌─────────────┐\n"
);
printf
(
" │ 1---插入排序 │\n"
);
printf
(
" │ 2---希尔排序 │\n"
);
printf
(
" │ 3---冒泡排序 │\n"
);
printf
(
" │ 4---选择排序 │\n"
);
printf
(
" │ 5---快速排序 │\n"
);
printf
(
" │ 请选择(1--5) │\n"
);
printf
(
" └─────────────┘\n"
);
ch=getch();
if
(ch==
'1'
) {
printf
(
"插入排序的结果是:\n"
);insertsort(a,n);}
else
if
(ch==
'2'
){
printf
(
"希尔排序的结果是:\n"
);shellsort(a,n);}
else
if
(ch==
'3'
){
printf
(
"冒泡排序的结果是:\n"
);bubblesort(a,n);}
else
if
(ch==
'4'
){
printf
(
"选择排序的结果是:\n"
);selectsort(a,n);}
else
if
(ch==
'5'
){
printf
(
"快速排序的结果是:\n"
);quicksort(a,n,1,n);}
else
printf
(
"对不起,你选择的参数不对!"
);
for
(i=1;i<=10;i++)
printf
(
"%5d"
,a[i]);
}
四、思考题
1.将上面几种排序算法进行比较
实验十二:银行模拟
实验学时:2
实验类型:综合
实验要求:选修
一、实验目的
掌握利用动态链表进行队列的动态事件的模拟
二、实验内容
银行模拟
三、程序清单
程序清单
/******************离散事件模拟******************************************
模拟银行处理客户业务.
************************************************************************/
# define CLOSTIME 480 /***银行下班时间(以分钟为单位)****/
# define ERROR 0
# define NULL 0
# define OVERFLOW -2
# define MAX_INTERTIME 10 /***距下一客户到达的最大时间*****/
# define MAX_DURTIME 15 /***处理单个客户业务的最大时间***/
# include "stdio.h "
# include "alloc.h"
# include "stdlib.h"
# include "conio.h"
typedef
struct
{
/*事件类型******************************************/
int
occurtime;
/*事件发生时刻**************************************/
int
ntype ;
/*事件类型,0表示到达事件,1至4表示四个窗口的离开时间*/
} event ,elemtype;
typedef
struct
linklist {
/*事件链表类型,定义为有序链表**************/
elemtype data ;
struct
linklist *next ;
} linklist;
typedef
struct
{
/***事件链表类型,(len为结点个数)***/
linklist * head;
int
len ;
} eventlist;
typedef
struct
{
/*队列元素类型*******************/
int
arrivaltime ;
/*到达时刻***********************/
int
duration ;
/*办理事务所需时间***************/
} qelemtype;
typedef
struct
qnode{
/***队列结点元素类型*************/
qelemtype data;
struct
qnode * next;
} qnode;
typedef
struct
{
/***队列类型*******************/
qnode *front;
qnode *rear ;
int
len ;
} linkqueue;
/************全局变量的定义******************************/
eventlist *ev;
/*事件表*/
event en;
/*事件*********************/
linkqueue * q[5];
/*4个客户队列**************/
qelemtype customer;
/*客户记录*****************/
int
totaltime;
/***累计客户逗留时间********/
int
customernum;
/***客户数 *********/
/************函数的定义********************************/
int
cmp(event en,event b)
/***比较事件发生的先后***/
/*依据事件en和b的发生先后返回1或0*/
{
if
(en.occurtime>=(b.occurtime))
return
1;
else
return
0;
}
double
random0_1()
/****产生0 到 1 之间的随机数**/
{
static
long
seed=3;
long
a=16807;
long
m=2147483647;
long
q=127773;
long
r=2836;
seed=a*(seed%q)-r*(seed/q) ;
if
(seed<0) seed+=m;
return
(
double
)seed/(
double
)m;
}
void
random2(
int
*durtime,
int
*intertime)
/**产生1 到MAX_DURTIME 之间的随机数*/
{
/**产生1 到MAX_INTERTIME 之间的随机数*/
*durtime=(
int
)(1+MAX_DURTIME*random0_1()) ;
*intertime=(
int
)(MAX_INTERTIME*random0_1()) ;
}
eventlist * initlist ()
/*产生一个空链表,并返回其地址******/
{
eventlist *evp;
evp=(eventlist*)
malloc
(
sizeof
(eventlist));
if
(!evp)
exit
(OVERFLOW);
evp->head=NULL;
evp->len=0;
return
(evp);
}
int
emptyeventlist (eventlist * ev)
/******* 检查链表是否为空************/
{
return
(ev->len);
}
linklist * delfirst(eventlist * ev)
/*** 删除链表中的第一个结点,并返回其地址*/
{
linklist *p;
p=ev->head;
ev->head=p->next;
ev->len--;
return
(p) ;
}
event getcurelem(linklist *p)
/***返回p 指针所指向结点的元素**********/
{
return
(p->data);
}
void
orderinsert(eventlist* ev,event en)
/***按事件发生的先后将事件en插入有序链表中*/
{
event en_temp;
linklist* s ,*p,*q;
s=(linklist*)
malloc
(
sizeof
(linklist));
if
(!s)
exit
(OVERFLOW);
else
{
s->data=en;
s->next=NULL;
}
if
(ev->head==NULL||(en.occurtime<ev->head->data.occurtime))
{ s->next=ev->head;
ev->head=s;
}
else
{
q=ev->head;
p=q->next ;
en_temp=getcurelem(p);
while
((p!=NULL)&& en.occurtime>en_temp.occurtime)
{
q=p;
p=p->next;
en_temp=getcurelem(p);
}
s->next =p;
q->next=s;
}
ev->len++;
}
linkqueue * initqueue()
/***创建空队列******/
{
linkqueue * q;
q=(linkqueue*)
malloc
(
sizeof
(linkqueue));
if
(!q)
exit
(OVERFLOW);
q->front=q->rear=(qnode*)
malloc
(
sizeof
(qnode));
if
(!q->front)
exit
(OVERFLOW);
q->front->next=NULL;
q->len=0;
return
(q) ;
}
void
enqueue(linkqueue*q,qelemtype e)
/***将e结点元素插入队列q中**/
{
qnode *p;
p=(qnode*)
malloc
(
sizeof
(qnode));
if
(!p)
exit
(OVERFLOW);
else
p->data=e;
p->next=NULL;
q->rear->next=p;
q->rear=p;
q->len++;
}
int
queueempty(linkqueue*q)
/****检查队列是否为空******/
{
return
(q->len);
}
int
queuelength(linkqueue*q)
/****检查队列的长度*******/
{
return
(q->len);
}
qelemtype delqueue(linkqueue *q)
{
qelemtype customer;
qnode *p;
if
(q->front==q->rear)
exit
(ERROR);
p=q->front->next;
customer=p->data;
q->front->next=p->next;
if
(q->rear==p)q->rear=q->front;
free
(p);
q->len--;
return
(customer);
}
qelemtype gethead_q(linkqueue*q)
/**返回第一个结点数据域的值***/
{
qelemtype customer;
qnode *p;
if
(!queueempty(q))
exit
(ERROR);
p=q->front->next;
customer=p->data;
return
(customer);
}
int
minnum(linkqueue*q[])
/***返回几个队列中结点最少的队列的序号**/
{
int
min1,min2;
min1=queuelength(q[1])<=queuelength(q[2])? 1 : 2 ;
min2=queuelength(q[3])<=queuelength(q[4])? 3 : 4 ;
return
queuelength(q[min1])<=queuelength(q[min2]) ? min1 :min2 ;
}
void
openforday()
/***初始化环境*****/
{
int
i;
totaltime=0; customernum=0;
ev=initlist();
en.occurtime=0; en.ntype=0;
orderinsert(ev,en) ;
for
(i=1;i<5;i++)
q[i]=initqueue();
}
void
customerarrived()
/** 客户到达事件函数**/
{
event en_temp;
qelemtype e_temp;
int
i,t,durtime,intertime;
customernum++;
random2(&durtime,&intertime);
t=en.occurtime+intertime;
en_temp.occurtime=t;
en_temp.ntype=0;
if
(t<CLOSTIME)
orderinsert(ev,en_temp);
i=minnum(q);
e_temp.arrivaltime=en.occurtime;
e_temp.duration=durtime ;
enqueue(q[i],e_temp);
if
(queuelength(q[i])==1)
{
en_temp.occurtime=en.occurtime+durtime;
en_temp.ntype=i;
orderinsert(ev,en_temp);
}
}
void
customerdeparture()
/*客户离开事件函数****/
{
event en_temp;
int
i=en.ntype;
customer=delqueue(q[i]);
//printf("%4d , %4d\n",en.occurtime,customer.arrivaltime);
totaltime+=en.occurtime-customer.arrivaltime;
if
(queueempty(q[i]))
{ customer=gethead_q(q[i]);
en_temp.occurtime=en.occurtime+customer.duration;
en_temp.ntype=i;
orderinsert(ev,en_temp);
}
}
void
bank_simulation()
{
linklist *p;
openforday();
while
(emptyeventlist(ev))
{
p=delfirst(ev);
en=getcurelem(p);
if
(en.ntype==0)
customerarrived();
else
customerdeparture();
}
printf
(
"totaltime=%d customernum=%d \n"
,totaltime,customernum);
printf
(
"\nthe average time is %f\n"
,(
float
)totaltime/(
float
)customernum);
}
void
main()
{
bank_simulation();
}