转眼间,2012年已经过去一半了,回想一下自己做了些什么呢?可保存的画图板—>弹球游戏 —> 连连看 —> 黄金矿工 —>哈弗曼压缩—>
小学期开始学通信方面的内容,做了简单的群聊
画图板的保存打开:原来画图板的基础上添加了一个FileUtil类
package 画图板可保存重绘;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileUtil implements Config {
/**
* 将图片数据保存到指定的位置
*
* @param path
* : 要保存数据的位置
*/
public static void saveFile(String path) {
try {
// 创建文件输出流对象
FileOutputStream fos = new FileOutputStream(path);
// 将输出流包装成可写基本类型的数据流
DataOutputStream dos = new DataOutputStream(fos);
// 写图片的高度和宽度
dos.writeInt(DrawListener.data.length);
dos.writeInt(DrawListener.data[0].length);
// 遍历二维数组,写数据
for (int i = 0; i < DrawListener.data.length; i++) {
for (int j = 0; j < DrawListener.data[i].length; j++) {
int num = DrawListener.data[i][j];
// 写数据
dos.writeInt(num);
}
}
//将输出流清空
dos.flush();
//将输出流关闭
fos.close();
} catch (Exception ef) {
ef.printStackTrace();
}
}
/**
* 读取文件中的数据
*
* @param path
* 要读取的文件
* @return 将读取到的数据作为二位数组返回
*/
public static int[][] readFile(String path) {
// 创建文件输入流
try {
//创建文件输入流对象
FileInputStream fis = new FileInputStream(path);
//将文件输入流包装成可写基本类型的数据流
DataInputStream dis = new DataInputStream(fis);
// 读取高度和宽度
int height = dis.readInt();
int width = dis.readInt();
// 定义二维数组
int[][] readData = new int[height][width];
//循环读取每个像素点
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// 将数据读入数组
readData[i][j] = dis.readInt();
}
}
//关闭输入流
fis.close();
//返回二维数组
return readData;
} catch (Exception ef) {
ef.printStackTrace();
}
return null;
}
}
在界面上保存打开的按钮,并添加监听器
在DrawListener中添加了将drawPanel在屏幕上占据的区域的像素点保存成数组
// 调用画图形的方法
shape.draw(g);
// 每绘制一次就将整个drawPanel区域内的所有像素点保存起来
// 得到事件源对象
Object obj = e.getSource();
JPanel drawPanel = (JPanel) obj;
// 得到drawPanel的左上角的点
Point point = drawPanel.getLocationOnScreen();
// 得到drawPanel的大小
Dimension dim = drawPanel.getPreferredSize();
// 创建矩形区域对象,刚好截取drawPanel在屏幕上所占据的区域
Rectangle rect = new Rectangle(point, dim);
// 从屏幕上获取像素区域,得到一个缓存区的图像对象
BufferedImage img = robot.createScreenCapture(rect);
data = new int[dim.height][dim.width];
// 将缓存区的图像对象中的每一个像素的颜色保存起来
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
// 得到每个点的颜色(用数字表示的颜色),存入二维数组
data[i][j] = img.getRGB(j, i);
}
}
连连看之囧事连连
这个游戏设计我认为界面比较可爱,代码部分没有新颖之处,剩余时间用了简单的线程来控制,代码量主要集中在对相同图片是否可以相互消掉的判断上,就是一些逻辑算法,自己的逻辑要清楚,否则会出现错误判断。
界面展示:
线程游戏—>黄金矿工
这是一个多线程游戏,仿照黄金矿工游戏进行模仿设计的
这个游戏实现经过了比较长的时间
用到了三个线程控制,每个线程只能操作自己的对象,不能对其他类的对象进行操作。
其中比较好的部分是运用rotate();方法对钩子进行摆动控制
以及一些boolean型变量的运用,使得各个阶段可以有效控制
钩子线程类
package 黄金矿工;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
/**
* 钩子的线程
*
* @author Administrator
*
*/
public class HookThread extends Thread {
public static boolean isCatch = false;
public static boolean isWrite = false;
double xx, yy;// 金块或石头的坐标点
double x, y;// 钩子的坐标点
double xc, yc;// 钩子,金块石头每次移动的横纵坐标改变量
double arc = Math.PI / 4;// 钩子的角度.
double arcx = Math.PI / 16;
ImageIcon icon;
static int money = 0;// 金钱数
static int gameTime = 60;// 倒计时
public static int biggolden = 500;
public static int middlegolden = 200;
public static int smallgolden = 50;
public static int stone = 25;
public static int pocket = 250;
public static int num;
public boolean isDown = true;
boolean isStop = false;
public HookThread(ImageIcon icon, int x, int y) {
this.x = x;
this.y = y;
this.icon = icon;
}
public void run() {
tocatch();
// 设置一个布尔型变量,当时间为0时,toCatch()结束,开始执行下面的语句
if (HookThread.money < 1500) {
JOptionPane.showMessageDialog(null, "GAME OVER 未达到目标分数o(╯□╰)o");
isStop = true;
}
if (HookThread.money >= 1500) {
JOptionPane.showMessageDialog(null, "达到目标分数~~顺利完成任务O(∩_∩)O");
isStop = true;
}
}
// 钩子向下运动
public void tocatch() {
long time = 10;
xc = -Math.sin(arc);
yc = Math.abs(Math.cos(arc));
while (!isStop) {
if (gameTime == 0) {
isStop = true;
}
if (isCatch) {
if (isDown) {
// 钩子到达边界抓空
if (x < 4 || x > 625 || y > 440) {
System.out.println("碰边了");
xc = -xc;
yc = -yc;
num = -1;
isDown = false;
}
// 如果抓到金矿,则返回
if (isDown) {
// 鉤子向下運動時,遍历一遍金矿和石头
for (int i = 0; i < GameUI.gases.size(); i++) {
GoldenAndStoneThread gs = GameUI.gases.get(i);
// 钩子在运动的过程中,是否可以抓取到东西
// 可以抓取则将钩子的运动位移量赋给金块或石头
if (i == 1 || i == 5 || i == 6 || i == 10) {// biggolden
double a = x + 13 - gs.xx;
double b = Math.abs(gs.yy + 5 - y);
if (a > 6 && a < 88 && b < 5) {
xc = -xc;
yc = -yc;
gs.xxc = xc;
gs.yyc = yc;
num = i;
System.out.println("1,5,6,10");
isDown = false;
break;
}
}
if (i == 3 || i == 7 || i == 8 || i == 0 || i == 11) {// middllegolden
// stone
double c = x + 13 - gs.xx;
double d = Math.abs(gs.yy + 5 - y);
if (c > 1 && c < 27 && d < 8) {
xc = -xc;
yc = -yc;
gs.xxc = xc;
gs.yyc = yc;
num = i;
System.out.println("3,7,8,0,11");
isDown = false;
break;
}
}
if (i == 2 || i == 4) {// middllegolden
double e = x + 13 - gs.xx;
double f = Math.abs(gs.yy + 5 - y);
if (e > 0 && e < 22 && f < 5) {
xc = -xc;
yc = -yc;
gs.xxc = xc;
gs.yyc = yc;
num = i;
System.out.println("2,4");
isDown = false;
break;
}
}
if (i == 9) {// stone
double g = x + 13 - gs.xx;
double h = Math.abs(gs.yy + 5 - y);
if (g > 0 && g < 57 && h < 5) {
xc = -xc;
yc = -yc;
gs.xxc = xc;
gs.yyc = yc;
num = i;
System.out.println("9");
isDown = false;
break;
}
}
}
}
}
if (!isDown) {
// 返回顶部时加分,金块消失,钩子 开始旋转
if (y < 65) {
// 判断金块石头的钱数,响应加分
HookThread.isCatch();
System.out.println(num);
if (num != -1) {
GameUI.gases.remove(num);
}
// 改变移动变量,使钩子可以继续伸出去
// 加分
if (num == 0) {// 1
money += pocket;
} else if (num == 1) {// 5
money += biggolden;
} else if (num == 2) {// 4
money += smallgolden;
} else if (num == 3) {// 3
money += middlegolden;
} else if (num == 4) {// 4
money += smallgolden;
} else if (num == 5) {// 5
money += biggolden;
} else if (num == 6) {// 5
money += biggolden;
} else if (num == 7) {// 3
money += middlegolden;
} else if (num == 8) {// 2
money += stone;
} else if (num == 9) {// 6
money += stone;
} else if (num == 10) {// 5
money += biggolden;
} else if (num == 11) {// 1
money += pocket;
} else if (num == 12) {
}
isDown = true;
}
}
// 钩子移动
x += xc;
y += yc;
time = 10;
} else {// 钩子旋转
arc += arcx;
xc = -Math.sin(arc);
yc = Math.abs(Math.cos(arc));
if (arc > Math.PI / 4) {
arcx = -arcx;
}
if (arc < -Math.PI / 4) {
arcx = -arcx;
}
time = 100;
}
try {
Thread.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 钩子抓东西时停止转动恢復轉動的方法
*/
public static void isCatch() {
// TODO Auto-generated method stub
isCatch = !isCatch;
}
}
金块石头线程类
package 黄金矿工;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.ImageIcon;
/**
* 金块与石头的线程
*/
public class GoldenAndStoneThread extends Thread {
double xx, yy;// 金块与石头的坐标点
double xxc = 0, yyc = 0;// 金块与石头的位移量
ImageIcon icon;
int width,height;//图片的高宽
public static Random random = new Random();
public static ArrayList<GoldenAndStoneThread> gases = new ArrayList<GoldenAndStoneThread>();
public GoldenAndStoneThread(ImageIcon icon,int xx,int yy){
this.xx=xx;
this.yy=yy;
this.icon=icon;
this.width = icon.getIconWidth();
this.height = icon.getIconHeight();
}
public void run() {
go();
}
public void go() {
while (true) {
xx+=xxc;
yy+=yyc;
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
时间线程类
package 黄金矿工;
/**
* 时间线程
* @author Administrator
*
*/
public class TimeThread extends Thread {
public TimeThread(){
}
public void run() {
// TODO Auto-generated method stub
while(HookThread.gameTime!=0){
HookThread.gameTime--;//减一秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
哈弗曼压缩&解压
实现了压缩和解压的功能,但是经过检测,他的效率好低啊~~不过简单测试可以保证它压缩和解压是正确的
过程中最大功劳应该是Test类,每做一步都要对其进行检测,否则一股脑做到最后结果不正确,都不晓得自己是哪一步出错了。。。
压缩步骤:
1.读取文件,统计每个字节出现的个数,存入到一个int[256]数组中
如:int[97]=1;(a出现一次)
int[98]=2;(b出现两次)
2.TreeNode{
byte b;//字节(a)
int count;//权值(1)
String str="";//左0右1
}
将数组中的次数作为权值构造节点,将节点放入优先队列
3.将字节出现的次数作为权值构造哈弗曼树
4.找到所有的叶子节点,得到每个叶子节点的哈弗曼01编码,将01编码存入到String[256]中(码表)
如:String[97]="110"
5.读取文件,将每个字节用相应的01编码表示,得到一个完整长01字符串s
如:s="11011111110101010000"
6.将字符串每八位转为一个整数,作为字节存入到byte[]b=new byte[length]中(length的大小由是否能被8整除决定)
length=20/8+2
最后一位存储补0的个数
倒数第二位存储除8后剩余的编码
7.将码表和byte数组写入到压缩文件中
解压步骤反向进行
压缩和解压共同的TreeNode类
public class TreeNode {
Object obj;//节点中存储的元素
int value;//权值
String str;//左孩子0右孩子1
TreeNode parent;//父节点
TreeNode leftChild;//左孩子节点
TreeNode rightChild;//右孩子节点
/**
* 构造函数
* @param obj
* @param value
*/
public TreeNode(Object obj,int value,String str){
this.obj=obj;
this.value=value;
this.str=str="";
}
压缩Compress类
package 哈弗曼压缩;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* 压缩文件类
*
* @author Administrator
*
*/
public class Compress {
// 创建文件输出流对象
FileOutputStream fos;
/**
* 1.统计指定文件中每个字节出现的次数
*
* @param path
*/
public int[] count(String path) {
int[] byteCount = new int[255];
try {
// 创建文件输出流对象
FileInputStream fis = new FileInputStream(path);
// 将输出流包装成可写的基本类型的流
DataInputStream dis = new DataInputStream(fis);
try {
while (dis.available() > 0) {
int i = dis.read();
byteCount[i]++;
// System.out.println(byteCount[i]);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return byteCount;
}
/**
* 将数组中的次数作为权值构造节点,将节点放入优先队列
*
* @param arr
* @return
*/
public PriorityQueue<TreeNode> array2Queue(int[] byteCount) {
// 创建排序队列对象,需要自己指定比较器
PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(11,
new MyComparator());
for (int i = 0; i < byteCount.length; i++) {
if (byteCount[i] != 0) {
// 循环创建节点对象
TreeNode node = new TreeNode(i, byteCount[i], "");
queue.add(node);
}
}
return queue;
}
/**
* 根据节点优先队列构造哈弗曼树
*
* @param queue
* @return
*/
public TreeNode creatHfmTree(PriorityQueue<TreeNode> queue) {
while (queue.size() > 1) {
// 取两个权值较小的节点
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();
// 根据两个节点的权值和构造一个根节点
TreeNode root = new TreeNode(null, (node1.value + node2.value), "");
// 建立孩子节点与父节点的关系
root.leftChild = node1;
node1.str = "0";
root.rightChild = node2;
node2.str = "1";
node1.parent = root;
node2.parent = root;
// 将该根节点存入队列中
queue.add(root);
}
// 如果循环结束后,证明队列中还有一个节点,该节点为根节点
TreeNode root = queue.poll();
root.str = "";
return root;
}
/**
* 得到每一个叶子节点的哈弗曼编码
*
* @param child
* @param s
* @return
*/
public String[] getByteCode(TreeNode root, String s) {
// 码表
String[] SaveString = new String[256];
// 调用得到编码的方法
getCode(SaveString, root, s);
// 打印码表
for (int i = 0; i < SaveString.length; i++)
System.out.println(i + "<>" + SaveString[i]);
return SaveString;
}
// 从下向上找
private void getCode(String[] SaveString, TreeNode root, String s) {
if (root != null) {
if (root.obj != null) {
int index = (Integer) root.obj;
SaveString[index] = s;
}
TreeNode left = root.leftChild;
if (left != null)
getCode(SaveString, left,s+left.str);
TreeNode right = root.rightChild;
if (right != null)
getCode(SaveString, right, s+ right.str);
}
}
/*
* 读取文件,将文件中的内容转化为01字符串
*/
public String change(String SaveString[], String path) {
String string = "";
try {
// 创建文件输出流对象
FileInputStream fis = new FileInputStream(path);
// 将输出流包装成可写的基本类型的流
DataInputStream dis = new DataInputStream(fis);
try {
while (dis.available() > 0) {
int i = dis.read();
String a = SaveString[i];
string = string + a;
// System.out.println(byteCount[i]);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return string;
}
/**
* 将一个八位的字符串转成一个整数
*
* @param s
* @return
*/
public byte changeString(String s) {
return (byte) (((byte) s.charAt(0) - 48) * 128
+ ((byte) s.charAt(1) - 48) * 64 + ((byte) s.charAt(2) - 48)
* 32 + ((byte) s.charAt(3) - 48) * 16
+ ((byte) s.charAt(4) - 48) * 8 + ((byte) s.charAt(5) - 48) * 4
+ ((byte) s.charAt(6) - 48) * 2 + ((byte) s.charAt(7) - 48));
}
/**
* 将字符串每八位转为一个整数后,作为字节存入到byte[]b=new byte[length]中
* @param string
* @return
*/
public byte[] StringToByteArray(String string) {
// 得到01字符串的长度
char[] c = string.toCharArray();// 将字节串str转化为字符数组c
int len = c.length;// 字符串字符的个数
int more = len % 8;// 余数
int length = len / 8;// 商
byte[] b;
String x = "";// 每八个01的编码
// 如果可以被8整除
if (more == 0) {
b = new byte[length+1];
for (int i = 0; i < length; i++) {
for (int j = i * 8; j < (i + 1) * 8; j++) {
x = x + c[j];
}
System.out.println("===================" + x);
b[i] = changeString(x);
x="";
}
b[length]=0;//补了零个0;
} else {//不可以被8整除
b = new byte[length + 2];
for(int i=0;i<length;i++){
for(int j=i*8;j<(i+1)*8;j++){
x=x+c[j];
}
System.out.println(">>>>>>>>>>>>>>>>>>>>"+x);
b[i]=changeString(x);
x="";
}
for(int a=0;a<more;a++){
x=x+c[length*8+a];
}
for(int d=more;d<8;d++){
x=x+"0";
}
System.out.println(">>>==========>>>>>>>"+x);
b[length]=changeString(x);
b[length+1]=(byte)(8-more);
}
return b;
}
/**
* 将码表和byte数组写入到压缩文件中 SaveString 和b
* @param path
* @param SaveString
* @param b
*/
public void writeIn(String path,String [] SaveString,byte[] b,TreeNode root) {
try {
// 创建文件输出流对象
FileOutputStream fos = new FileOutputStream(path);
// 将输出流包装成可写基本类型的数据流
DataOutputStream dos = new DataOutputStream(fos);
// //写入哈弗曼树
// printTree(root);
// dos.writeBytes(root);
//写入SaveString有多少字节不是空的
int num = 0;
for(int i=0;i<255;i++){
if(SaveString[i]!=null){
num++;
}
}
System.out.println("_____________________________________________________________________"+num);
dos.writeInt(num);
//先写入SaveString
for(int i=0;i<255;i++){
if(SaveString[i]!=null){
System.out.println("OK"+SaveString[i].length());
int l=SaveString[i].length();
//写入97,3,110
dos.writeByte(i);
dos.writeInt(l);
dos.writeBytes(SaveString[i]);
System.out.println("HAHA"+i+" "+l+" "+SaveString[i]);
}
}
//写入 b
for(int j=0;j<b.length;j++){
dos.writeByte(b[j]);
System.out.println("GOGO"+b[j]);
}
//将输出流清空
dos.flush();
//将输出流关闭
fos.close();
} catch (Exception ef) {
ef.printStackTrace();
}
}
/**
* 实现的比较器类
*
* @author Administrator
*
*/
class MyComparator implements Comparator<TreeNode> {
@Override
public int compare(TreeNode o1, TreeNode o2) {
// TODO Auto-generated method stub
return o1.value - o2.value;
}
}
/**
* 遍历树的方法(先序遍历)
*
* @param root
*/
public void printTree(TreeNode root) {
// 只要数不空就执行
if (root != null) {
// 得到根节点的元素
int va = root.value;
System.out.println(va + "<>" + root.str);
// 得到根节点的左孩子节点
TreeNode leftNode = root.leftChild;
// 递归左树
printTree(leftNode);
// 得到根节点的右孩子节点
TreeNode rightNode = root.rightChild;
// 递归右树
printTree(rightNode);
}
}
}
解压Decompress类
package Decompress解压1;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
public class Decompress {
/**
* 读取byte[] b
*/
public byte[] readBytes(String path) {
byte[] b = null;
try {
// 创建文件输出流对象
FileInputStream fis = new FileInputStream(path);
// 将输出流包装成可写的基本类型的流
DataInputStream dis = new DataInputStream(fis);
int lenZ = dis.available();
System.out.println();
// 先跳过256个Int
dis.skip(256 * 4);
int len = dis.available();
b = new byte[len];
for (int i = 0; i < b.length; i++) {
b[i] = dis.readByte();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return b;
}
/**
* 读取码表
*
* @param path
* @return
*/
public int[] readCount(String path) {
int[] byteCount = new int[256];
try {
// 创建文件输出流对象
FileInputStream fis = new FileInputStream(path);
// 将输出流包装成可写的基本类型的流
DataInputStream dis = new DataInputStream(fis);
// System.out.println("WOW");
for (int i = 0; i < 256; i++) {
byteCount[i] = dis.readInt();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return byteCount;
}
/**
* 将8位10字符串前面缺0的补上0
*
* @param str
* @return
*/
public String addZero(String str) {
int strLen = str.length();
int zeroNum;
if (strLen < 8) {// 若字符串长度小于8则补0
zeroNum = 8 - strLen;
for (int i = 0; i < zeroNum; i++) {
str = "0" + str;
}
}
return str;
}
/**
* 将整型数组还原成之前的10串,即文件内容的哈夫曼编码
*
* @param n
* @return
*/
public String InttoBinaryString(byte[] bs) {
String BinaryStr = "";
for (int i = 0; i < bs.length - 1; i++) {
String str = Integer.toBinaryString(bs[i]);
if (str.length() < 8) {
for (int j = 0; j < 8 - str.length(); j++) {
str = "0" + str;
}
} else if (str.length() > 8) {
str=str.substring(str.length()-8);
}
BinaryStr = BinaryStr + str;
}
int BinaryStrLen = BinaryStr.length();// 得到为减0前的字符串大小
byte zeroSub = bs[bs.length - 1];// 之前在末尾补0的个数,现在减去
System.out.println(bs[bs.length - 1]);
BinaryStr = BinaryStr.substring(0, BinaryStrLen - zeroSub);
System.out.println("<BinaryStr>"+BinaryStr);
return BinaryStr;
}
/**
*
* @param path
* 解压的路径
* @param BinaryStr
* 01串
* @param SaveString
* 码表
*/
public void writeIn(String path, String BinaryStr,
HashMap<String, Integer> SaveString) {
// 创建文件输出流对象
try {
FileOutputStream fos = new FileOutputStream(path);
DataOutputStream dos = new DataOutputStream(fos);
String str = "";
int index = 0;
// System.out.println(BinaryStr);
while (index < BinaryStr.length()) {
str += BinaryStr.charAt(index);
// 如果码表中包含该01串
if (SaveString.containsKey(str)) {
// System.out.println(">>"+str);
// 就得到01传对应的字节
int b = SaveString.get(str);
dos.write(b);
str = "";
}
index++;
}
// 将输出流清空
dos.flush();
// 将输出流关闭
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 将输出流包装成可写基本类型的数据流
}
/**
* 将数组中的次数作为权值构造节点,将节点放入优先队列
*
* @param arr
* @return
*/
public PriorityQueue<TreeNode> array2Queue(int[] byteCount) {
// 创建排序队列对象,需要自己指定比较器
PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(11,
new MyComparator());
for (int i = 0; i < byteCount.length; i++) {
if (byteCount[i] != 0) {
// 循环创建节点对象
TreeNode node = new TreeNode(i, byteCount[i], "");
queue.add(node);
}
}
return queue;
}
/**
* 根据节点优先队列构造哈弗曼树
*
* @param queue
* @return
*/
public TreeNode creatHfmTree(PriorityQueue<TreeNode> queue) {
while (queue.size() > 1) {
// 取两个权值较小的节点
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();
// 根据两个节点的权值和构造一个根节点
TreeNode root = new TreeNode(null, (node1.value + node2.value), "");
// 建立孩子节点与父节点的关系
root.leftChild = node1;
node1.str = "0";
root.rightChild = node2;
node2.str = "1";
node1.parent = root;
node2.parent = root;
// 将该根节点存入队列中
queue.add(root);
}
// 如果循环结束后,证明队列中还有一个节点,该节点为根节点
TreeNode root = queue.poll();
root.str = "";
return root;
}
/**
* 得到每一个叶子节点的哈弗曼编码
*
* @param child
* @param s
* @return
*/
public HashMap<String, Integer> getByteCode(TreeNode root, String s) {
// 码表
HashMap<String, Integer> SaveString = new HashMap<String, Integer>();
// 调用得到编码的方法
getCode(SaveString, root, s);
return SaveString;
}
// 从下向上找
private void getCode(HashMap<String, Integer> SaveString, TreeNode root,
String s) {
if (root != null) {
if (root.obj != null) {
int index = (Integer) root.obj;
SaveString.put(s, index);
}
TreeNode left = root.leftChild;
if (left != null)
getCode(SaveString, left, s + left.str);
TreeNode right = root.rightChild;
if (right != null)
getCode(SaveString, right, s + right.str);
}
}
/**
* 实现的比较器类
*
* @author Administrator
*
*/
class MyComparator implements Comparator<TreeNode> {
@Override
public int compare(TreeNode o1, TreeNode o2) {
// TODO Auto-generated method stub
return o1.value - o2.value;
}
}
/**
* 遍历树的方法(先序遍历)
*
* @param root
*/
public void printTree(TreeNode root) {
// 只要数不空就执行
if (root != null) {
// 得到根节点的元素
int va = root.value;
System.out.println(va + "<>" + root.str);
// 得到根节点的左孩子节点
TreeNode leftNode = root.leftChild;
// 递归左树
printTree(leftNode);
// 得到根节点的右孩子节点
TreeNode rightNode = root.rightChild;
// 递归右树
printTree(rightNode);
}
}
}
通信群聊
要分清客户端与服务器之间的关系,以及各自方法的使用
ChatServer类
package tx0630服务器2;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class ChatServer {
// 保存处理进处连结的线程对象
public static ArrayList<ServerThread> cts = new ArrayList<ServerThread>();
/**
* 在指定端口上创建服务器
*
* @param port
* 服务器所在的端口号
*/
public void setServer(int port) {
try {
// 创建一个服务器对象
ServerSocket s = new ServerSocket(port);
while (true) {
// 等待连结进入
Socket chatClient = s.accept();
// 创建线程对象,去处理
ServerThread ct = new ServerThread(chatClient);
ct.start();
cts.add(ct);// 保存到队列中
}
} catch (Exception ef) {
ef.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
ChatServer ss = new ChatServer();
ss.setServer(1000);
}
}
ServerThread类
package tx0630服务器2;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
//处理进入的连结对象的线程,:每进入一个连结,就创建一个处理线程对象
//每个客户端,在服务器端,都由一个处理线程对象代表
public class ServerThread extends Thread {
public static native long currentTimeMillis();
private Socket socket;
private OutputStream ous;
public ServerThread(Socket socket) {
try {
this.socket = socket;
ous = socket.getOutputStream();
} catch (Exception ef) {
ef.printStackTrace();
}
}
// 给我所代表的客户机发送一条消息
public void sendMsg2Me(String msg) {
try {
msg += "\r\n";
ous.write(msg.getBytes());
} catch (Exception ef) {
ef.printStackTrace();
}
}
// 服务器统计在线人数
public int Count() {
int num = ChatServer.cts.size();
return num;
}
public void run() {
// 处理通信过程:
processChat(this.socket);
}
/**
* 处理进入的客户端连结对象:处理通信流程
*
* @param client
*/
private void processChat(Socket chatClient) {
try {
// 得取输入输出流,读写数据
InputStream ins = chatClient.getInputStream();
// 通信流程实现阶段:最简流程
String msg = "hello!欢迎进入QQChat";// 发给连结上来的客户机
sendMsg2Me(msg);
int num = Count();
for (int i = 0; i < ChatServer.cts.size(); i++) {
ServerThread ct = ChatServer.cts.get(i);
ct.sendMsg2Me("当前在线人数" + num);
}
String inMsg = "";
while (!"*".equals(inMsg)) {
inMsg = readMsg(ins);
System.out.println("recive Msg:" + inMsg);
// 遍历cts中的每一个对象,发送消息
for (int i = 0; i < ChatServer.cts.size(); i++) {
ServerThread ct = ChatServer.cts.get(i);
Date d = new Date();
// 在默认时区下输出日期和时间值
System.out.println(d);
ct.sendMsg2Me(d + inMsg);
}
if(inMsg=="over"){
msg = "有人要下线了,通信结束!";// 发给连结上来的客户机
sendMsg2Me(msg);
ins.close();
ous.close();
chatClient.close();
}
}
} catch (Exception ef) {
ef.printStackTrace();
}
}
/**
* 从输入流上读取字节,直到读到以*字节结尾的,将读到的字节转为字符串返回
*
* @param ins
* :读取的输入流对象
* @return 读到的字符串
*/
private String readMsg(InputStream ins) {
try {
// 读取:
int t = ins.read();
ArrayList<Byte> ds = new ArrayList();
while (t != '~') {
System.out.println("读取的字节是: " + t);
ds.add((byte) t);
t = ins.read();
}
// 将前面收到的字节,都转成一个字符串:
byte[] dd = new byte[ds.size()];
for (int i = 0; i < dd.length; i++) {
dd[i] = ds.get(i);
}
// 转为字符串
String inMsg = new String(dd);
return inMsg;
} catch (Exception ef) {
ef.printStackTrace();
System.out.println("从输入流上读取字符串时出错!");
}
return "error";
}
}
客户机
MainClientUI()界面设计代码略
package tx0630客户机2;
import java.awt.TextArea;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端
*/
public class NetClient extends Thread {
private String UserName;
private String serverIP;//服务器IP
private int port;//服务器端口
private OutputStream out;//到服务器的输出流
private BufferedReader brd;//到服务器的输入流,以\r\n结尾
private TextArea jta_recived;//从界面上传来的显示接收到的消息的组件
/**
* 构造函数,传入服务器的IP和端口和显示组件
* @param serverIP
* @param port
* @param jta_input
*/
public NetClient(String UserName,String serverIP,int port,TextArea jta_input){
this.UserName=UserName;
this.serverIP=serverIP;
this.port=port;
this.jta_recived=jta_input;
}
public String getUserName(){
return UserName;
}
/**
* 连接并判断连接服务器是否成功
* @return
*/
public boolean conn2Server(){
try{
//创建一个服务端的SOCKET对象
Socket client=new Socket(this.serverIP,this.port);
//获取输入输出流
InputStream ins=client.getInputStream();
brd=new BufferedReader(new InputStreamReader(ins));
out=client.getOutputStream();
return true;
}catch(Exception ef){
ef.printStackTrace();
}
return false;
}
/**
* 注册服务器
*/
public boolean registerServer(String name,String pwd){
try{
//发送登陆
out.write("register\r\n".getBytes());
//发送用户名
name+="\r\n";
out.write(name.getBytes());
out.flush();
//发送密码
pwd+="\r\n";
out.write(pwd.getBytes());
out.flush();
String register=brd.readLine();
if(register.equals("false")){
return false;
}else{
return true;
}
}catch(Exception ef){
ef.printStackTrace();
}
return false;
}
/**
* 登陆服务器
* @param name
* @param pwd
* @return
*/
public boolean loginServer(String name,String pwd){
try{
//发送登陆
out.write("login\r\n".getBytes());
//发送用户名
name+="\r\n";
out.write(name.getBytes());
out.flush();
//发送密码
pwd+="\r\n";
out.write(pwd.getBytes());
out.flush();
String login=brd.readLine();
if(login.equals("false")){
return false;
}else{
return true;
}
}catch(Exception ef){
ef.printStackTrace();
}
return false;
}
/**
* 找回密码
*/
public String backpwd(String name){
try{
//发送登陆
out.write("backpwd\r\n".getBytes());
//发送用户名
name+="\r\n";
out.write(name.getBytes());
out.flush();
String backpwd=brd.readLine();
return backpwd;
}catch(Exception ef){
ef.printStackTrace();
}
return "用户名不存在";
}
/**
* 线程处理读取服务器的阻塞问题
*/
public void run(){
while(true){
this.readFromServer();
}
}
/**
* 读消息
*/
public void readFromServer(){
try{
String input=brd.readLine();
//将收到的消息显示到界面上
jta_recived.append(input+"\r\n");
//jta_recived.setLineWrap(true);
}catch(Exception ef){
ef.printStackTrace();
}
}
/**
* 发消息
*/
public void sendMsg(String msg){
try{
msg=msg+"~\r\n";
this.out.write(msg.getBytes());
this.out.flush();
}catch(Exception ef){
ef.printStackTrace();
}
}
}
这段时间自己独立完成的东西比较少,很多都是在老师的帮助指导下完成的,以后我会自己多动脑,一步步锻炼自己,挖掘自己的潜力,独立完成一个项目。