数据结构编程笔记二:第一章 绪论 三元组的程序实现
来源:互联网 发布:斯诺克最新过百数据 编辑:程序博客网 时间:2024/06/07 13:00
第一章主要是让大家入门,理解ADT的作用,所以书的作者没有安排太难的程序,只安排了三元组。
写C的童鞋都知道,写指针程序是个麻烦事,且不说调试遇到的各种奇葩问题,仅仅是打*号字符就是一个麻烦,每次手都必须伸到很远去找星号。为了解决这个麻烦,我们给指针起个别名,可以减少星号的输入。C语言中的返回值只能带回一个变量(当然了,可以用结构体封装多个结果,就是往回带结果的时候还得逐个去设置,想想就麻烦),使用C++中的引用参数可以方便的带回多个操作结果。本次的程序分为指针版和引用版,旨在帮助大家搞清楚指针和引用是什么关系,从线性表开始,我们就用引用来写程序了。
程序在码云上可以下载。
地址:https://git.oschina.net/601345138/DataStructureCLanguage.git
我们的程序主要分为以下几个部分(以后的程序都是如此,不再重复说明):
- 数据结构的ADT定义和程序操作的各种声明
- 引入头文件
- 自定义常量
- 自定义数据类型以及typedef给已有数据类型起别名
- 对ADT定义的各个操作算法的实现
- 主函数调用各个函数完成对算法的演示
- 程序运行结果的截屏(我采用复制控制台字符的方式,不截图,方便大家复制我的测试输入数据)
我们要完成的程序要求如下:
设计实现抽象数据类型“三元组 (Triplet)” 。 每个三元组由任意三个实数的序列构成,基本操作包括:创建一个三元组,取三元组的任意一个分量,置三元组的任意一个分量,求三元组的最大分量、最小分量,显示三元组,销毁三元组等。
抽象数据类型三元组的定义:
ADT Triplet { 数据对象:D={e1,e2,e3|e1,e2,e3属于ElemSet (定义了关系运算的某个集合)} 数据关系:R={<e1,e2>|<e2,e3>} 基本操作: 1.创建三元组 createTriplet() 初始条件:无 操作结果:已申请好三元组所占的内存空间,并返回带有三元组首地址的指针。 2.初始化三元组 initTriplet(*T,v0,v1,v2) 初始条件:已成功输入vo,v1,v2的值,并且已经开辟好三元组的内存空间 操作结果:元素e1,e2和e3分别被赋予参数v1,v2,v3的值。 3.销毁三元组 destroyTriplet(*T) 初始条件:三元组已经存在。 操作结果:销毁三元组T。 4.获取第i个元素的值 getElem(*T,i,&e) 初始条件:三元组已经存在且1<=i<=3. 操作结果:用e返回三元组的第i个元素。 5.置三元组第i个元素的值 putElem(*T,i,e) 初始条件:三元组已经存在且1<=i<=3. 操作结果:用e值取代三元组的第i个元素。 6.判断三元组的三个元素是否为升序排列 isAscending(*T) 初始条件:三元组已经存在。 操作结果:如果三元组的三个元素按升序排列,则返回TRUE;否则返回FALSE。 7.判断三元组的三个元素是否为降序排列 isDescending(*T) 初始条件:三元组已经存在。 操作结果:如果三元组的三个元素按降序排列,则返回TRUE,否则返回FALSE。 8.获取三元组三个元素中的最大值 getMax(*T,&e) 初始条件:三元组已经存在。 操作结果:用e返回的3个元素中的最大值。 9.获取三元组三个元素中的最小值 getMin(*T,&e) 初始条件:三元组已经存在。 操作结果:用e返回的3个元素中的最小值。 } ADT Triplet
首先看看静态存储分配方式的指针版程序:
#include<stdio.h>#define OK 1#define ERROR 0typedef int Status;typedef float ElemType; //三元组元素的类型先定义为int,可以随时变换成别的类型 typedef struct{ ElemType e[3];}Triplet;//三元组的初始化Status initTriplet(Triplet *T,ElemType v0,ElemType v1,ElemType v2){ T->e[0]=v0; T->e[1]=v1; T->e[2]=v2; return OK;}//销毁三元组,静态存储是在程序开始的时候就分配固定的内存单元,整个程序结束后自动释放存储单元,不需销毁 //而动态存储单元在程序运行初不分配内存单元在用到时才分配,而当用过后需要用语句释放该内存空间Status destroyTriplet(Triplet *T){ return OK;}//用e获取T的第i(1~3)个元素的值, Status getElem(Triplet T,int i,ElemType *e){ if(i<1||i>3) return ERROR; else *e=T.e[i-1]; return OK;}//置T的第i元的值为e Status putElem(Triplet *T,int i,ElemType e){ if(i<1||i>3) return ERROR; else T->e[i-1]=e; return OK;}//如果T的三个元素按升序排列,则返回1,否则返回0Status isAscending(Triplet *T){ return (T.e[0]<=T.e[1])&&(T.e[1]<=T.e[2]);} //如果T的三个元素按降序排列,则返回1,否则返回0Status isDescending(Triplet T){ return (T.e[0]>=T.e[1])&&(T.e[1]>=T.e[2]);} //用e返回指向T的最大元素的值ElemType getMax(Triplet T){ ElemType e; if(T.e[0]>T.e[1]) e=T.e[0]; else e=T.e[1]; if(T.e[2]>e) e=T.e[2]; return e;} //用e返回指向T的最小元素的值ElemType getMin(Triplet T){ ElemType e; if(T.e[0]<T.e[1]) e=T.e[0]; else e=T.e[1]; if(T.e[2]<e) e=T.e[2]; return e;} int main(){ Status flag; ElemType v0,v1,v2; Triplet T; printf("请进入三元组的三个值v0,v1,v2:\n"); scanf("%f,%f,%f",&v0,&v1,&v2); flag=initTriplet(&T,v0,v1,v2); printf("调用初始化函数后,flag=%d,T的三个值为:%4.2f,%4.2f,%4.2f\n",flag,T.e[0],T.e[1],T.e[2]); if(isAscending(T)) printf("该三元组元素为升序\n"); if(isDescending(T)) printf("该三元组元素为降序\n"); printf("该三元组中的最大值为:%4.2f,最小值为:%4.2f",getMax(T),getMin(T)); return OK;}
再看看动态内存分配方式的指针版程序:
#include<stdio.h>#include<stdlib.h>#include<conio.h>#define OK 1#define ERROR 0#define OVERFLOW -2 typedef int Status;typedef float ElemType; //三元组的类型先定义为float,可以随时变换成别的类型 typedef ElemType *Triplet;//声明Triplet为ElemType指针类型 //三元组的初始化Status initTriplet(Triplet *T,ElemType v0,ElemType v1,ElemType v2) // Triplet *T可以写成 ElemType **T { (*T)=(ElemType *)malloc(3*sizeof(ElemType)); if((*T)==NULL) { printf("分配内存失败!"); exit(OVERFLOW); } *(*T+0)=v0; *(*T+1)=v1; *(*T+2)=v2; return OK;}Status destroyTriplet(Triplet *T){ free(*T); *T=NULL; printf("分配内存已释放!"); return OK;}//用e获取T的第i(1~3)个元素的值, Status getElem(Triplet T,int i,ElemType *e){ if(i<1||i>3) return ERROR; else *e=T[i-1]; return OK;}//置T的第i元的值为e Status putElem(Triplet *T,int i,ElemType e){ if(i<1||i>3) return ERROR; else *(*T+i-1)=e; return OK;}//如果T的三个元素按升序排列,则返回1,否则返回0Status isAscending(Triplet T){ return (T[0]<=T[1])&&(T[1]<=T[2]);} //如果T的三个元素按降序排列,则返回1,否则返回0Status isDescending(Triplet T){ return (T[0]>=T[1])&&(T[1]>=T[2]);} //用e返回指向T的最大元素的值ElemType getMax(Triplet T){ ElemType e; if(T[0]>T[1]) e=T[0]; else e=T[1]; if(T[2]>e) e=T[2]; return e;} //用e返回指向T的最小元素的值ElemType getMin(Triplet T){ ElemType e; if(T[0]<T[1]) e=T[0]; else e=T[1]; if(T[2]<e) e=T[2]; return e;} int main(){ Status flag; ElemType v0,v1,v2,e; Triplet T; printf("请进入三元组的三个值v0,v1,v2:\n"); scanf("%f,%f,%f",&v0,&v1,&v2); flag=initTriplet(&T,v0,v1,v2); printf("调用初始化函数后,flag=%d,T的三个值为:%4.2f,%4.2f,%4.2f\n",flag,T[0],T[1],T[2]); if(isAscending(T)) printf("该三元组元素为升序\n"); if(isDescending(T)) printf("该三元组元素为降序\n"); printf("该三元组中的最大值为:%4.2f,最小值为:%4.2f\n",getMax(T),getMin(T)); destroyTriplet(&T); return OK;}
然后再来看看引用版程序,明显是精简了不少,至少没星号了:
静态存储引用版:
#include<stdio.h>#define OK 1#define ERROR 0typedef int Status;typedef float ElemType; //三元组元素的类型先定义为int,可以随时变换成别的类型 typedef struct{ ElemType e[3];}Triplet;//三元组的初始化Status initTriplet(Triplet &T,ElemType v0,ElemType v1,ElemType v2){ T.e[0]=v0; T.e[1]=v1; T.e[2]=v2; return OK;}//销毁三元组,静态存储是在程序开始的时候就分配固定的内存单元,整个程序结束后自动释放存储单元,不需销毁 //而动态存储单元在程序运行初不分配内存单元在用到时才分配,而当用过后需要用语句释放该内存空间Status destroyTriplet(Triplet &T){ return OK;}//用e获取T的第i(1~3)个元素的值, Status getElem(Triplet T,int i,ElemType &e){ if(i<1||i>3) return ERROR; else e=T.e[i-1]; return OK;}//置T的第i元的值为e Status putElem(Triplet &T,int i,ElemType e){ if(i<1||i>3) return ERROR; else T.e[i-1]=e; return OK;}//如果T的三个元素按升序排列,则返回1,否则返回0Status isAscending(Triplet T){ return (T.e[0]<=T.e[1])&&(T.e[1]<=T.e[2]);} //如果T的三个元素按降序排列,则返回1,否则返回0Status isDescending(Triplet T){ return (T.e[0]>=T.e[1])&&(T.e[1]>=T.e[2]);} //用e返回指向T的最大元素的值ElemType getMax(Triplet T){ ElemType e; if(T.e[0]>T.e[1]) e=T.e[0]; else e=T.e[1]; if(T.e[2]>e) e=T.e[2]; return e;} //用e返回指向T的最小元素的值ElemType getMin(Triplet T){ ElemType e; if(T.e[0]<T.e[1]) e=T.e[0]; else e=T.e[1]; if(T.e[2]<e) e=T.e[2]; return e;} int main(){ Status flag; ElemType v0,v1,v2; Triplet T; printf("请进入三元组的三个值v0,v1,v2:\n"); scanf("%f,%f,%f",&v0,&v1,&v2); flag=initTriplet(T,v0,v1,v2); printf("调用初始化函数后,flag=%d,T的三个值为:%4.2f,%4.2f,%4.2f\n",flag,T.e[0],T.e[1],T.e[2]); if(isAscending(T)) printf("该三元组元素为升序\n"); if(isDescending(T)) printf("该三元组元素为降序\n"); printf("该三元组中的最大值为:%4.2f,最小值为:%4.2f",getMax(T),getMin(T)); return OK;}
动态分配引用版(以后的程序多数采用此方式):
//***********************引入头文件***************************# include <stdio.h># include <malloc.h># include <stdlib.h>//*********************自定义符号常量**************************# define OK 1# define ERROR 0# define TRUE 1# define FALSE 0# define OVERFLOW -1//********************自定义数据类型**************************typedef int Status;typedef int ElemType;typedef ElemType * Triplet;//*******************三元组的主要操作*************************/* 函数:createTriplet 参数:Triplet &T 三元组引用 返回值:无 作用:创建三元组 */void createTriplet(Triplet &T){ T = (Triplet)malloc(sizeof(ElemType)); if(!T){ //if(!T) <=> if(T == null) printf("申请内存失败!\n"); exit(OVERFLOW); }//if}//createTriplet/* 函数:InitTriplet 参数:Triplet &T 三元组引用 ElemType v1 三元组第一个分量 ElemType v2 三元组第二个分量 ElemType v3 三元组第三个分量 返回值:状态码,OK表示操作成功 作用:初始化三元组 */Status InitTriplet(Triplet &T, ElemType v1,ElemType v2,ElemType v3){ //创建一个三元组 createTriplet(T); //初始化三元组的三个分量 T[0] = v1; T[1] = v2; T[2] = v3; //操作成功 return OK;}//InitTriplet/* 函数:DestroyTriplet 参数:Triplet &T 三元组引用 返回值:状态码,OK表示操作成功 作用:销毁三元组 */Status DestroyTriplet(Triplet &T){ free(T); //释放内存空间 T = NULL; //指针清零 return OK; //操作成功 }//DestroyTriplet/* 函数:getElem 参数:Triplet T 三元组结构体指针 int i 索引变量,指示三元组中的第几个分量 ElemType &e 带回的元素E 返回值:状态码,OK表示操作成功 作用:取出三元组第i个分量存储的数据 */Status getElem(Triplet T, int i, ElemType &e){ //检查索引变量i是否越界 if(i < 1 || i > 3){ return ERROR; }//if //取出对应位置元素 e = T[i - 1]; //操作成功 return OK;}//getElem/* 函数:putElem 参数:Triplet &T 三元组引用 int i 索引变量,指示三元组中的第几个分量 ElemType &e 带回的元素E 返回值:状态码,OK表示操作成功 作用:修改三元组第i个分量的值 */Status putElem(Triplet &T, int i, ElemType e){ //检查索引变量是否正确 if(i < 1 || i > 3) { return ERROR; }//if //修改元素的值 T[i - 1] = e; //操作成功 return OK;}//putElem/* 函数:isAscending 参数:Triplet T 三元组结构体指针 返回值:如果三元组的三个元素按升序排列,则返回TRUE;否则返回FALSE。 作用:判断三元组是否升序排列 */Status isAscending(Triplet T){ return T[0] <= T[1] && T[1] <= T[2];}//isAscending/* 函数:isDescending 参数:Triplet T 三元组结构体指针 返回值:如果三元组的三个元素按降序排列,则返回TRUE;否则返回FALSE。 作用:判断三元组是否降序排列 */Status isDescending(Triplet T){ return T[0] >= T[1] && T[1] >= T[2];}//isDescending/* 函数:getMax 参数:Triplet T 三元组结构体指针 ElemType &e 带回三元组中三个分量的最大值 返回值:状态码,OK表示操作成功 作用:获得三元组中三个分量的最大值 */Status getMax(Triplet T, ElemType &e){ //通过三目条件运算符求得最大值 e = T[0] >= T[1] ? (T[0] >= T[2] ? T[0] : T[2]) : (T[1] >= T[2] ? T[1] : T[2]); //操作成功 return OK;}//getMax/* 函数:getMin 参数:Triplet T 三元组结构体指针 ElemType &e 带回三元组中三个分量的最小值 返回值:状态码,OK表示操作成功 作用:获得三元组中三个分量的最小值 */Status getMin(Triplet T, ElemType &e){ //通过三目条件运算符求得最小值 e = T[0] <= T[1] ? (T[0] <= T[2] ? T[0] : T[2]) : (T[1] <= T[2] ? T[1] : T[2]); //操作成功 return OK;}//getMin//-----------------------主函数--------------------------------- int main(){ Triplet T; ElemType v0, v1, v2, e; Status flag, temp, temp1; printf("请输入v0,v1,v2:"); scanf("%d,%d,%d", &v0, &v1, &v2); flag = InitTriplet(T, v0, v1, v2); printf("调用初始化函数后,flag=%d(1:成功) T的三个值为:%d %d %d\n", flag, T[0], T[1], T[2]); printf("您想查找三元组第几个元素的值(1-3):\n"); scanf("%d", &temp); getElem(T, temp, e); printf("三元组第%d个元素的值:%d\n", temp, e); printf("您想重置三元组第几个元素的值(1-3):\n"); scanf("%d", &temp); printf("您想重置三元组第%d个元素的值为多少?:\n", temp); scanf("%d", &temp1); putElem(T, temp, temp1); printf("三元组第%d个元素重置后的值:%d\n", temp, T[temp-1]); printf("重置第%d个元素后三元组的三个值为:%4d,%4d,%4d\n", temp, T[0], T[1], T[2]); if(isAscending(T)) //判断三元组是否为升序 printf("该三元组元素为升序!\n"); else if(isDescending(T)) //再判断三元组是否为降序 printf("该三元组元素为降序!\n"); else //若以上两条件均不符合则提示用户既不是升序也不是降序 printf("该三元组元素既不是升序也不是降序!\n"); //输出三元组的最大值和最小值 getMax(T, e); printf("该三元组中的最大值为:%4d\n", e); getMin(T, e); printf("该三元组中的最小值为:%4d\n", e); printf("销毁三元组\n"); DestroyTriplet(T); return 0;}
接下来看看程序的运行结果:
/**********************测试记录************************** 请输入v0,v1,v2:1,2,5 调用初始化函数后,flag=1(1:成功) T的三个值为:1 2 5 您想查找三元组第几个元素的值(1-3): 3 三元组第3个元素的值:5 您想重置三元组第几个元素的值(1-3): 2 您想重置三元组第2个元素的值为多少?: 56 三元组第2个元素重置后的值:56 重置第2个元素后三元组的三个值为: 1, 56, 5 该三元组元素既不是升序也不是降序! 该三元组中的最大值为: 56 该三元组中的最小值为: 1 -------------------------------- Process exited after 18.11 seconds with return value 0 请按任意键继续. . .*/
通过对四种实现方式的比较,相信大家能更好的理解指针和引用的概念,初步了解ADT的作用了。
如果大家对程序有什么看法和意见,欢迎提出来。
下一期内容是线性表——顺序表的实现。
- 数据结构编程笔记二:第一章 绪论 三元组的程序实现
- 《数据结构》 笔记 第一章 绪论
- 第一章 数据结构绪论(数据结构笔记)
- 《数据结构》学习笔记--第一章 绪论
- [MOOC笔记]第一章 绪论(数据结构)
- 数据结构【第一章 绪论】 个人笔记
- 数据结构 第一章绪论 学习笔记
- 《数据结构》学习笔记--第一章绪论
- 《大话数据结构》笔记之 第一章 数据结构绪论
- 《数据结构》---三元组的实现
- 数据结构C++版第一章绪论课后笔记
- 数据结构笔记——第一章 绪论
- 数据结构学习笔记<一>三元组的具体实现
- 数据结构 严蔚敏 清华大学出版社 第一章 抽象数据类型 三元组的实现 成功编译并运行
- 数据结构 严蔚敏 清华大学出版社 第一章 抽象数据类型 三元组的实现 成功编译并运行
- 数据结构第一章 数据结构绪论
- 数据结构实现三元组
- 数据结构 第一章 绪论
- Android Touch事件传递机制通俗讲解
- js控制输入框最大长度
- Qt第一天——搭建开发环境
- hihocoder 1174 : 拓扑排序·一
- TF随笔-14-二分法求解一元方程
- 数据结构编程笔记二:第一章 绪论 三元组的程序实现
- redis面试总结
- 解决频繁升级Xcode问题
- js读取xml的<![CDATA[]]>存放内容
- TCP/IP, WebSocket 和 MQTT
- reselsense采集深度值
- 如何防止鼠标移出移入子元素触发mouseout和mouseover事件
- java集合vector与stack
- 简单背景图片,鼠标移动特效