一个简单的HttpClient多线程工具类

近期发现某项目运行一段时间后,端口占用非常多,导致程序运行异常。

经查发现里面有使用HttpClient的方式如下:

HttpClient client = new HttpClient();

…..

client.executeMethod(method)

该代码在服务器不主动关闭连接的情况下会发起大量的网络请求导致资源耗尽。

大部分人使用HttpClient都是使用类似上面的代码,包括Apache官方的例子也是如此。

具体大家可以移步:http://seanhe.iteye.com/blog/234759 作者做了较详细的分析。

考虑到接口的是定期获取采集数据的,访问比较频繁,连接也无需关闭,顺手写了一个简单HttpClient连接池。

package com.stock.util;

import java.util.Queue;
import java.util.concurrent.LinkedBlockingDeque;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;

 

/**
 * 多线程HTTP 调用工具类 <br>
 * Date: 2015-7-15
 *
 * @author snow2back
 * @version 1.0
 *
 */
public class HttpUtil {
	private static Queue<HttpClient> clientQueue = new LinkedBlockingDeque<HttpClient>();

	private static int queueSize = 0;

	/**
	 * 最大连接数
	 **/
	private static final int MAX_QUEUE_SIZE = 3;

	static ThreadLocal<HttpClient> local = new ThreadLocal<HttpClient>();

	public static HttpClient getClient() {
		// System.out.println(Thread.currentThread().getId()+"获取httpclient");
		HttpClient client = null;
		synchronized (clientQueue) {
			client = local.get();
			if (client == null) {
				// 获取一个
				if (clientQueue.size() > 0) {
					client = clientQueue.poll();
				} else {
					if (queueSize <= MAX_QUEUE_SIZE) {
						queueSize++;
						client = new HttpClient();
						client.getHttpConnectionManager().getParams()
						        .setSoTimeout(5000);
						client.getHttpConnectionManager().getParams()
						        .setConnectionTimeout(10000);
					} else {
						try {
							clientQueue.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						client = getClient();
					}
				}
				local.set(client);
			}
		}
		return client;
	}

	public static void release() {
		synchronized (clientQueue) {
			// System.out.println(Thread.currentThread().getId()+"归还httpclient");
			// 归还HTTPCLient
			clientQueue.add(local.get());
			local.remove();
			clientQueue.notify();
		}
	}

	public static final String fetchUrl(String url) {
		String rep = "";
		// ajax 数据抓取
		GetMethod method = new GetMethod(url);
		method.addRequestHeader("Accept",
		        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		method.addRequestHeader("Accept-Language:", "zh-CN,zh;q=0.8");
		method.addRequestHeader(
		        "User-Agent",
		        "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36");
		try {
			// 设置http代理
			// getClient().getHostConfiguration().setProxy("10.119.6.6", 8886);
			int status = getClient().executeMethod(method);
			if (status == 200) {
				rep = method.getResponseBodyAsString();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		release();
		return rep;
	}

	public static void main(String args[]) {
		String resp = HttpUtil
		        .fetchUrl("http://10.119.0.17/PhdSvervice/TagTime.asmx");
		System.out.println(resp);
	}
}

重新部署,程序稳定运行,问题得到解决~

大家也可以考虑更换默认的ConnectionManager为MultiThreadedHttpConnectionManager,也可以达到一样的效果。

可以看下这篇文章:http://blog.csdn.net/kobejayandy/article/details/16921265

2013年读书计划

近期读书计划

学无止境,消除惰性。

1.Android开发完全讲义(第二版)  10%

2.Core Java I  0%

3.Core Java II  0%

4.JAVA并发编程实战  10% (基本概念不是很清楚,补下内存模型内容)

5.深入理解 Java 虚拟机 (JVM 高级特性与最佳实践) 50%

JAVA EE 学习笔记(四)–SSH WEB程序员的必修课之hibernate

碎语:

很久没上博客,突然发现博客多了不少评论,想起建站时候听到的一句话,只要你建博客,肯定会有垃圾评论,无论你的水平如何,应验了。

想起建博的初衷,记录下成长的点点滴滴,回首过去,展望未来,激励自己去不停进步,总有一天我会从一个菜鸟渐渐变成一个高手,而我这走过的路,也可以帮助到一些在学习路上的朋友。

学习整理:

SSH三大框架可以说是一个合格的WEB程序员的必修课,Struts,hibernate,spring各施其职,可以说是解放了程序员。我们为什么用框架,我个人目前的理解是:1,它让开发更加便捷。2,它让程序更有效率。

Hibernate部分:

在这三个框架中,hibernate可以说是最复杂的,学习过后小总结一下。

hibernate的作用主要是提供一个ORM映射,让从数据库取出数据变得更加方便,省略了一次次无聊的get。

hibernate主要适用于oa系统,行业软件(crm,财务管理),不适合联机数据查询分析为主的系统,对性能要求高的,也不适用。

大致使用:

在hibernate.cfg.xml中配置数据库的信息,配置对应对象的*.hbm.xml文件,建立关系映射。

sessiongFactory->session->开启事务->获取query->进行操作->提交事务->关闭资源

可以使用Myeclipse给我们生成的一个HibernateSessionFactory.java来进行操作,建议去看下其具体实现,很有好处。

HQL:这个是重点了,基本上都是在和hql文打交道。

hql也支持sql中常见的distinct, between,in / not in, group by ,having 等语句,写的时候注意要基于对象来写。

使用hql来实现分页可以说是非常简单,只要设定每页数量 setMaxResult,和起始位置setFirstResult就可以了。

给一个分页的示例

/**
	 * queryVo 中除了带有查询字段外,还有 分页大小,当前页,总记录数,总页数等信息
	 * @param queryVo
	 * @return
	 */
public List<ActiveVo> findActiveVoListByQry(ActiveQryVo queryVo){
		Session session = null;
		List<ActiveVo> result = null;
		/**
		 * 查询条件
		 */
		List<Object> conditions = new ArrayList<Object>();
		/**
		 * 查询语句 / 查询总记录数 /拼接条件
		 */
		StringBuilder hql = new StringBuilder();
		StringBuilder rowsHql = new StringBuilder();
		StringBuilder sb = new StringBuilder();
		hql.append("select new com.cares.vo.ActiveVo(id,activeName,startDate,endDate,sponsors,state,creater,createTime) from TblActive where 1=1");
		rowsHql.append("select count(*) from TblActive where 1=1");
		// 拼接hql
		if (!StringUtil.isEmpty(queryVo.getActiveName())) {
			sb.append(" and activeName like ?");
			conditions.add("%"+queryVo.getActiveName()+"%");
		}
		if (queryVo.getStartDate()!=null) {
			sb.append(" and startDate >= ?");
			conditions.add(queryVo.getStartDate());
		}
		if (queryVo.getEndDate()!=null) {
			sb.append(" and endDate <= ?");
			conditions.add(queryVo.getEndDate());
		}
		if (!"-1".equals(queryVo.getState())){
			sb.append(" and state = ?");
			conditions.add(queryVo.getState());
		}
		/**
		 * 拼接
		 */
		hql.append(sb);
		rowsHql.append(sb);
		try {
			session = HibernateSessionFactory.getSession();
			Query query = session.createQuery(hql.toString());
			Query queryRow = session.createQuery(rowsHql.toString());

			for (int i = 0; i < conditions.size(); i++) {
					Object obj = conditions.get(i);
					query.setParameter(i, obj);
					queryRow.setParameter(i,obj);
			}
			// 设定总记录数
			int n = ((Long)queryRow.iterate().next()).intValue();;
			queryVo.setAllSize(n);

			// 设定分页
			query.setFirstResult((queryVo.getCurPage()-1)*queryVo.getPageSize());
			query.setMaxResults(queryVo.getPageSize());
			result = query.list();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			HibernateSessionFactory.closeSession();
		}
		return result;
	}
关系映射:主要有三种
many to one  会生成 外键的一个对象(可以配置many to one 特例,一对一)
one to many  会生成 对象的集合
one to one  一对一

缓存:

使用query接口查询数据,是不会从缓存中获取数据的,但是其获取的数据会放到缓存中供get/load来使用。

hibernate有二级缓存,不会默认开启,要手动配置缓存,有挺多缓存框架可以用,以下是OScache的示例,其它配置大同小异。

<property name="cache.use_second_level_cache" >true</ property>
<property name="cache.provider_class" >org.hibernate.cache.OSCacheProvider</ property>
<property name="hibernate.generate_statistics" >true</ property>
<class-cache usage="read-only" class ="com.cares.pojo.TblInterest" />
解决懒加载问题
建议many-to-one可以配置下
解决方法:
1.扩展session作用域(sessionInView)
2.配置xml 中对应的对象lazy 为 false
3.显示初始化对象集合hibernate.initialize()
4.ssh整合的时候 可以注解方式 (这个没使用过)
主键生成策略,手册第五章
①increament:用于long,short,int类型生成唯一标识。// 单进程状态可以使用
<id name=”id” type=”java.lang.String”>
<generator />
<id>
②identity:需要数据库支持,mysql ,sqlserver。
③sequence:db2,oracle可以使用。
④native:根据底层数据库,选择identity,sequence,hilo中的一种。
⑤hilo:高地位算法
<id name=”id” type=”java.lang.Integer” column=”ID”>
<generator>
<param name=”table”>my_hi_value</param>
<param name=”column”>next_value</param>
</generator>
</id>
⑥uuid
128位2
⑦assigned
用户自己设定的主键
(8)复合主键
(9)foreign
sequence / identify / uuid / hilo
使用原则
Oracle 主键是 int/long/short  使用sequence
          主键是字符串,uuid/assigned
Mysql  int/long/short   使用increament
          字符串,uuid/assigned

JAVA EE 学习笔记(三)–JavaScript让人既爱又恨

碎语:

近期发生了很多事情,心情很是烦躁。一是实习方面,很多朋友都出去实习了,实习工资开得还挺高,虽然我是本着实习是学习的心态,但是这也是要能够基本温饱的情况,年纪挺大了,老问父母要钱也听不好意思。实习的话还有纠结的则是实习的公司的选择,我有信心让大公司看上我,我各方面都还算得上优秀,大学期间挺多时间去学习计算机相关的知识,但是在毕业刚刚开始的几年是最关键的,在大公司优厚的待遇和小公司有一展拳脚的空间,我有些难以取舍,在我的个人规划中近几年我会经历很多家公司,直到时机成熟的时候,成立自己的公司。现在的问题则是从哪里开始更加有利于日后的发展,这个问题我觉得有必要请教下前辈的经验了。

笔记:

Javascript是一门神奇的语言,让人既爱又恨(这很多东西都不一样啊),总的来说,它的作用是操作DOM,给用户更友好的交流体验。

先晒下学习成果吧,自己写的一个弹出层示例。

自己写的alert提示框

这个重点是写个利用createElement创建元素,配合一个遮罩层来实现。

tips:还有prompt和confirm如果要写的话无法通过阻塞方式实现的,只能通过回调函数(N多资料后的结论)。

以下则是我整理出来的一些重点~

数组的定义

var arr = new Array();
var arr = new Array(3);
var arr = new Array(“1″,”2″,”3”);
var arr = [“1″,”2”];

判断条件

等于== 全等于=== 全等于要求类型也相等

函数定义方式

1.变量定义:
var getNumber = new function(){};
2.直接定义 function a(){}

函数调用方式:

1.作为事件处理程序调用(onclick = “”)。

2.绑定事件处理程序。
document.all.BUTTON_name.click();
3.全局调用 (直接写代码,基本没怎么用的)

4.元素对象属性字符串中调用。//不怎么看到
<script language=”javascript” for=”document” event=”oncontextmenu”>
window.event.returnValue = false;
</script>

document all 集合的使用方法

id name index tagName
all[id] all[name] all[index]
all.item(index)与上面等效
//是tags方法不是集合
all.tags(tagName)[0].tagName

以上方法已经被替代掉了,用下面的吧
getElementById
getElementsByName
getElementsByTagName

tips:火狐调试发现document.getElementById提示找不到对象,Javascript最好等dom树建立后再去运行。

tips:  不要乱用iframe,建立DOM树慢了一个数量级,会消耗连接,延缓onload事件,用户的感觉就是很慢。

表单的使用:

调用:
1.表单名 document.form1.username.value
2.对象集合 document.forms[]
form1.username //通过name直接应用
两个重要方法:
1.form.submit();
2.form.reset();
两个重要的事件句柄
1.onreset
2.onsubmit
提交参数设置:
form.method = “post/get”
form.action =”mailto:[email protected]
元素操作
focus //设置焦点到需要修改项
select

Cookie的使用

设置:
document.cookie = “id=12”;
document.cookie = “ff=teset”;
提取
arr.split(;);
str.indexOf() 配合substring()来截取
加密escape unescape
有效期
date.setTime(date.getTime() + n*3600*24*1000);
document.cookie = name + “=” uname + “;expire=” + date.toGMTString();

javascript innerHTML、outerHTML、innerText、outerText的区别
HTML是操作HTML代码 Text操作文本//特殊字符会自动转义
inner是标签内部的 outer操作的是标签本身

以下内容我觉得是目前Javascript的重中之重

AJAX重要摘记:
XMLHttpRequest对象:
创建不同浏览器不一样,通用方法如下:

function ajaxFunction()
{
var xmlHttp;
try
{
// Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
alert("您的浏览器不支持AJAX!");
return false;
}
}
}
}

XMLHttpRequest对象的属性:
一个例子来说明:

if (xmlhttp!=null)
{
xmlhttp.onreadystatechange=state_Change;
xmlhttp.open("GET",url,true);
xmlhttp.send(null);
}
function state_Change(){
if (xmlhttp.readyState==4)
{// 4 = "loaded"
if (xmlhttp.status==200)
{// 200 = OK
// ...our code here...
}
else
{
alert("Problem retrieving XML data");
}
}
}

设置事件句柄:
事件句柄:
onreadystatechange
每次 readyState 属性改变的时候调用的事件句柄函数。当 readyState 为 3 时,它也可能调用多次。

readyState:
状态 名称 描述
0 Uninitialized 初始化状态。XMLHttpRequest 对象已创建或已被 abort() 方法重置。
1 Open open() 方法已调用,但是 send() 方法未调用。请求还没有被发送。
2 Sent Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。
3 Receiving 所有响应头部都已经接收到。响应体开始接收但未完成。
4 Loaded HTTP 响应已经完全接收。
status
由服务器返回的 HTTP 状态代码,如 200 表示成功,而 404 表示 “Not Found” 错误。
当 readyState 小于 3 的时候读取这一属性会导致一个异常。
使用基本流程:
1.绑定onreadystatechange
2.初始化请求参数open()
3.send()提交
如果之前调用的 open() 参数 async 为 false,这个方法会阻塞并不会返回,
直到 readyState 为 4 并且服务器的响应被完全接收。否则,如果 async 参数为 true,或者这个参数省略了,send() 立即返回.
4.onreadystatechange绑定函数中的操作
xmlhttp 对象
xmlhttp.readyState == 4 //onload
xmlhttp.status == 200 //ok readyState must be 4
xmlhttp.responseText;

JAVA EE 学习笔记(二)

碎语:

好久没有写文章,除了临近期末,要准备考试之外,还有个原因则是生活上遇到一些问题。大三了,马上就大四了,由于参加了个软件的培训,这个暑假估计都没法出去实习了,现在有些矛盾,感觉培训这边的话进度有点慢,还没自己学得快,但是有个学习环境还是很好的,到时候集中训练的时候再看看效果吧。人生总是充满了这种矛盾,就像女朋友并不赞成我留着现在这个城市一样,她希望我可以回到那个小城市,安安稳稳地过日子,但是她是一个喜欢享受的人,没有一个良好的经济基础,怎么过上安逸的生活。我的想法很简单,男子汉大丈夫,事业未立,何以家为。如果以后要我去做些和IT无关或者卖卖电脑打打杂的这种工作,我还不如死了算了。从小到大我字写得都很差,但是我从来不在意这点,也没刻意去做改变,因为我知道我以后的工作,只要有个电脑就好了,打字速度快点就差不多了,想法很简单,但这就是我的路,我希望能走这个路,未来如何,我都无所畏惧。

言归正传,对这个阶段的学习做下整理吧。

笔记:

这个阶段主要是学习了下javascript,复习了下css。

页面布局:

之前CSS其实也有学过,不过对于布局一直不是很清楚,东西可以做出来,但是花的时间特别多。经过这次的学习感觉用起来顺手很多了,扒了个新浪微博的界面

我扒的新浪微博界面

感觉布局中有几点很是重要:

1.margin是外边距,不计算到元素自身大小里面

2.padding是内边距,使用padding的时候,面积会变大

3.display: 这个比较重要,通过更改display的属性可以更改元素默认的display属性,不居中很有用,比如你可以将一个p改为inline,这样两个段落之间不会换行了。

4.position属性很重要,

static是默认值,这个出现在它应该在的地方

relative是相对定位,使用这个可以对元素进行偏移,但是元素会占用它本应该占用的空间

absolute绝对定位,当使用绝对定位的时候,它将不占用空间(层叠了),但是当它的父元素为relative的时候,它绝对定位的基础是父元素的位置

fixed定位,可以理解为将元素设成父元素为当前窗口的absolute定位(在特定位置停留不动)。

关于这个有个文章有详细介绍,有兴趣可以看看: CSS定位属性Position详解

5.display none 和 visibility hidden 之间的区别

这两个配合js动态调用和position可以做些漂亮的弹出菜单,或者是一些动态效果。它们之间的区别在于:display:none这个设置之后,元素不再占用空间。visibility:hidden设置后,会占用原来的空间

这个在w3schools上面有个示例很形象可以看看:CSS Display and Visibility http://www.w3schools.com/css/css_display_visibility.asp

6.浮动float 这个可以说是重中之重了,布局神器。

使用float可以让元素浮动起来,完成平常常见的2栏或者3栏布局,或者是生成一个漂亮的横向菜单。

使用这个属性后有一件事情很重要,得清除浮动。

就现在总结了下,清除浮动的方法:

1.父元素下面加个div块设置clear:both;
2.父元素添加overflow:hidden 这个比较费解,但是它的确可以起到清除浮动的作用,可以让内部的元素撑开父元素。
3.还有个方法是新浪微博用的方法。给父元素添加一个.clearfix样式。
这个其实和1方法原理是相同的。

.clearfix::after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

7.CSS sprite,这个可以讲多张背景图片拼接到一起,使用同一个background-image ,然后通过background-position进行移位

如果向上移动10px ,左移动20px 应该这么设置:background-position:-10px 20px;

这个实例比较好理解,这里推荐一篇老外写的文章,很详细,介绍了为什么要使用css sprite,如何使用css sprite,英文要是不好的话,可以直接跳到后面看关键的内容http://css-tricks.com/css-sprites/

JAVA EE 学习笔记(一)

碎语:

学JAVA好几个月了,断断续续的,怕贪多嚼不烂一直都不敢学得太快,还是从基础开始学起。

先是大致看了下教程,然后再找了本《JAVA疯狂讲义》来进行学习,这本书讲得很细,这是个优点,也是它的缺点了,大部分还是完整看下来了,跳过后面一些章节,例如讲界面部分的内容可以大致看看,等到以后如果有需要的话去查询也是可以的。

近期正式进入web部分,这部分感觉和之前学过的php差不多,有许多概念都是重复的http响应头,之类内容算是有了一个较好的整合。

找的 韩顺平.2011最新j2ee视频教程 学习,基本一天学好几天的课程,速度比较快,觉得有必要做些笔记进行温习,不然容易忘记,至于练习的话则暂时不做,有php的经验,等到后面学Jsp的时候将 servlet ,jsp ,javabean一起来个统一练习。

笔记:

tomcat部分

1.tomcat运行需要设置环境变量主要是JAVA_HOME,CLASS_PATH,不然的话有些应用汇不正常。

2.tomcat的应用目录是webapps,应用的目录结构是 WebRoot –> WEB-INF ;WEB-INF目录下情况:classes,lib,web.xml。其中classes包含的是编译后的.class文件,lib包含的是应用需要的jar包,web.xml是服务的配置文件。程序源码并不需要发布到应用上面。

web.xml 文件,主要分层如下  service –> connector –> engine –> host->context

1.此文件可以配置servlet访问路径等信息,mapping 可以映射为 /* , *.do,/具体内容,各种形式,其采用的是最长匹配。

2.<load-on-startup>参数可以让servlet在后台启动,这个可以执行定时任务。

3<init-param> 可以配置变量被程序使用

Servlet部分:

1.servlet生存周期: 请求->反射方式装载类-> init()调用一次 ->使用service方法。

2.单例会出现线程同步问题。

3.现在基本继承 HttpServlet来实现功能。

Request & Response对象  主要是几个常用方法需要注意下

1.request.setCharacterEncoding(“utf-8”); response.setContentType(“text/html;charset=utf-8”) 可以进行编码设置,防止乱码的出现。

2.response输出流只能获取一次,之后系统会返回给用户然后自动关闭。

3.两者均有一个跳转 request.getRequestDispatcher(“path”).forward(request,response),response.sendRedirect(url) ,前者是服务器端进行的,可以附带请求和解析的转发,后者是浏览器的302重定向。

4.request主要用于获取客户机的一些信息,url,uri,queryString ,remoteAddr之类。

中文编码乱码处理

   这个比较麻烦,简单说是编码不一致导致的乱码问题。

   需要编码的地方:浏览器编码(request),web服务器编码,返回对象编码(response),文件编码,编译编码(jsp页面)。

   web服务器编码默认是iso-8859-1方式,浏览器默认get使用iso-8859-1(不确定,查协议再说),Post提交的数据encoding一下就可以了。

   如果是要生成url的话,就需要用URL Encoder Decoder 工具对其进行编码/解码了。

post get看实例:

//响应头设成utf-8编码 设置返回编码
    response.setContentType("text/html;charset=utf-8");
    
    //post直接对request 转码就可以  get转码是没用的
    request.setCharacterEncoding("utf-8");


    //如果不转码但是使用 以下方法     post or get都可以顺利转换编码
    String s = new String(request.getParameter("name").getBytes("iso-8859-1"),"utf-8");

    out.println( s  + "get  encode");
    out.println("自己设定的中文"); //这样是可以的
    System.out.println(s + "get提取"); //查看获取到的是否是好码
    out.println("<form name=’form1′ action=” method=’get’>");
    out.println("<input type=’text’ name=’name’>");
    out.println("<input type=’submit’ />");
    out.println("</form>");
    out.flush();
    out.close();

MVC模式

   这个是重点了,model view controller ,分层三块各司其职。   其中model可以细分为 业务逻辑,DAO,持久层。

model主要处理业务逻辑部分,实现业务需要的功能。

controller 主要负责请求的调度,根据请求转向不同的view调用不同的model来处理请求。

view  主要负责界面的显示。

如果用纯servlet实现的话,可以分 domain, service,view,controller 来进行编程。

 

 

个人小结:

不总结的时候以为什么都懂了,看一遍什么都知道了,学得快忘得也快,还需要看书巩固知识。同时需要学习下javascript,至少要会简单的判断。

数据结构课程设计报告,哈夫曼树

 

 

 

 

数据结构课程设计 

 

实验题目:赫夫曼编码/译码器 

 

 

       

 

 

 

 

 

 

 

 

 

 

一、需求分析 

      利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个赫夫曼码的编/译码系统。 

 

 

二、基本要求 

    1.基本要求 

一个完整的系统应具有以下功能: 

     (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。 

 (2) E:编码(Encoding)。利用已建好的赫夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 

 (3) D:译码(Decoding)。利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。 

2.测试要求 

(1) 利用教科书例6-2的数据调试程序:已知某系统在通信联络中只可能出现八种字符,其频率分别0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。 

(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME  IS  MY  FAVORITE”。 

 

字符 

 

A 

B 

C 

D 

E 

F 

G 

H 

I 

J 

K 

L

M

频度

186

64

13

22

32

103

21

15

47

57

1

5

32

20

字符

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

 

频度

57

63

15

1

48

51

80

23

8

18

1

16

1

 

 

3.实现提示

(1) 编码结果以文本方式存储在文件Codefile中。

(2) 用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”,表示退出运行Quit。请用户键入一个选择功能符。此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。

(3) 在程序的一次执行过程中,第一次执行IDC命令之后,赫夫曼树已经在内存了,不必再读入。每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。

概要设计 

   程序主要分为五部分,哈夫曼节点的定义,哈夫曼编码的定义,Select函数选择出权值最小的节点,Initialization函数生成哈夫曼树,主函数。

  

四、详细设计

1. 数据存储结构设计

1哈夫曼节点

 哈夫曼节点数据类型如下,包含字符,权值,父节点,左右孩子:

typedef struct{

        char ch;

        unsigned int weight;

        unsigned int parent,lchild,rchild;       

}HTNode,*HfmTree;

(2)哈夫曼编码

     哈夫曼编码用二级指针存储,动态分配空间:

typedef char **HfmCode;

2. 算法的设计思想

   1Select函数

 

void Select(HfmTree HT,int a,int &s1,int &s2){
     //选择出parent为0的两个权值最小的两个节点,s1节点权值小于s2节点
     int i,temp;
     i=0;
     while(HT[++i].parent!=0);
     s1=i;
     while(HT[++i].parent!=0);
     s2=i++;
     if(HT[s1].weight>HT[s2].weight){
        temp=s1;
        s1=s2;
        s2=temp;
     }
     for(;i<=a;i++){
        if(HT[i].parent==0)
           if(HT[i].weight<HT[s1].weight)  s1=i;
             else if(HT[i].weight<HT[s2].weight) s2=i;
     }
}//选出权值最小且无父节点的节点,选择范围为i-a;

 

   2Initialization函数

 

void Initialization(HfmTree &HT,HfmCode &HC,int n,string ch,int *w)
   {
     int i,m,s1,s2,start,c,f;
//i HTNode位置,m为哈夫曼树节点数,s1s2选择节点,start开始点,c当前节点,f父节点
     char* cd;
     if(n<=1) return;
     m=2*n-1;
     HT=(HfmTree)malloc((m+1)*sizeof(HTNode));//0号单元使用
     for(i=1;i<=n;i++){
        HT[i].ch=ch[i-1];
        HT[i].weight=w[i-1];
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
     }//初始化叶子节点

     for(;i<=m;i++){
        HT[i].ch='0';
        HT[i].weight=0;
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
     }//----------------为什么不能批量赋值----------!!

     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;
     }
     HC=(HfmCode)malloc((n+1)*sizeof(char*));
     cd=(char*)malloc(n*sizeof(char));
     cd[n-1]='';
     for(i=1;i<=n;i++){
        start=n-1;
        for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){
           if(HT[f].lchild==c){
              cd[--start]='0';
           }else{
              cd[--start]='1';
           }
        HC[i]=(char*)malloc((n-start)*sizeof(char));
        strcpy(HC[i],&cd[start]);
        }
     }
     free(cd);
     cout<<"生成成功!"<<endl<<endl;;
     cout<<"IDtchart"<<"weight"<<"t"<<"parent"<<"t"<<"lchild"<<"t"<<"rchild"<<"t"<<endl;
     for(i=1;i<2*n;i++){
          cout<<i<<"t"<<HT[i].ch<<"t"<<HT[i].weight<<"t"<<HT[i].parent<<"t"<<HT[i].lchild<<"t"<<HT[i].rchild<<"t"<<endl;
     }
     cout<<"chart"<<"Codet"<<endl;
     for(i=1;i<=n;i++){
           cout<<HT[i].ch<<"t"<<HC[i]<<"t"<<endl;
    }
}
 //生成,前半部分为生成哈夫曼树,调用Select得出权值最小的两项,计算权值
 //后半部分为哈夫曼编码生成,从后到前生成,动态分配空间大小

 

 

3.源程序

 

#include<iostream>
#include<fstream>
#include<string>
using namespace std;
typedef struct{
        char ch;
        unsigned int weight;
        unsigned int parent,lchild,rchild;
}HTNode,*HfmTree;

typedef char **HfmCode;

void Select(HfmTree HT,int a,int &s1,int &s2){
     //选择出parent为0的两个权值最小的两个节点,s1节点权值小于s2节点
     int i,temp;
     i=0;
     while(HT[++i].parent!=0);
     s1=i;
     while(HT[++i].parent!=0);
     s2=i++;
     if(HT[s1].weight>HT[s2].weight){
        temp=s1;
        s1=s2;
        s2=temp;
     }
     for(;i<=a;i++){
        if(HT[i].parent==0)
           if(HT[i].weight<HT[s1].weight)  s1=i;
             else if(HT[i].weight<HT[s2].weight) s2=i;
     }
}


void Initialization(HfmTree &HT,HfmCode &HC,int n,string ch,int *w)
   {
     int i,m,s1,s2,start,c,f;
     //i HTNode位置,m为哈夫曼树节点数,s1s2选择节点,start开始点,c当前节点,f父节点
     char* cd;
     if(n<=1) return;
     m=2*n-1;
     HT=(HfmTree)malloc((m+1)*sizeof(HTNode));//0号单元使用
     for(i=1;i<=n;i++){
        HT[i].ch=ch[i-1];
        HT[i].weight=w[i-1];
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
     }//初始化叶子节点

     for(;i<=m;i++){
        HT[i].ch='0';
        HT[i].weight=0;
        HT[i].parent=0;
        HT[i].lchild=0;
        HT[i].rchild=0;
     }//----------------为什么不能批量赋值----------

     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;
     }
     HC=(HfmCode)malloc((n+1)*sizeof(char*));
     cd=(char*)malloc(n*sizeof(char));
     cd[n-1]='';
     for(i=1;i<=n;i++){
        start=n-1;
        for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){
           if(HT[f].lchild==c){
              cd[--start]='0';
           }else{
              cd[--start]='1';
           }
        HC[i]=(char*)malloc((n-start)*sizeof(char));
        strcpy(HC[i],&cd[start]);
        }
     }
     free(cd);
     cout<<"生成成功!"<<endl<<endl;;
  cout<<"IDtchart"<<"weight"<<"t"<<"parent"<<"t"<<"lchild"<<"t"<<"rchild"<<"t"<<endl;
     for(i=1;i<2*n;i++){
cout<<i<<"t"<<HT[i].ch<<"t"<<HT[i].weight<<"t"<<HT[i].parent<<"t"<<HT[i].lchild<<"t"<<HT[i].rchild<<"t"<<endl;
     }
     cout<<"chart"<<"Codet"<<endl;
     for(i=1;i<=n;i++){
           cout<<HT[i].ch<<"t"<<HC[i]<<"t"<<endl;
    }
}



int main(){
    ifstream input_file;
    ofstream output_file;
    char action;
    string toBeTranSource,textFileSource;
    string charsIn,code;
    int i,j,c,n,w[100];
    HfmTree HT;
    HfmCode HC;
    while(action!='Q'){
        cout<<endl<<"**********************************************"<<endl;
        cout<<"*          哈夫曼编码/译码器                 *"<<endl;
        cout<<"*                                            *"<<endl;
        cout<<"*  I.初始化  E.编码  D.译码 /P.印码  /T.印树 *"<<endl;
        cout<<"*  C.清屏                                    *"<<endl;
        cout<<"*     Code by whocaresu    16/12/2010        *"<<endl;
        cout<<"**********************************************"<<endl;
        cout<<endl<<"请输入操作码:";
        cin>>action;
        action=toupper(action);
        switch(action){
                       case 'I':
                            // 输入信息
                            cout<<"请输入字符数:";
                            cin>>n;
                            cout<<"请输入字符组(紧密输入不用空格区分):";
                            getline(cin,charsIn);
                            getline(cin,charsIn);
                            cout<<"输入各个权重(中间空格):";
                            for(i=1;i<=n;i++){
                            cin>>w[i-1];
                            }
                            Initialization(HT,HC,n,charsIn,w);
                            //输出备份到文件
                            cout<<"正在输出备份到hfmTree.txt..."<<endl;
                            output_file.open("hfmTree.txt");
                            if(!output_file){
                                 system("cls");
                                 cout<<"Can't open file!"<<endl;return 1;
                            }
                            output_file<<n;
                            output_file<<charsIn<<"n";
                            for(i=0;i<n;i++){
                               output_file<<w[i]<<" ";
                            }
                            output_file<<"--------以下为具体编码信息--------"<<endl;
                            output_file<<"ChartCodet"<<endl;;
                            for(i=1;i<=n;i++){
                            output_file<<HT[i].ch<<"t"<<HC[i]<<"t"<<endl;
                            }
                            output_file.close();
                            cout<<"备份到hfmTree.txt成功!"<<endl;
                            ;break;

                       case 'E':
                            //判断内存中是否有生成哈夫曼树,没有的话从文件读入
                            if(sizeof(HC)<5){
                           cout<<"内存中不存在哈夫曼树,从hfmTree.txt读入!"<<endl;
                               input_file.open("hfmTree.txt");
                               if(!input_file){
                                 system("cls");
                                 cout<<"Can't open file!"<<endl;return 1;
                               }
                               input_file>>n;
                               getline(input_file,charsIn);
                               for(i=1;i<=n;i++){
                                  input_file>>w[i-1];
                               }
                               input_file.close();
                               Initialization(HT,HC,n,charsIn,w);
                            }
                            input_file.open("ToBeTran.txt");
                            if(!input_file){
                                 system("cls");
                                 cout<<"Can't open file!"<<endl;return 1;
                            }
                            cout<<"-------从ToBetTran.txt读取数据为--------"<<endl;
                            getline(input_file,toBeTranSource);
                            cout<<toBeTranSource<<endl;
                            input_file.close();
                            cout<<"----------------------------------------"<<endl;
                            output_file.open("CodeFile.txt");
                            if(!output_file){
                                 system("cls");
                                 cout<<"Can't open file!"<<endl;return 1;
                            }
                            cout<<"------编译的密文(输出到CodeFile.txt)----"<<endl;
                            for(i=0;i<=toBeTranSource.length();i++){
                               for(j=1;j<=n;j++){
                                  if(toBeTranSource[i]==HT[j].ch){
                                     cout<<HC[j];
                                     output_file<<HC[j];
                                  }
                               }
                            }
                            output_file.close();
                            cout<<endl<<"------------编译完成--------------------"<<endl;
                            ;break;
                      case 'D':
                           //译码
                           input_file.open("CodeFile.txt");
                           if(!output_file){
                                 system("cls");
                                 cout<<"Can't open file!"<<endl;
                                 return 1;
                           }
                           cout<<"------------读取的编码为----------------------"<<endl;
                           getline(input_file,code);
                           cout<<code<<endl;
                           input_file.close();
                           cout<<"----------------译码为--------------------"<<endl;
                           c=2*n-1;
                           output_file.open("TextFile.txt");
                           for(i=0;i<=code.length();i++){
                               if(HT.lchild==0){
                                 cout<<HT.ch;
                                 c=2*n-1;
                               }
                               if(code[i]=='0') c=HT.lchild;
                               else c= HT.rchild;
                           }
                           cout<<endl;
                           cout<<"-------------------------------------------"<<endl;
                           ;break;
                      case 'C':
                           system("cls");
                           break;
                      default:
                              cout<<endl<<"操作码错误,重新输入!"<<endl;
        }
   }
   system("pause");
   return 0;
    }

 

 

 

五、调试分析

1.测试数据列表:

(1) 利用教科书例6-2的数据调试程序:0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11

(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME  IS  MY  FAVORITE”。

 abcdefghijklmnopqrstuvwxyz

186 64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 15 1 48 51 80 23 8 18 1 16 1


 

 

 

 

 

 

 

 

 

 

、课程设计总结及心得体会

     不得不说,这个是目前做到的最复杂的一个程序,与停车场相比,它的函数,数据存储结构的定义少了不少,但是其复杂度却比停车场有过之无不及,文件操作比较复杂,为此我查阅了相关资料,做到了基本能够实现文件的读取和写入,程序中依然存在一个问题,那就是它只能读取一段文字,遇到回车会终止读入,这也局限了程序的使用面。

     在开发哈夫曼编译器的时候,发现一个整体概念很重要,要很清晰地知道它具体是怎么运作的。双亲结点,左右孩子,字符,权值组成哈夫曼节点,二级指针来动态存储哈夫曼编码,然后分配空间,调用Select函数帮助生成哈夫曼树,最后才生成哈夫曼节点。

     这次课程设计,加深了我对哈夫曼树的理解,巩固了数据结构的知识。但是我认为其中更加重要的是实践的一个过程,实践中学习,清楚了理论与实践之间的差距。用google搜索相关的资料,然后从资料中获取自己需要的信息,化为己用,这种学习的能力的锻炼,我认为才是最为重要的。

     

 

c++数据结构编程,停车场管理

终于好了~~中间一个错误,内存分配有问题,原来malloc分配空间太小了~~解决了
/*
 * 停车场管理
 * author:whocares
 * date:20101125
  */
#include<stdio.h>
#include<iostream>
using namespace std;
#include<malloc.h>
const int ParkingAreaSize=2;         //停车场位置数
const int DetourLength=100;			//便道位置数
const int Price=10;
#define ERROR 0;
#define OK 1;
#define OVERFLOW -1;
typedef int Status;
/*
-----------------------停车场定义-------------------------
*/
typedef struct CarInfo{
        int number;
	    int ar_time;
}CarInfo;
typedef struct{
           CarInfo  *base;    //停车场的堆栈底
           CarInfo  *top;    //停车场的堆栈顶
           int ParkingAreaSize_now ;
}ParkingArea;

//停车场操作;
Status InitStack(ParkingArea &L){
         L.base=(CarInfo*)malloc(ParkingAreaSize*sizeof(CarInfo));
         if(!L.base) return OVERFLOW;
         L.top=L.base;
         L.ParkingAreaSize_now=0;
         return OK;
       }

Status Push(ParkingArea &L,CarInfo e){
         *L.top++=e;
         L.ParkingAreaSize_now++;
		 return OK;
       }

Status Pop(ParkingArea &L,CarInfo &e){
        if(L.top==L.base) return ERROR;
        e=*--L.top;
        L.ParkingAreaSize_now--;
        return OK;
       }
Status DestoryStack(ParkingArea &L){
        free(L.base);
        return OK;
       }
/*
--------------------便道定义------------------
*/
typedef struct DetourCarInfo{
    int number;      //汽车车号
    int ar_time;      //汽车到达时间
    struct DetourCarInfo *next;
}DetourCarInfo,*DetourPtr;

typedef struct{
    DetourPtr front;    //便道的队列的对头
    DetourPtr rear;    //便道的队列的队尾
    int DetourLength_now;
}Detour;

//便道操作;
Status InitDetour(Detour &d){
        d.front=d.rear=(DetourPtr)malloc(sizeof(DetourCarInfo)); //这里第一次把DetourCarInfo 写成CarInfo 造成分配空间小的悲剧了
        if(!d.front) return OVERFLOW;
        d.rear->next=NULL;
        d.DetourLength_now=0;
        return OK;
       }
Status EnDetour(Detour &d,CarInfo c){//便道,车辆信息
        DetourPtr p;
        p=(DetourPtr)malloc(sizeof(DetourCarInfo));
        if(!p) return OVERFLOW;
        p->ar_time=c.ar_time;
        p->number=c.number;
        p->next=NULL;
        d.rear->next=p;
        d.rear=p;
        d.DetourLength_now++;
        return OK;
       }
Status PopDetour(Detour &d,CarInfo &c){
        DetourPtr dp;
        if(d.rear==d.front){
           cout<<"*|便道为空!"<<endl;
           return OK;
           }
        dp=d.front->next;
        c.ar_time=dp->ar_time;
        c.number=dp->number;
        d.front->next=d.front->next->next;
        if(d.rear==dp)d.rear=d.front;//如果出便道的是最后一辆车,特殊处理下rear
		free(dp);
		d.DetourLength_now--;
		return OK;
       }

void CarIn(ParkingArea &p,Detour &d,CarInfo c){//停车场,车辆信息
    if(p.ParkingAreaSize_now<ParkingAreaSize){
       Push(p,c);
       cout<< "*|车牌号为"<<c.number<<"的车进入停车场,停在 "<<p.ParkingAreaSize_now<<" 号停车位!"<<endl<<endl;
    }else{
       EnDetour(d,c);
       cout<<"*|停车场已满,车牌号为"<<c.number<<"先停在便道的第"<<d.DetourLength_now<<"个位置上"<<endl<<endl;
     }

}


void CarLeave(ParkingArea &p,ParkingArea &temp,Detour &d,CarInfo c){ //停车场,倒车,便道,离开车的信息
    int cost,time_now;
    time_now=c.ar_time;//当前时间保存
    if(p.ParkingAreaSize_now==0){cout<<"没车了,还离开?"<<endl;return;}
    while(p.top->number!=c.number&&(p.top!=p.base)){//第二次看的生活发现这里有个问题。。思维有点混乱了,要需要的话自己改下吧,不花多少时间
           Pop(p,c);
           Push(temp,c);
         }
    Pop(p,c);
    cost=Price*(time_now-c.ar_time);
    cout<<"*|车牌号为";
    cout<<c.number;
    cout<<"的车离开停车场,离开时间: ";
    cout<<time_now;
    cout<<",在停车场停留时间为:";
    cout<<time_now-c.ar_time;
    cout<<"收费:";
    cout<<cost;
    cout<<"元"<<endl<<endl;
    while(temp.ParkingAreaSize_now){
          Pop(temp,c);
          Push(p,c);
          }
    if((p.ParkingAreaSize_now<ParkingAreaSize)&&(d.DetourLength_now>0)){
         PopDetour(d,c);
         c.ar_time=time_now;
         Push(p,c);
         cout<<"停车场有空位,车牌号为:"<<c.number<<"的车由便道进入"<<p.ParkingAreaSize_now<<"号车道。"<<endl;
         }
}

int main()
    {
     char action;
     CarInfo c;
     ParkingArea parkingAreaInstance,temp;
     Detour   line;
     InitStack(parkingAreaInstance);
     InitStack(temp);
     InitDetour(line);
     while(1)
         {
         cout<<endl;
         cout<<"           --停车场管理系统-- CODE BY WHOCARESU    "<<endl;
         cout<<"---------------------------------------------------"<<endl;
         cout<<"|     A-到达         D-离开        E-退出         |"<<endl;
         cout<<"|                                                 |"<<endl;
         cout<<"|     示例:A:牌号为1的车于5点到达:A 1 5         |"<<endl;
         cout<<"|           D:牌号为1的车于7点离开:D 1 5         |"<<endl;
         cout<<"---------------------------------------------------"<<endl;
         cout<<" 请输入信息: ";
         cin>>action;
         cout<<endl;
         action=toupper(action);
         switch(action)
             {
              case 'A':
                    cin>>c.number>>c.ar_time;
                    CarIn(parkingAreaInstance,line,c);break;        //汽车进车场
              case 'D':
                   cin>>c.number>>c.ar_time;
                   CarLeave(parkingAreaInstance,temp,line,c);break; //汽车出车场
              case 'E':
                    return 0;
              default:
                    cout<<"*|操作码有误,请重新输入!"<<endl;
                    break;
            }
        }
}



MISSION START NO.5内容抓取&&面向对象设计

最近挺混乱的,女女回家总要陪陪~~拜托没工夫看了

都是晚上在看

总结复习下

内容抓取

打开远程网址,$fp=fopen(“url”,r)

读取数据 ,$filecontents=file_get_content($fp #OR url,r)

使用 ereg&&eregi正则表达式来抓取想要的内容ereg(“表达式”,$filecontents,$reg) 内容

$reg[1]取得的内容

代入模板就ok了~~

面向对象程序设计内容比较多。看了好几天了~~

1 有几个函数需要注意下

__construct()   __destruct()  //php5中虽然兼容和类同名的成员函数做初始化函数,但是考虑到类名

__set()   __get() //对private属性的成员可以做做输入输出的处理~

private protected public  //和c++差不多

2 抽象类,抽象方法

abstract关键字

其实就是个模板,让人用,让人遵守规则

3 几个关键字

final self static CONST #  final 和 self 特别点~剩下两个基本和c++一样的

4接口interface implements

全部是抽象方法,public 成员属性为常量

单继承多接口,继承在先

暂时到这里了~

MISSION START NO.4 学习手记 -静态生成

主要学习了静态生成的原理 建立好模板后,通过php程序根据模板和内容生成静态网页减轻服务器和数据库的压力~·

貌似暂时用不着。。这么高级的功能。。

我暂且当它是用来盗窃比人的模板的好工具吧几个文件操作函数 fopen(),fread(),filesize(),fwrite(),fclose(),配合下foreach str_replace()来使用

今天内容比较简单,这么几天下来渐渐找到窍门了~~明天开始一天学两章~~呵呵今天重点是和网工一学长交流了下,大概得知以后方向了。

。看来得往软件方向发展了~下次考个网工吧,同时把那个数据结构研究下~~ok,继续充电….