3.1、设计任务与目标
3.1.1
分析论证:设计一系统,实现医药公司定期对销售各药品的记录进行统计,可按药品的编号、单价、销售量或销售额做出排名。
3.1.2目的意义:在本设计中,首先从数据文件中读出各药品的信息记录,存储在顺序表中。各药品的信息包括:药品编号、药名、药品单价、销出数量、销售额。药品编号共4位,采用字母和数字混合编号,如:A125,前一位为大写字母,后三位为数字,按药品编号进行排序时,可采用基数排序法。对各药品的单价、销售量或销售额进行排序时,可采用多种排序方法,如直接插入排序、冒泡排序、快速排序,直接选择排序等方法。在本设计中,对单价的排序采用冒泡排序法,对销售量的排序采用快速排序法,对销售额的排序采用堆排序法。
3.1.3达到目标:
(1)设计外部储存药品信息文件txt
(2)建立顺序表
(3)结合多种排序方法
3.2、数据结构和算法说明
3.2.1总体设计与分析和设计:
(1)要设计一个txt文档,把各个药品详细信息储存进去。
(2)代码中需要设计一个顺序表,用来储存外部文件拷贝进来的药品信息。
(3)采用多种排序方法,题目规定,对单价的排序采用冒泡排序法,对销售量的排序采用快速排序法,对销售额的排序采用堆排序法。
3.2.2采用的数据结构:
(1)多种排序方法:对单价的排序采用冒泡排序法。
冒泡排序
冒泡的基本思想是:
两个数比较大小,较大的数下沉,较小的数冒起来。
趟数
1 21 32 43 98 54 45 23 4 66 9
2 21 32 43 54 45 23 4 66 9 98
3 21 32 43 54 45 23 4 9 66 98
4 21 32 43 45 23 4 9 54 66 98
5 21 32 43 23 4 9 45 54 66 98
6 21 32 23 4 9 43 45 54 66 98
7 21 23 4 9 32 43 45 54 66 98
8 21 4 9 23 32 43 45 54 66 98
9 4 9 21 23 32 43 45 54 66 98
总结:
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
(2)对销售量的排序采用快速排序法。
快速排序
快速排序的基本思想是:
先从数列中取出一个数作为基准数;分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边;再对左右区间重复第二步,直到各区间只有一个数
概括来说为 挖坑填数+分治法
下面随机选取数字举例来进行说明,主要有三个参数,low为区间的开始地址,high为区间的结束地址,X为当前的开始的值
第一步,选取第一个值划分,low=0,high=9,X=21
总结:
1.low =L; high= R; 将基准数挖出形成第一个坑a[low]。
2.High-–由后向前找比它小的数,找到后挖出此数填前一个坑a[low]中。
3.low++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[high]中。
4. 再重复执行2,3二步,直到low==high,将基准数填入a[low]中。
(3)对销售额的排序采用堆排序法。
堆排序
堆排序的基本思想是:
1.将长度为n的待排序的数组进行堆有序化构造成一个大顶堆
2.将根节点与尾节点交换并输出此时的尾节点
3.将剩余的n -1个节点重新进行堆有序化
4.重复步骤2,步骤3直至构造成一个有序序列
假设待排序数组为[20,50,10,30,70,20,80]
构造堆
总结:
在构造有序堆时,我们开始只需要扫描一半的元素(n/2-1 ~ 0)即可,为什么?
因为(n/2-1)~0的节点才有子节点,如图1,n=8,(n/2-1) = 3 即3 2 1 0这个四个节点才有子节点
3.2.3算法思想:
先定义好储存药品信息的顺序表(sequnenlist)
,在从外部文件drug.txt中导入药品清单,其中txt中要设置好间隔及行数
还有题目要求:采用字母和数字混合编号,如:A125。然后建立输出函数show(),读文件函数read(),写文件函数write()。
最后结合各种排序方法进行调用。在快速排序法中,定义函数partition(),在销售量那部分进行快排。在冒号排序法中,定义函数bubbling_sort()和交换函数swap(),两者结合用作单价排序。在堆排序法中,定义函数heapadjust(),head_sort()用作销售额排序。
3.2.4遇到的问题:
(1)在外部文件txt中,一开始设计的行列没有对齐,结果不能读取出来。
(2)在冒号排序法中,一开始直接赋值,需要借助另一个变量进行赋值。3.2.5解决方法
(1)规定外部文件txt的格式,设置好行数和列数,具体格式。
(2)冒号排序法中,定义好另一个变量,利用它来进行交换。
3.3、全部源程序清单
代码清单及主要注释:
源文件下的main.cpp如下:
#define MAXSIZE 100
int N = 0;
typedef struct node /*药品信息的元素定义*/
{
string num; /*药品编号*/
string name; /*药品名称*/
float price; /*药品单价*/
int count; /*销售数量*/
float sale; /*本药品销售额*/
}Datatype;
typedef struct /*存储药品信息的顺序表的定义*/
{
Datatype r[MAXSIZE + 1];
int length;
}Sequnenlist;
Sequnenlist *l = new Sequnenlist;
int line()
{//获取文件中的药品种数
int len = 0;
string str;
ifstream file1("drug.txt");
while (file1)
{
getline(file1, str);//每次读取一行
if (str.length()>4) //长度4是随便写的,代表本行有数据
len++; //记录药品种类数
}
return len;
}
void show()
{//输出
cout << "====序号=====编号=====名称=====单价=====销售量=====销售额====" << endl;
for (int i = 1; i <= N; i++)
cout << " [" << i << "] "
<< setw(7) << l->r[i].num
<< setw(10) << l->r[i].name
<< setw(8) << l->r[i].price
<< setw(9) << l->r[i].count
<< setw(12) << l->r[i].sale
<< endl;
}
void read()
{//读文件
ifstream ofile;
string nu;
string na;
float pr;
int co;
float sa;
ofile.open("drug.txt", ios::in);
if (ofile.is_open())
{
for (int i = 1; i <= N; i++)
{
ofile >> nu >> na >> pr >> co >> sa;
l->r[i].num = nu;
l->r[i].name = na;
l->r[i].price = pr;
l->r[i].count = co;
l->r[i].sale = sa;
if (i == N)
{
cout << "文件导入成功。=^_^=" << endl;
cout << "药品种类数:" << i << endl;
show();
}
}
}
else
cout << "文件打开失败" << endl;
}
void write()
{//写文件
ofstream ifile("drug_1.txt");
for (int i = 1; i <= N; i++)
{
ifile << l->r[i].num << " "
<< l->r[i].name << " "
<< l->r[i].price << " "
<< l->r[i].count << " "
<< l->r[i].sale << endl;
}
show();
cout << "药品全部导出到文件 “drug_1.txt”" << endl;
}
int Partition(int low, int high)//快排
{//一趟比较,返回枢纽所在位置
l->r[0] = l->r[low];//将枢纽key暂存在r[0]
int pivotkey = l->r[0].count;
while (low<high)
{
while (low<high&&l->r[high].count >= pivotkey)
--high;
l->r[low] = l->r[high];//将比枢纽小的移到低端
while (low<high&&l->r[low].count <= pivotkey)
++low;
l->r[high] = l->r[low];//将比枢纽大的移到高端
}
l->r[low] = l->r[0];
return low;//返回枢纽位置
}
void QSort(int low, int high)
{
if (low<high)
{
int pivotloc = Partition(low, high);//将序列一分为二
QSort(low, pivotloc - 1);//对低子表进行递归排序
QSort(pivotloc + 1, high);//对高子表进行递归排序
}
}
void quick_sort()
{//销售量快排
cout << "按销售量从小到大(快排):" << endl << endl;
QSort(1, l->length);//书上276 对顺序表整体排序
show();
}
void Swap(int i, int j)
{//交换第i和第j个药品
l->r[MAXSIZE].count = l->r[i].count;
l->r[MAXSIZE].name = l->r[i].name;
l->r[MAXSIZE].num = l->r[i].num;
l->r[MAXSIZE].price = l->r[i].price;
l->r[MAXSIZE].sale = l->r[i].sale;
l->r[i].count = l->r[j].count;
l->r[i].name = l->r[j].name;
l->r[i].num = l->r[j].num;
l->r[i].price = l->r[j].price;
l->r[i].sale = l->r[j].sale;
l->r[j].count = l->r[MAXSIZE].count;
l->r[j].name = l->r[MAXSIZE].name;
l->r[j].num = l->r[MAXSIZE].num;
l->r[j].price = l->r[MAXSIZE].price;
l->r[j].sale = l->r[MAXSIZE].sale;
}
void bubbling_sort()
{//单价排序冒泡排序法
cout << "按单价从小到大(冒泡排序):" << endl << endl;
for (int i = 1; i <= N - 1; i++)//从第一个开始相邻的两个比较 价格从小到大排序
for (int j = i + 1; j <= N; j++)
if (l->r[i].price>l->r[j].price)
Swap(i, j);
show();
}
void HeapAdjust(int s, int m)
{//堆排序筛选算法
Datatype rc;
rc.count = l->r[s].count;
rc.name = l->r[s].name;
rc.num = l->r[s].num;
rc.price = l->r[s].price;
rc.sale = l->r[s].sale;
for (int j = 2 * s; j <= m; j *= 2)
{//沿key较大的孩子节点向下筛选
if ((j<m) && l->r[j].sale<l->r[j + 1].sale) ++j;
//j为key较大的记录的下标
if (rc.sale >= l->r[j].sale) break;
//rc应插入在位置s上
l->r[s].count = l->r[j].count;
l->r[s].name = l->r[j].name;
l->r[s].num = l->r[j].num;
l->r[s].price = l->r[j].price;
l->r[s].sale = l->r[j].sale;
s = j;
}
l->r[s].count = rc.count;
l->r[s].name = rc.name;
l->r[s].num = rc.num;
l->r[s].price = rc.price;
l->r[s].sale = rc.sale;
}
void Heap_sort()
{//销售额的排序堆排序法
cout << "按销售额从小到大(堆排序):" << endl << endl;
for (int i = l->length / 2; i >= 1; i--)
HeapAdjust(i, l->length);
for (int i = l->length; i>1; i--)
{
Swap(1, i);//将堆顶记录和当前未经排序子序列中
//的最后一个记录交换
HeapAdjust(1, i - 1);//将l->r[1~i-1]重新调整为大顶堆
}
show();
}
void menu()
{//菜单
cout << endl;
cout << " 药品信息管理系统 " << endl;
cout << " ◇ ◇" << endl;
cout << " 1、导入药品信息 " << endl;
cout << " ◇ 2、导出药品信息 ◇" << endl;
cout << " 3、单价排序 " << endl;
cout << " ◇ 4、销售额排序 ◇" << endl;
cout << " 5、销售量排序 " << endl;
cout << " ◇ 6、退出管理系统 ◇" << endl;
cout << endl << endl << "请选择功能:";
}
void exit()
{//退出
cout << endl;
cout << " ◆-------◆---------◆---------◆-------◆" << endl;
cout << endl;
cout << " ◇ 感谢您的使用!=^_^= ◇" << endl;
cout << endl;
cout << " ◆-------◆---------◆---------◆-------◆" << endl;
cout << endl;
}
int main()
{
int n;
system("color 37");
l->length = N = line() - 1;
while (1)
{
system("cls");
menu();
cin >> n;
switch (n)
{
case 1:
{
system("cls");
read();
system("pause");
break;
}
case 2:
{
system("cls");
write();
system("pause");
break;
}
case 3:
{
system("cls");
bubbling_sort();
system("pause");
break;
}
case 4:
{
system("cls");
Heap_sort();
system("pause");
break;
}
case 5:
{
system("cls");
quick_sort();
system("pause");
break;
}
case 6:
{
system("cls");
exit();
return 0;
}
default:
{
cin.clear();
cin.sync();
cout << "输入有误,请重新输入!" << endl;
system("pause");
break;
}
}
}
return 0;
}
3.4、程序运行、测试与分析
运行结果: