转眼间,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();
}
}
}
这段时间自己独立完成的东西比较少,很多都是在老师的帮助指导下完成的,以后我会自己多动脑,一步步锻炼自己,挖掘自己的潜力,独立完成一个项目。
发表评论
-
M个int 排重分析
2012-10-28 00:58 981最近两周学习研究了有关大数据的解决办法,下面就M个int ... -
MyHash实现
2012-10-23 17:40 888经过一段时间的研究学 ... -
TCP的三次握手及四次断开
2012-09-19 22:27 783我们知道TCP和UDP是两种 ... -
黄金矿工游戏总结
2012-07-03 15:16 1368经过近二十天的努力,黄金矿工游戏初见雏型,它是我们对 ... -
画图板总结
2012-02-29 14:05 1348在蓝杰上了几节课后就开始了画图板的开发,从一开始简单的界面到能 ... -
java学习总结
2012-01-08 23:12 7951.八大基本数据类型 byte(字节型8) int(整型 ... -
java学习总结
2012-01-08 23:05 11.八大基本数据类型 byte(字节型8) int(整型 ... -
关键字小结
2011-11-19 10:29 796在蓝杰一个月学习后,我们开班了,1015组,开班后上的第一节 ...
相关推荐
总结起来,"2012上半年软考中级软件设计师试题及答案解析.zip" 是一个宝贵的教育资源,它涵盖了软件设计领域的广泛知识,并提供了深度解析,对于提升软件设计能力、备战软考具有极大的帮助。考生可以通过系统地学习...
乡镇2012年上半年工作总结.doc
中学2012年上半年工作总结.doc
小学2012年上半年工作总结.doc
本文将对2012年5月上半年软考软件设计师试题进行分析,并总结出相关的知识点。 软件设计师资格考试的重要性 软件设计师资格考试是中国计算机专业技术资格考试中的一项重要考试。该考试旨在检验考生的软件设计能力...
【普外科2012年上半年工作总结及下半年计划】 在2012年上半年,普外科在医院领导的指导下,全体医护人员团结协作,成功完成了各项任务,包括等级医院评审、医疗服务、科研教学、医德医风建设以及综合目标管理等多个...
街道社区2012年上半年工作总结.doc
【标题】: 2012车间上半年工作总结.doc 【描述】: 该文档是2012年车间上半年的工作总结,涵盖了车间在新机构改革背景下的管理工作、制度建设、员工培训、安全生产和质量控制等方面的内容。 【标签】: 资料 【部分...
设计队2012年上半年工作总结.doc
2012年上半年综治工作总结.doc
2012年上半年少先队工作总结.docx
房管处2012年上半年工作总结范文.doc
财务审计部2012年上半年工作总结.pdf
综合维修队2012年上半年工作总结.doc
精品工作总结模板范文-统计局2012年上半年工作总结.doc
精品工作总结模板范文-市财政局2012年上半年工作总结.doc
精品工作总结模板范文-区统计局2012年上半年工作总结.doc
这个文件的标题暗示其内容可能是某人在2012年上半年的工作总结,可能包括个人或团队的业绩、项目进度、挑战、解决方案以及对未来的规划。 描述同样简单,只提及了文件名,没有提供额外的信息。但我们可以推测,由于...
2012年上半年护士个人工作总结.doc
### 一、2012年上半年信息系统项目管理师考试概述 2012年上半年(5月)的信息系统项目管理师考试包含上午、案例分析以及论文三个部分。本次考试是针对信息系统项目管理领域的专业资格认证考试,旨在评估考生在信息...