数据结构 实验.docx
- 文档编号:23126071
- 上传时间:2023-05-08
- 格式:DOCX
- 页数:88
- 大小:177.80KB
数据结构 实验.docx
《数据结构 实验.docx》由会员分享,可在线阅读,更多相关《数据结构 实验.docx(88页珍藏版)》请在冰豆网上搜索。
数据结构实验
第1部分实验
实验1线性表基本运算及其应用
案例1.1采用顺序表模拟约瑟夫(Josephus)问题
【案例说明】
编号为1,…,n的n个人按顺时针方向围坐一圈,从第1号的人开始按顺时针方向自1开始顺序报数,报到m(m<n)时停止报数。
报m的人出列,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。
试设计一个程序,采用顺序表模拟此过程,按照出列的顺序输出每个人的编号。
【案例目的】
(1)验证线性表的两种存储结构及线性表的基本运算在两种存储结构上的实现。
(2)掌握以线性表作为数据结构解决实际问题的方法。
【技术要点】
1.类型定义
#defineM100/*顺序表的最大长度*/
typedefintElemType;/*ElemType为顺序表元素的类型*/
typedefstruct{
ElemTypedata[M];
intlength;/*顺序表的实际长度*/
}SqList;
2.算法思想
(1)L->data[0..n﹣1]存放n个人,初始化所有数组元素为1,即所有人均未出列;当某个人出列时,该数组元素置0。
(2)设置变量i标记数组元素的下标或报数人的序号,从序号为0的人开始报数;设目前刚刚报数的人的序号为i(i (3)设置变量out标记出列人数,控制循环执行次数,当out取值0到n﹣1时,执行循环,否则退出循环。 (4)设置变量count累计报数人数,决定某一个人是否出列,count从0开始累计,只有未出列的人员参与报数,当count==m时,①刚报数的人需要置0出列、输出序号;②出列人数out加1;③count重新置0,准备开始下一轮报数。 3.测试数据 输入: inputn(总人数): 8 inputm: 3 输出: outputdata: 36152847 【代码实现】 #include #defineMAXSIZE100/*顺序表的最大长度*/ typedefintElemType; typedefstruct{ ElemTypedata[MAXSIZE]; intlength;/*顺序表的实际长度*/ }SqList; voidbaoshu(SqList*L,intn,intm){ intcount,out,i; count=0; out=0; i=0; while(out if(L->data[i]==1) count++; if(count==m){ printf("%d",i+1); L->data[i]=0; out++; count=0; } i++; if(i==n)i=0; } } voidcreate(SqList*L,intn){ inti; for(i=0;i<=n-1;i++) L->data[i]=1; } main(){ intn,m; SqListL; printf("\ninputn: "); scanf("%d",&n); printf("\ninputm: "); scanf("%d",&m); create(&L,n); printf("\ntheorderis: "); baoshu(&L,n,m); } 案例1.2采用单链表实现线性表的就地逆置 【案例说明】 线性表的就地逆置,就是利用原表的存储空间将线性表(a1,a2,…,an)逆置为(an,an—1,…,a1),并且此处要求只使用一个元素的辅助空间。 【案例目的】 (1)验证线性表的两种存储结构及线性表的基本运算在两种存储结构上的实现。 (2)掌握以线性表作为数据结构解决实际问题的方法。 【技术要点】 1.类型定义 typedefintElemType; typedefstructnode{ ElemTypedata; structnode*next; }LNode,*LinkList; 2.算法思想 算法思想如下: (1)空表或长度为1的表,不做任何处理; (2)表长大于等于2时,做如下处理: ①从链表的第1个结点处断开; ②依次取剩余链表中的每个结点,将其作为第1个结点插入到前面的链表中去。 该算法只是对链表中的结点顺序扫描一遍,即完成了逆置,所以时间复杂度为O(n)。 3.测试数据 输入: inputn: 10 input10data: 8591581197 输出: Reversed! ! output: 7911851958 Deleted! ! output: 79185 【代码实现】 #include #include typedefintElemType; typedefstructnode{ ElemTypedata; structnode*next; }LNode,*LinkList; LinkListCreat_LinkListR(intn){/*利用尾插法建立带头结点的单链表*/ LinkListL,s,r; inti,x; L=(LinkList)malloc(sizeof(LNode));/*申请空间,生成头结点*/ r=L;/*指针r指向头结点*/ printf("\ninput%ddata: \n",n); for(i=1;i<=n;i++){ scanf("%d",&x); s=(LinkList)malloc(sizeof(LNode)); s->data=x; r->next=s;/*将新结点*s插入到指针r所指结点的后面*/ r=s;/*指针r指向新结点*/ } r->next=NULL;/*对于非空表,最后结点的指针域为空指针*/ returnL; } voidPrint_LinkList(LinkListL){/*输出单链表*/ LinkListp; p=L->next;/*p指向第1个结点*/ printf("\noutput: "); while(p){/*若p所指结点非空,输出*/ printf("%d",p->data); p=p->next; } } voidDel_LinkList(LinkListL){/*删除单链表中值相同的多余元素*/ LinkListp,q,r; for(p=L->next;p;p=p->next){/*顺序扫描单链表中的每一个结点*/ r=p;q=r->next; while(q){ if(q->data==p->data){ r->next=q->next; free(q); q=r->next; } else{ r=q;q=r->next; } } } } voidReverse_LinkList(LinkListL){/*单链表的就地逆置*/ LinkListp,q,s; if(! L->next||! L->next->next)return; q=L->next->next;/*q指向链表的第2个结点*/ L->next->next=NULL;/*从链表的第1个结点处断开*/ while(q){ s=q->next;/*s指向q的后继,q指向剩余链表的第1个结点*/ q->next=L->next; L->next=q; q=s; } } main(){ intn; LinkListhead; printf("\ninputn: "); scanf("%d",&n); head=Creat_LinkListR(n); printf("\nReversed! ! "); Reverse_LinkList(head); Print_LinkList(head); printf("\nDeleted! ! "); Del_LinkList(head); Print_LinkList(head); } 实验2栈和队列及其应用 案例2.1括号匹配的检验 【案例说明】 假设表达式中允许包含3种括号: 圆括号“(”和“)”,方括号“[”和“]”和花括号“{”和“}”,其嵌套的顺序随意,如“{([]())}”或“[([][])]”等为正确的格式,“[{(])”或“([])}()”或“(()))”均为错误的格式。 设计一个算法,要求检验一个给定表达式中的括号是否匹配? 【案例目的】 (1)验证栈的基本运算。 (2)掌握以栈作为数据结构解决实际问题的方法。 【技术要点】 1.类型定义 #defineMAXSIZE100/*最多元素数*/ typedefcharElemType; typedefstruct{ ElemTypedata[MAXSIZE];/*栈空间*/ inttop;/*栈顶指针*/ }SqStack; 2.算法思想 假设表达式存储在字符数组str中,设置一个元素为字符类型的栈S,用它来存储表达式中从左到右顺序扫描到的左括号,栈的最大深度不会超过表达式中左括号的个数。 算法思想: 顺序扫描字符数组str中的每一个字符,若遇到的是左括号,则令其入栈。 若遇到的是右括号,则当栈空时(缺少相配的左括号)报错。 否则,将栈顶元素弹出。 若弹出的括号不是相配的左括号(缺少相配的左括号),则报错。 当表达式扫描结束时,若栈空,则说明表达式中的括号匹配,返回1。 否则,说明表达式括号不匹配(缺少相配的右括号),报错,返回0。 3.测试数据 输入: 输入表达式: (a+b*c)+((d*e+f)*g) 输出: 括号匹配! 【代码实现】 #include #defineMAXSIZE100/*最多元素数*/ typedefcharElemType; typedefstruct{ ElemTypedata[MAXSIZE];/*栈空间*/ inttop;/*栈顶指针*/ }SqStack; voidInit_SqStack(SqStack*S){ S->top=-1; } intEmpty_SqStack(SqStack*S){ if(S->top==-1) return1; else return0; } voidPush_SqStack(SqStack*S,ElemTypex){ if(S->top==MAXSIZE-1){/*栈满,不能入栈*/ printf("栈满! "); } else/*栈非满,x入栈*/ S->data[++S->top]=x; } voidPop_SqStack(SqStack*S,ElemType*x){ if(Empty_SqStack(S)){/*栈空,不能进行出栈*/ printf("栈空! "); } else{/*栈顶元素存入变量x*/ *x=S->data[S->top]; S->top--; } } voidTop_SqStack(SqStack*S,ElemType*x){ if(S->top==-1)/*栈空,不能读取栈顶元素*/ printf("栈空! "); else/*栈顶元素存入变量x并返回*/ *x=S->data[S->top]; } intMatchsq(charstr[]){/*str中存放字符串表达式*/ inti=0;/*字符数组str的工作指针*/ charch; SqStackS; Init_SqStack(&S); for(i=0;str[i]! ='\0';i++){/*逐字符处理字符表达式的数组*/ switch(str[i]){ case'(': Push_SqStack(&S,str[i]); break; case')': if(Empty_SqStack(&S))return0; else{ Pop_SqStack(&S,&ch); if(ch! ='(')/*缺少相配的左括号*/ {printf("\n括号不配对! \n");return0;} } break; case'[': Push_SqStack(&S,str[i]); break; case']': if(Empty_SqStack(&S))return0; else{ Pop_SqStack(&S,&ch); if(ch! ='[')/*缺少相配的左括号*/ {printf("\n括号不配对! \n");return0;} } break; case'{': Push_SqStack(&S,str[i]);i++; break; case'}': if(Empty_SqStack(&S))return0; else{ Pop_SqStack(&S,&ch); if(ch! ='{')/*缺少相配的左括号*/ {printf("\n括号不配对! \n");return0;} } break; }/*switch结束*/ }/*for结束*/ if(Empty_SqStack(&S)) {printf("\n括号配对! \n");return1;} else/*缺少相配的右括号*/ {printf("\n括号不配对! \n");return0;} }/*算法结束*/ main(){ charstr[50]; printf("\n输入表达式: "); gets(str); Matchsq(str); } 案例2.2背包问题 【案例说明】 设有一个背包可以放入的物品质量为t,现有n件物品,质量分别为wl,w2,…,wn。 问能否从这n件物品中选择若干件放入此背包,使得放入的质量之和正好为t。 如果存在一种符合上述要求的选择,则称此背包问题有解(或称解为真),否则此问题无解(或称解为假)。 例如,当“intw[5]={1,4,4,5,7},n=5,t=10;”时,背包问题的解为真,方案1为: 第一个元素w[0]=1,第二个元素w[1]=4,第四个元素w[3]=5。 方案2为: 第一个元素w[0]=1,第三个元素w[2]=4,第四个元素w[3]=5。 【案例目的】 (1)验证栈的基本运算。 (2)掌握以栈作为数据结构解决实际问题的方法。 【技术要点】 若用knap(w,t,n)表示上述背包问题的解,这个函数的返回值要么为1(表示解为真),要么为0(表示解为假),其参数应满足t≥0,n≥1。 背包问题如果有解,其选择只有两种可能: 一种是选择的一组物品中不包含wn,这样knap(w,t,n)的解就是knap(w,t,n﹣1)的解;另一种是选择中包含wn,这样knap(w,t,n)的解就是knap(w,t﹣wn,n﹣l)的解。 另外,可以定义: 当t=0时,背包问题总有解,即knap(w,0,n)=1,只要不选择任何物品放入背包即可;当t<0时,背包问题总无解,即knap(w,t,n)=0,因为无论怎样选择总不能使质量之和为负值;当t>0但n<1时,背包问题也无解,即knap(w,t,n)=0,因为不取任何东西就要使质量为正值总是办不到的。 从而,背包问题可以递归定义如下: 上述递归定义的函数knap(w,t,n)是有递归出口的。 因为每递归调用一次n都减1,t也可能减少wn,所以递归若干次后,一定会出现t≤0或者n=0,无论哪种情况都可由定义找到解。 【代码实现】 递归算法源代码: intknap(intw[],intt,intn){/*递归算法*/ if(t==0) return (1);/*当t=0时,背包问题总有解*/ else if(t<0||t>0&&n<1) return(0);/*当t<0或t>0但n<1时,背包问题无解*/ else if(knap(w,t-w[n-1],n-1)==1){/*包含w[n-1],即knap(w,t,n)的解就是knap(w,t-w[n-1],n-l)的解*/ printf("result: n=%d,w[%d]=%d\n",n,n-1,w[n-1]); return (1); } else/*不包含w[n-1],即knap(w,t,n)的解就是knap(w,t,n-l)的解*/ return(knap(w,t,n-1)); } main(){ intw[5]={1,4,4,5,7}; intn=5; intt=10; knap(w,t,n); } 程序运行结果如图1.1所示 图1.1输出1个解 上述递归算法,可以改为用栈实现的非递归算法。 设一个栈,用来存放加入背包的物品序号,若某一时刻,栈中物品的总质量恰好等于背包要求容纳的质量时,即得到一个解。 利用栈的特点,还可以输出全部解。 程序运行结果如图1.2所示。 图1.2输出2个解 非递归算法源代码: #defineMAXSIZE100/*最多元素数*/ typedefintElemType; typedefstruct{ ElemTypedata[MAXSIZE];/*栈空间*/ inttop;/*栈顶指针*/ }SqStack; voidInit_SqStack(SqStack*S){S->top=-1;} intEmpty_SqStack(SqStack*S){ if(S->top==-1) return1; else return0; } voidPush_SqStack(SqStack*S,ElemTypex){ if(S->top==MAXSIZE-1){/*栈满,不能入栈*/ printf("栈满! "); } else/*栈非满,x入栈*/ S->data[++S->top]=x; } voidPop_SqStack(SqStack*S,ElemType*x){ if(Empty_SqStack(S)){/*栈空,不能进行出栈*/ printf("栈空! "); } else{/*栈顶元素存入变量x*/ *x=S->data[S->top]; S->top--; } } voidknap(intw[],intt,intn){/*非递归算法*/ SqStackS; intj,k; Init_SqStack(&S); k=0;/*从0号物品开始扫描*/ do{ while(t>0&&k if(t-w[k]>=0){/*序号为k的物品入栈*/ Push_SqStack(&S,k); t-=w[k]; } k++; } if(t==0){/*输出一个解*/ printf("\nresult: \n"); for(j=0;j<=S.top;j++) printf("n=%d,w[%d]=%d\n",S.data[j]+1,S.data[j],w[S.data[j]]); } Pop_SqStack(&S,&k);/*回溯寻求下一个解*/ t+=w[k];/*有物品出栈时,背包的剩余重量增加*/ k++; }while(! Empty_SqStack(&S)||k! =n); } main(){ intw[5]={1,4,4,5,7}; intn=5; intt=10; knap(w,t,n); } 案例2.3采用队列打印杨辉三角形 【案例说明】 杨辉三角形的图案如图1.3所示。 由图1.3可以看出杨辉三角形的特点: 即每一行的第一个数字和最后一个数字均为1,其他位置上的数字是其上一行中与之相邻的两个整数之和。 所以第i行上的元素要由第i﹣1行中的元素来生成。 图1.3杨辉三角形 【案例目的】 (1)验证队列的基本运算。 (2)掌握以队列作为数据结构解决实际问题的方法。 【技术要点】 1.类型定义 #defineMAXSIZE100/*最大队列长度*/ typedefintElemType; typedefstruct{ ElemTypedata[MAXSIZE];/*队列存储空间*/ intfront;/*头指针,若队列不空,指向队头元素*/ intrear;/*尾指针,若队列不空,指向队尾元素的下一个位置*/ }SqQueue; 2.算法思想 利用顺序队列实现打印杨辉三角形的过程: 在队列中依次存放第i行上的元素,然后逐个出队并打印,同时生成第i+1行上的元素并入队。 如果要求计算并输出杨辉三角前n行的值,则队列的最大空间应为n+2。 为了计算方便,在每行开始处添加一个0作为行界值,则在计算第i+1行元素时,队列头指针指向第i行开始处的0,而队列尾指针指向第k+1行开始处的0。 【代码实现】 #defineMAXSIZE100/*最大队列长度*/ typedefintElemType; typedefstruct{ ElemTypedata[MAXSIZE];/*队列存储空间*/ intfront;/*头指针,若队列不空,指向队头元素*/ intrear;/*尾指针,若队列不空,指向队尾元素的下一个位置*/ }SqQueue; voidInit_SqQueue(SqQueue*Q){/*构造一个空队列Q*/ Q->front=Q->rear=0; } intLength_SqQueue(SqQueue*Q){/*返回Q的元素个数,即队列的长度*/ return(Q->rear-Q->front); } intEmpty_SqQueue(SqQueue*Q){/*若队列Q为空,则返回1,否则返回0*/ return(Q->rear==Q->front); } intFull_SqQueue(SqQueue*Q){/*若队列Q为满,返回1,否则返回0*/ return(Q->rear+1==MAXSIZE)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 实验