#undef UNICODE
#undef _UNICODE
#include <graphics.h> // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
#include <windows.h> //用到了定时函数sleep()
#include <math.h>
#include <string>
#include <iostream>
#include <string.h>
#include <iomanip>
#define PI 3.1416
using namespace std;
int r[3][4]={{30,20,130,60},{170,20,220,60},{260,20,310,60}};//三个按钮的二维数组
float alpha,R,h0,sim_t;//碰撞时的能量损失率,球的半径、初始高度、仿真时间
char s[50],s2[20];
int w[50]={0};
int count;
typedef struct
{
int weight;
int lchild,rchild;
int parent;
}HTNode,*HuffmanTree;
typedef char** HuffmanCode;
void weightHuff();
void InitHuff(HuffmanTree& HT,int *w,int n);
void Select(HuffmanTree &ht,int i,int &s1,int &s2);
void Select(HuffmanTree &ht,int i,int &s1,int &s2);
void CreateHuff(HuffmanTree& HT,int n);
void HuffmanCoding(HuffmanTree& HT,HuffmanCode& HC);
void pushCoding(HuffmanCode& HC);
void deCoding(HuffmanCode& HC);
//按钮判断函数
int button_judge(int x,int y)
{
if(x>r[0][0] && x<r[0][2] && y>r[0][1] && y<r[0][3])return 1;
if(x>r[1][0] && x<r[1][2] && y>r[1][1] && y<r[1][3])return 2;
if(x>r[2][0] && x<r[2][2] && y>r[2][1] && y<r[2][3])return 3;
return 0;
}
//初始化图像
void init_figure()
{
int i;
setrop2(R2_COPYPEN);//当前颜色
setlinecolor(BLACK);
setlinestyle(PS_SOLID);//实线
rectangle(30,100,420,330);//外框线
setlinestyle(PS_DOT);//点线
for(i=30+39;i<420;i+=39)
{
line(i,100,i,330);//竖直辅助线
}
for(i=100+23;i<330;i+=23)
{
line(30,i,420,i);//水平辅助线
}
}
//仿真运行
int simulation()
{
char t[3];//百分值的字符
char *out_text;
float dt = 0.01;//仿真间隔10ms
float dy = 230/h0;//单位纵坐标
long int N = (long int)(sim_t/dt);//迭代次数
float *h=(float*)calloc(N,sizeof(float));//高度
float *v=(float*)calloc(N,sizeof(float));//速度(竖直方向)
long int i;//迭代变量
float process_duty;//进度
RECT r={370,35,400,65};//百分值显示区域的矩形指针
init_figure();//初始化图像网格
setrop2(R2_COPYPEN);//当前颜色
setfillcolor(WHITE);
setlinecolor(WHITE);
fillrectangle(354,19,411,81);//覆盖原进度条区域
setlinestyle(PS_NULL);//无线条
setbkmode(TRANSPARENT);//设置文字填充背景为透明
//计算步骤
h[0]=h0;v[0]=0;
BeginBatchDraw();//开始缓存区
for(i=1;i<N;i++)
{
if(h[i-1]>R)//未发生碰撞
{
v[i]=v[i-1]-9.8*dt;//速度计算
}
else//发生碰撞,动能损失alpha,速度损失alpha的开方
{
v[i]=-sqrt(alpha)*v[i-1];
}
setfillcolor(WHITE);
setlinecolor(WHITE);
fillrectangle(354,19,416,81);//覆盖原进度条区域
h[i]=h[i-1]+v[i]*dt;//高度计算
process_duty = (i+1)/(float)(N);
setlinestyle(PS_SOLID);
putpixel(30+(int)(process_duty*390),330-(int)(h[i]*dy),RED);
setfillcolor(BLUE);
setlinestyle(PS_NULL);
fillpie(355,20,415,80,0,process_duty*2*PI);
setfillcolor(WHITE);
fillcircle(385,50,20);
sprintf(t,"%d",(int)(process_duty*100.0));//整型转换为字符串
out_text = strcat(t,"%");//添加一个百分号
drawtext(out_text,&r,DT_CENTER | DT_VCENTER | DT_SINGLELINE);
Sleep(dt*1000);
FlushBatchDraw();//刷新缓存区
}
EndBatchDraw();//结束缓存区
free(h);
free(v);
return 0;
}
int main()
{
//********************创建界面*******************************
int i,event=0;
char s[30];//输入字符串变量
short win_width,win_height;//定义窗口的宽度和高度
win_width = 480;win_height = 360;
initgraph(win_width,win_height);//初始化窗口(黑屏)
for(i=0;i<256;i+=5)
{
setbkcolor(RGB(i,i,i));//设置背景色,原来默认黑色
cleardevice();//清屏(取决于背景色)
Sleep(30);//延时30ms
}
//********************创建按钮*******************************
RECT R1={r[0][0],r[0][1],r[0][2],r[0][3]};
RECT R2={r[1][0],r[1][1],r[1][2],r[1][3]};
RECT R3={r[2][0],r[2][1],r[2][2],r[2][3]};
LOGFONT f;//字体样式指针
gettextstyle(&f); //获取字体样式
_tcscpy(f.lfFaceName,_T("宋体")); //设置字体为宋体
f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿
settextstyle(&f); // 设置字体样式
settextcolor(BLACK); //BLACK在graphic.h头文件里面被定义为黑色的颜色常量
drawtext("输入参数",&R1,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R1内输入文字,水平居中,垂直居中,单行显示
drawtext("运行",&R2,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R2内输入文字,水平居中,垂直居中,单行显示
drawtext("退出",&R3,DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在矩形区域R3内输入文字,水平居中,垂直居中,单行显示
setlinecolor(BLACK);
rectangle(r[0][0],r[0][1],r[0][2],r[0][3]);
rectangle(r[1][0],r[1][1],r[1][2],r[1][3]);
rectangle(r[2][0],r[2][1],r[2][2],r[2][3]);
//**********************鼠标操作******************************
MOUSEMSG m;//鼠标指针
while(true)
{
m = GetMouseMsg();//获取一条鼠标消息
switch(m.uMsg)
{
//鼠标移动消息
case WM_MOUSEMOVE:
setrop2(R2_XORPEN);
setlinecolor(LIGHTCYAN);//线条颜色为亮青色
setlinestyle(PS_SOLID, 3);//设置画线样式为实现,10磅
setfillcolor(WHITE);//填充颜色为白色
if(button_judge(m.x,m.y)!=0)
{
if(event != button_judge(m.x,m.y))
{
event = button_judge(m.x,m.y);//记录这一次触发的按钮
fillrectangle(r[event-1][0],r[event-1][1],r[event-1][2],r[event-1][3]);//有框填充矩形(X1,Y1,X2,Y2)
}
}
else
{
if(event!=0)//上次触发的按钮未被修正为原来的颜色
{
fillrectangle(r[event-1][0],r[event-1][1],r[event-1][2],r[event-1][3]);//两次同或为原来颜色
event = 0;
}
}
break;
//左键按下消息
case WM_LBUTTONDOWN:
setrop2(R2_NOTXORPEN);//二元光栅——NOT(屏幕颜色 XOR 当前颜色)
for(i=0;i<=10;i++)
{
setlinecolor(RGB(25*i,25*i,25*i));//设置圆颜色
circle(m.x,m.y,2*i);
Sleep(20);//停顿30ms
circle(m.x,m.y,2*i);//抹去刚刚画的圆
}
//按照按钮判断左键单击后的操作
switch(button_judge(m.x,m.y))
{
//复原按钮原型
case 1:
InputBox(s,30,"请输入碰撞时的能量损失率、球的半径、初始高度、仿真时间");
sscanf(s,"%f%f%f%f",&alpha,&R,&h0,&sim_t);//将输入字符串依次扫描到全局变量里面
FlushMouseMsgBuffer();//单击事件后清空鼠标消息
break;
case 2:
simulation();//仿真运行
FlushMouseMsgBuffer();//单击事件后清空鼠标消息
break;
case 3:
closegraph();//关闭绘图环境
exit(0);//正常退出
default:
FlushMouseMsgBuffer();//单击事件后清空鼠标消息
//printf("\r\n(%d,%d)",m.x,m.y);//打印鼠标坐标,方便调试时确定区域
break;
}
break;
}
}
return 0;
}
void weightHuff()//计算权值、找到不重复的字符数组并计数
{
int i=0;
cout<<"请输入需要编码的字符串"<<endl;
cin>>s;
while(s[i]!='\0')
{
int j;
for(j=0;j<count;j++)
{
if(s[i]==s2[j])//查看当前字符出现过
{
w[j]++;//s2中对应的权值也加1
i++;//查找s字符串的下一个字符
break;
}
}
if(j==count)//把不同字符数组遍历完了
{
s2[count]=s[i];//如果j==count,说明s[i]没有出现过,就放到s2中
w[count]++; //s2中对应的权值也加1
i++;
count++;//统计目前有多少个不同的字符
}
}
}
void InitHuff(HuffmanTree& HT,int *w,int n)//初始化哈夫曼树
{
int i,m;
if(n<=1)
{
return;
}
m=2*n-1;
HT = new HTNode[m+1];
for(i=1;i<=n;i++)//初始化叶子结点
{
HT[i].weight=w[i-1];
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(i=n+1;i<=m;i++)//初始化非叶子结点
{
HT[i].weight=0;
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
}
void Select(HuffmanTree &ht,int i,int &s1,int &s2)//选择两个最小权值
{
int min1=2147483647,min2=2147483647,j;
for(j=1;j<=i;j++)
{
if(ht[j].parent==0&&ht[j].weight<min1)
{
min1=ht[j].weight;
s1=j;
}
}
for(j=1;j<=i;j++)
{
if(ht[j].parent==0&&j!=s1&&ht[j].weight<min2)
{
min2=ht[j].weight;
s2=j;
}
}
}
void CreateHuff(HuffmanTree& HT,int n)
{
int s1,s2,i,m;
m=2*n-1;
cout<<"\n哈弗曼树的构造过程如下:"<<endl;
for(i=n+1;i<=m;i++)//构造哈夫曼树
{
Select(HT,i-1,s1,s2);
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;
}
}
void HuffmanCoding(HuffmanTree& HT,HuffmanCode& HC)//哈夫曼编码
{
int i,start,j,f;
char *cd;
weightHuff();
InitHuff(HT,w,count);
CreateHuff(HT,count);
HC = new char*[count+1];//存放每个叶子结点的编码
cd = new char[count];//用于临时存放编码
cd[count-1]='\0';
//遍历每一个叶子结点1~count
//对于每一个叶子结点都要判断它是他父亲结点的左孩子还是右孩子
//然后从他的父亲结点要继续向上遍历,即判断它父亲结点是其父亲结点的左孩子还是右孩子
for(i=1;i<=count;i++)
{
start=count-1;
for(j=i,f=HT[i].parent;f!=0;j=f,f=HT[f].parent)//向上回溯
{
if(HT[f].lchild==j)//如果该叶子结点是他的父亲结点的左孩子
cd[--start]='0';
else//该结点是右孩子
cd[--start]='1';
//然后再查找该结点的父亲结点是其父亲结点的左孩子还是右孩子,一直到根结点结束
}
HC[i]=new char[count-start];
strcpy(HC[i],&cd[start]);
}
cout<<"字符\t\t 频数\t\t 编码"<<endl;
for(i=0;i<count;i++)
{
cout<<s2[i]<<"\t\t"<<w[i]<<"\t\t"<<HC[i+1]<<endl;
}
}
void pushCoding(HuffmanCode& HC)//编码函数
{
int i;
string s1;
cout << "输入要编码的英文:" << endl;
cin >> s1;
cout << "编码:" << endl;
for (i = 0; i < s1.length(); i++)
{
for (int j = 0; j < count; j++)
{
if (s1[i] == s2[j])
{
cout << HC[j + 1];
break;
}
}
}
cout << endl;
}
void deCoding(HuffmanCode& HC)//解码函数
{
string s3;
int i=0,j,k,l;
char h[10];
cout<<"请输入哈夫曼编码:"<<endl;
cin>>s3;
while(i<s3.length())//遍历属于的哈夫曼编码
{
//将s3字符串的前一段分别与s2中的每个字符的编码做比较
//直到在s2找到与这一段编码相同为止
//在截取s3的下一段与s2中的字符编码作比较...
for(j=1;j<=count;j++)
{
l=i;//ly用于存放i
for(k=0;k<strlen(HC[j]);k++)
{
h[k]=s3[l++];
}
h[k]='\0';
if(strcmp(HC[j],h)==0)
{
cout<<s2[j-1];
i=i+strlen(HC[j]);
break;
}
}
}
}
哈夫曼编码
最新推荐文章于 2022-12-23 17:32:00 发布