javascript实现数据结构:广义表
广义表是线性表的推广。广泛用于人工智能的表处理语言Lisp,把广义表作为基本的数据结构。
广义表一般记作:
LS = (a1, a2, ..., an)
LS是广义表的名称,n是它的长度,ai可以是单个元素,也可以是广义表,分别称为广义表LS的原子和子表。习惯上,用大写字母表示广义表的名称,小写字母表示原子。当广义表LS非空时,称第一个元素a1为LS的表头,称其余元素组成的表(a2, a3, ..., an)是LS的表尾。
下面列举一些广义表的例子:
1.A = () ---- A是一个空表,它的长度为0。
2.B = (e) ---- 列表B只有一个原子e,B的长度为1。
3.C = (a, (b, c, d)) ---- 列表C的长度为2,两个元素分别为原子a和子表(b, c, d)。
4.D = (A, B, C) ---- 列表D的长度为3,3个元素都是列表。显示,将子表的值代入后,则有D = ((), (e), (a, (b, c, d)))。
5.E = (a, E) ---- 这是一个递归的表,它的长度为2.E相当于一个无限的列表E = (a, (a, (a, ...)))。
下图为列表的图形表示:
从定义和例子可推出三个结论:
1)列表的元素可以是子表,而子表的元素还可以是子表。由此,列表是一个多层次的结构,可以用图形象地表示。
2)列表可为其它列表所共享。列表A,B和C为D的子表,则在D中可以不必列出子表的值。
3)列表可以是一个递归的表,即列表也可以是其本身的一个子表。例如列表E。
然后我们根据结论可知:
任何一个非空列表其表头可能是原子,也可能是列表,而其表尾必定为列表。
由于广义表中的数据元素可以具有不同的结构(或是原子,或是列表),因此难以用顺序存储结构表示,通常采用链式存储结构,每个数据元素可用一个结点表示。
下面是两种稍微不同的存储结构表示:
- var ATOM = 0;
- var LIST = 1;
- // 广义表的头尾链表存储表示
- function GLNode() {
- // 公共部分,用于区分原子结点和表结点
- this.tag = undefined;
- // atom是原子结点的值域
- this.atom = null;
- // ptr是表结点的指针域
- this.ptr = {
- // ptr.hp和ptr.tp分别指向表头和表尾
- hp: null,
- tp: null
- };
- }
- // 广义表的扩展线性链表存储表示
- function GLNode2() {
- // 公共部分,用于区分原子结点和表结点
- this.tag = undefined;
- // 原子结点的值域
- this.atom = null;
- // 表结点的表头指针
- this.hp = null;
- // 相当于线性链表的next,指向下一个元素结点
- this.tp = null;
- }
下列分别为两个存储结构的示例图:
1.GLNode
2.GLNode2
两种存储结构没有大的区别,可根据自己的习惯选择。
广义表的递归算法
我们知道递归定义的归纳项是用来描述如何实现从当前状态到终结状态的转化。
由于递归函数的设计用的是归纳思维的方法,则在设计递归函数时,应注意:
(1)首先应书写函数的首部和规格说明,严格定义函数的功能和接口(递归调用的界面),对求精函数中所得的和原问题性质相同的字问题,只要接口一致,便可进行递归调用。
(2)对函数中的每一个递归调用都看成只是一个简单的操作,只要接口一致,必能实现规格说明中定义的功能,切忌想得太深太远。
求广义表的深度
广义表的深度定义为广义表中括弧的重数,是广义表的一种量度。
设非空广义表为:
LS = (a1, a2, ..., an)
其中ai(i = 1, 2, ..., n)或为原子或为LS的子表,则求LS的深度可分解为n个子问题,每个子问题为求ai的深度,若ai是原子,则由定义其深度为零,若ai是广义表,则递归处理,而LS的深度为各ai(i = 1, 2, ..., n)的深度最大值加1.空表也是广义表,且深度为1.
广义表的深度DEPTH(LS)的递归定义为:
基本项: DEPTH(LS) = 1 当LS为空表时
DEPTH(LS) = 0 当LS为原子时
归纳项: DEPTH(LS) = 1 + MAX{DEPTH(ai)} 1 <= i <= n
下面为采用头尾链表存储结构,求广义表的深度的代码:
- // 采用头尾链表存储结构,求广义表的深度
- GLNode.prototype.depth = function () {
- return getDepth(this);
- };
- function getDepth(gList) {
- if (!gList) return 1;
- else if (gList.tag === ATOM) return 0;
- var m = getDepth(gList.ptr.hp) + 1;
- var n = getDepth(gList.ptr.tp);
- return m > n ? m : n;
- }
然后下面是广义表基本操作的代码(都是涉及到递归算法设计):
- // 复制广义表
- GLNode.prototype.copyList = function (gList) {
- gList.tag = this.tag;
- if (this.tag === ATOM) {
- gList.atom = this.atom;
- } else {
- if (this.ptr.hp) {
- gList.ptr.hp = new GLNode();
- this.copyList.call(this.ptr.hp, gList.ptr.hp);
- }
- if (this.ptr.tp) {
- gList.ptr.tp = new GLNode();
- this.copyList.call(this.ptr.tp, gList.ptr.tp);
- }
- }
- };
- function isWord(str){
- return /^[\w-]+$/.test(str);
- }
- // 采用头尾链表存储结构,由广义表的书写形式串创建广义表
- GLNode.prototype.createGList = function (string) {
- string = string.trim();
- // 创建单原子广义表
- var q;
- if (isWord(string)) {
- this.tag = ATOM;
- this.atom = string;
- } else {
- this.tag = LIST;
- var p = this;
- // 脱外层括号
- var sub = string.substr(1, string.length - 2);
- do {
- var hsub;
- var n = sub.length;
- var i = 0;
- var k = 0;
- var ch;
- do {
- ch = sub[i++];
- if (ch == '(') ++k;
- else if (ch == ')') --k;
- } while (i < n && (ch != ',' || k != 0));
- // i为第一个逗号分隔索引
- if (i < n) {
- hsub = sub.substr(0, i - 1);
- sub = sub.substr(i, n - i);
- // 最后一组
- } else {
- hsub = sub;
- sub = '';
- }
- if(hsub === '()')
- p.ptr.hp = null;
- else
- // 创建表头结点
- this.createGList.call((p.ptr.hp = new GLNode()), hsub);
- q = p;
- // 创建表尾结点
- if (sub) {
- p = new GLNode();
- p.tag = LIST;
- q.ptr.tp = p;
- }
- } while (sub);
- q.ptr.tp = null;
- }
- };
- var node = new GLNode();
- node.createGList('((), (ea), (sa, (bd, ce, dh)))');
- console.log(node.depth());
- GLNode.equal = function equal(gList1, gList2) {
- // 空表时相等的
- if (!gList1 && !gList2) return true;
- if (gList1.tag === ATOM && gList2.tag === ATOM && gList1.atom === gList2.atom) return true;
- if (gList1.tag === LIST && gList2.tag === LIST) {
- // 表头表尾都相等
- if (equal(gList1.ptr.hp, gList2.ptr.hp) && equal(gList1.ptr.tp, gList2.ptr.tp)) return true;
- }
- return false;
- };
- // 递归逆转广义表
- GLNode.prototype.reverse = function reverse() {
- var ptr = [];
- // 当A不为原子且表尾非空时才需逆转
- if (this.tag === LIST && this.ptr.tp) {
- for (var i = 0, p = this; p; p = p.ptr.tp, i++) {
- // 逆转各子表
- if (p.ptr.hp) reverse.call(p.ptr.hp);
- ptr[i] = p.ptr.hp;
- }
- // 重新按逆序排列各子表的顺序
- for (p = this; p; p = p.ptr.tp)
- p.ptr.hp = ptr[--i];
- }
- };
- var global = Function('return this')();
- GLNode.prototype.toString = function () {
- var str = '';
- if (this == global) str = '()';
- else if (this.tag === ATOM) str = this.atom; // 原子
- else {
- str += '(';
- for (var p = this; p; p = p.ptr.tp) {
- str += this.toString.call(p.ptr.hp);
- if (p.ptr.tp) str += ', ';
- }
- str += ')';
- }
- return str;
- };
- // 按层序输出广义表
- // 层序遍历的问题,一般都是借助队列来完成的,每次从队头
- // 取出一个元素的同时把它下一层的孩子插入队尾,这是层序遍历的基本思想
- GLNode.prototype.orderPrint = function(){
- var queue = [];
- for(var p = this; p; p = p.ptr.tp) queue.push(p);
- while(queue.length){
- var r = queue.shift();
- if(r.tag === ATOM) console.log(r.atom);
- else {
- for(r = r.ptr.hp; r; r = r.ptr.tp)
- queue.push(r);
- }
- }
- };
- // 使用链队列
- var Queue = require('../Queue/Queue.js').Queue;
- GLNode.prototype.orderPrint2 = function(){
- var queue = new Queue();
- for(var p = this; p; p = p.ptr.tp) queue.enQueue(p);
- while(queue.size){
- var r = queue.deQueue();
- if(r.tag === ATOM) console.log(r.atom);
- else {
- for(r = r.ptr.hp; r; r = r.ptr.tp)
- queue.enQueue(r);
- }
- }
- };
- console.log(node + '');
- node.reverse();
- console.log(node + '');
- var node2 = new GLNode();
- node.copyList(node2);
- console.log(GLNode.equal(node, node2));
- console.log(node + '');
- console.time('A');
- node.orderPrint();
- console.timeEnd('A');
- console.log('------------------------------------');
- console.time('B');
- node.orderPrint2();
- console.timeEnd('B');
广义表的运用:
m元多项式表示
如果用线性表来表示,则每个数据元素需要m+1个数据项,以存储一个系数和m个指数值,这将产生两个问题。
一是无论多项式中各项的变元数是多是少,若都按m个变元分配存储空间,则将造成浪费;反之,若按各项实际的变元数分配存储空间,就会造成结点的大小不匀,给操作带来不便。二是对m值不同的多项式,线性表中的结点大小也不同,这同样引起存储管理的不便。
故不适于用线性表表示。
例如三元多项式:
P(x, y, z) = x(10)y(3)z(2) + 2x(6)y(3)z(2) + 3x(5)y(2)z(2) + x(4)y(4)z + 2yz + 15
如若改写为:
P(x, y, z) = ((x(10) + 2x(6))y(3) + 3x(5)y(2))z(2) + ((x(4) + 6x(3))y(4) + 2y)z + 15
用广义表表示:
P = z((A, 2), (B, 1), (15, 0))
A = y((C, 3), (D, 2))
B = y((E, 4), (F, 1))
C = x((1, 10), (2, 6))
D = x((3, 5))
E = x((1, 4), (6, 3))
F = x((2, 0))
下面为用广义表描述m元多项式的存储结构:
- function MPNode() {
- // 区分原子结点和表结点
- this.tag = undefined;
- // 指数域
- this.exp = 0;
- // 系数域
- this.coef = 0;
- // 表结点的表头指针
- this.hp = null;
- // 相当于线性表的next,指向下一个元素结点
- this.tp = null;
- }
篇幅有限,就没有做其他操作,以后有空再补回吧。
所有代码:
- /**
- * 广义表
- *
- * 广义表是线性表的推广。广泛用于人工智能的表处理语言Lisp,把广义表作为基本的数据结构。
- * 广义表一般记作:
- * LS = (a1, a2, ..., an)
- * LS是广义表的名称,n是它的长度,ai可以是单个元素,也可以是广义表,分别称为广义表LS的原子和子表。习惯上,用大写字母表示广义表的名称,小写字母表示原子。当广义表LS非空时,称第一个元素a1为LS的表头,称其余元素组成的表(a2, a3, ..., an)是LS的表尾。
- *
- * 下面列举一些广义表的例子:
- * 1.A = () ---- A是一个空表,它的长度为0。
- * 2.B = (e) ---- 列表B只有一个原子e,B的长度为1。
- * 3.C = (a, (b, c, d)) ---- 列表C的长度为2,两个元素分别为原子a和子表(b, c, d)。
- * 4.D = (A, B, C) ---- 列表D的长度为3,3个元素都是列表。显示,将子表的值代入后,则有D = ((), (e), (a, (b, c, d)))。
- * 5.E = (a, E) ---- 这是一个递归的表,它的长度为2.E相当于一个无限的列表E = (a, (a, (a, ...)))。
- *
- * 1)列表的元素可以是子表,而子表的元素还可以是子表。由此,列表是一个多层次的结构,可以用图形象地表示。
- * 2)列表可为其它列表所共享。列表A,B和C为D的子表,则在D中可以不必列出子表的值。
- * 3)列表可以是一个递归的表,即列表也可以是其本身的一个子表。例如列表E。
- *
- * 任何一个非空列表其表头可能是原子,也可能是列表,而其表尾必定为列表。
- *
- */
- var ATOM = 0;
- var LIST = 1;
- // 广义表的头尾链表存储表示
- function GLNode() {
- // 公共部分,用于区分原子结点和表结点
- this.tag = undefined;
- // atom是原子结点的值域
- this.atom = null;
- // ptr是表结点的指针域
- this.ptr = {
- // ptr.hp和ptr.tp分别指向表头和表尾
- hp: null,
- tp: null
- };
- }
- // 广义表的扩展线性链表存储表示
- function GLNode2() {
- // 公共部分,用于区分原子结点和表结点
- this.tag = undefined;
- // 原子结点的值域
- this.atom = null;
- // 表结点的表头指针
- this.hp = null;
- // 相当于线性链表的next,指向下一个元素结点
- this.tp = null;
- }
- /*
- 广义表的递归算法
- 递归定义的归纳项描述了如何实现从当前状态到终结状态的转化。
- 由于递归函数的设计用的是归纳思维的方法,则在设计递归函数时,应注意:
- (1)首先应书写函数的首部和规格说明,严格定义函数的功能和接口(递归调用的界面),对求精函数中所得的和原问题性质相同的字问题,只要接口一致,便可进行递归调用。
- (2)对函数中的每一个递归调用都看成只是一个简单的操作,只要接口一致,必能实现规格说明中定义的功能,切忌想得太深太远。
- */
- /*
- 求广义表的深度
- 广义表的深度定义为广义表中括弧的重数,是广义表的一种量度。
- 设非空广义表为:
- LS = (a1, a2, ..., an)
- 其中ai(i = 1, 2, ..., n)或为原子或为LS的子表,则求LS的深度可分解为n个子问题,每个子问题为求ai的深度,若ai是原子,则由定义其深度为零,若ai是广义表,则递归处理,而LS的深度为各ai(i = 1, 2, ..., n)的深度最大值加1.空表也是广义表,且深度为1.
- 广义表的深度DEPTH(LS)的递归定义为:
- 基本项: DEPTH(LS) = 1 当LS为空表时
- DEPTH(LS) = 0 当LS为原子时
- 归纳项: DEPTH(LS) = 1 + MAX{DEPTH(ai)} 1 <= i <= n
- */
- // 采用头尾链表存储结构,求广义表的深度
- GLNode.prototype.depth = function () {
- return getDepth(this);
- };
- function getDepth(gList) {
- if (!gList) return 1;
- else if (gList.tag === ATOM) return 0;
- var m = getDepth(gList.ptr.hp) + 1;
- var n = getDepth(gList.ptr.tp);
- return m > n ? m : n;
- }
- // 复制广义表
- GLNode.prototype.copyList = function (gList) {
- gList.tag = this.tag;
- if (this.tag === ATOM) {
- gList.atom = this.atom;
- } else {
- if (this.ptr.hp) {
- gList.ptr.hp = new GLNode();
- this.copyList.call(this.ptr.hp, gList.ptr.hp);
- }
- if (this.ptr.tp) {
- gList.ptr.tp = new GLNode();
- this.copyList.call(this.ptr.tp, gList.ptr.tp);
- }
- }
- };
- function isWord(str){
- return /^[\w-]+$/.test(str);
- }
- // 采用头尾链表存储结构,由广义表的书写形式串创建广义表
- GLNode.prototype.createGList = function (string) {
- string = string.trim();
- // 创建单原子广义表
- var q;
- if (isWord(string)) {
- this.tag = ATOM;
- this.atom = string;
- } else {
- this.tag = LIST;
- var p = this;
- // 脱外层括号
- var sub = string.substr(1, string.length - 2);
- do {
- var hsub;
- var n = sub.length;
- var i = 0;
- var k = 0;
- var ch;
- do {
- ch = sub[i++];
- if (ch == '(') ++k;
- else if (ch == ')') --k;
- } while (i < n && (ch != ',' || k != 0));
- // i为第一个逗号分隔索引
- if (i < n) {
- hsub = sub.substr(0, i - 1);
- sub = sub.substr(i, n - i);
- // 最后一组
- } else {
- hsub = sub;
- sub = '';
- }
- if(hsub === '()')
- p.ptr.hp = null;
- else
- // 创建表头结点
- this.createGList.call((p.ptr.hp = new GLNode()), hsub);
- q = p;
- // 创建表尾结点
- if (sub) {
- p = new GLNode();
- p.tag = LIST;
- q.ptr.tp = p;
- }
- } while (sub);
- q.ptr.tp = null;
- }
- };
- var node = new GLNode();
- node.createGList('((), (ea), (sa, (bd, ce, dh)))');
- console.log(node.depth());
- GLNode.equal = function equal(gList1, gList2) {
- // 空表时相等的
- if (!gList1 && !gList2) return true;
- if (gList1.tag === ATOM && gList2.tag === ATOM && gList1.atom === gList2.atom) return true;
- if (gList1.tag === LIST && gList2.tag === LIST) {
- // 表头表尾都相等
- if (equal(gList1.ptr.hp, gList2.ptr.hp) && equal(gList1.ptr.tp, gList2.ptr.tp)) return true;
- }
- return false;
- };
- // 递归逆转广义表
- GLNode.prototype.reverse = function reverse() {
- var ptr = [];
- // 当A不为原子且表尾非空时才需逆转
- if (this.tag === LIST && this.ptr.tp) {
- for (var i = 0, p = this; p; p = p.ptr.tp, i++) {
- // 逆转各子表
- if (p.ptr.hp) reverse.call(p.ptr.hp);
- ptr[i] = p.ptr.hp;
- }
- // 重新按逆序排列各子表的顺序
- for (p = this; p; p = p.ptr.tp)
- p.ptr.hp = ptr[--i];
- }
- };
- var global = Function('return this')();
- GLNode.prototype.toString = function () {
- var str = '';
- if (this == global) str = '()';
- else if (this.tag === ATOM) str = this.atom; // 原子
- else {
- str += '(';
- for (var p = this; p; p = p.ptr.tp) {
- str += this.toString.call(p.ptr.hp);
- if (p.ptr.tp) str += ', ';
- }
- str += ')';
- }
- return str;
- };
- // 按层序输出广义表
- // 层序遍历的问题,一般都是借助队列来完成的,每次从队头
- // 取出一个元素的同时把它下一层的孩子插入队尾,这是层序遍历的基本思想
- GLNode.prototype.orderPrint = function(){
- var queue = [];
- for(var p = this; p; p = p.ptr.tp) queue.push(p);
- while(queue.length){
- var r = queue.shift();
- if(r.tag === ATOM) console.log(r.atom);
- else {
- for(r = r.ptr.hp; r; r = r.ptr.tp)
- queue.push(r);
- }
- }
- };
- // 使用链队列
- var Queue = require('../Queue/Queue.js').Queue;
- GLNode.prototype.orderPrint2 = function(){
- var queue = new Queue();
- for(var p = this; p; p = p.ptr.tp) queue.enQueue(p);
- while(queue.size){
- var r = queue.deQueue();
- if(r.tag === ATOM) console.log(r.atom);
- else {
- for(r = r.ptr.hp; r; r = r.ptr.tp)
- queue.enQueue(r);
- }
- }
- };
- console.log(node + '');
- node.reverse();
- console.log(node + '');
- var node2 = new GLNode();
- node.copyList(node2);
- console.log(GLNode.equal(node, node2));
- console.log(node + '');
- console.time('A');
- node.orderPrint();
- console.timeEnd('A');
- console.log('------------------------------------');
- console.time('B');
- node.orderPrint2();
- console.timeEnd('B');
- /*
- m元多项式表示
- 如果用线性表来表示,则每个数据元素需要m+1个数据项,以存储一个系数和m个指数值,这将产生两个问题。
- 一是无论多项式中各项的变元数是多是少,若都按m个变元分配存储空间,则将造成浪费;反之,若按各项实际的变元数分配存储空间,就会造成结点的大小不匀,给操作带来不便。二是对m值不同的多项式,线性表中的结点大小也不同,这同样引起存储管理的不便。
- 故不适于用线性表表示。
- 例如三元多项式:
- P(x, y, z) = x(10)y(3)z(2) + 2x(6)y(3)z(2) + 3x(5)y(2)z(2) + x(4)y(4)z + 2yz + 15
- 如若改写为:
- P(x, y, z) = ((x(10) + 2x(6))y(3) + 3x(5)y(2))z(2) + ((x(4) + 6x(3))y(4) + 2y)z + 15
- 用广义表表示:
- P = z((A, 2), (B, 1), (15, 0))
- A = y((C, 3), (D, 2))
- B = y((E, 4), (F, 1))
- C = x((1, 10), (2, 6))
- D = x((3, 5))
- E = x((1, 4), (6, 3))
- F = x((2, 0))
- */
- function MPNode() {
- // 区分原子结点和表结点
- this.tag = undefined;
- // 指数域
- this.exp = 0;
- // 系数域
- this.coef = 0;
- // 表结点的表头指针
- this.hp = null;
- // 相当于线性表的next,指向下一个元素结点
- this.tp = null;
- }
javascript实现数据结构:广义表的更多相关文章
- 【C/C++】实现数据结构广义表
1. 广义表的定义 每个元素可以为Atom,原子,也可以为线性表. 线性表的推广.线性表元素有唯一的前驱和后继,为线性表,而广义表是多层次的线性表 表头:第一个元素,可能是 ...
- 数据结构(C语言第2版)-----数组,广义表,树,图
任何一个算法的设计取决于选定的数据结构,而算法的实现依赖于采用的存储结构. 之前线性表的数据元素都是非结构的原子类型,元素的值是不可再分的.下面学习的这两个线性表是很特殊的,其中数据元素本身也可能是一 ...
- 数据结构算法C语言实现(十九)--- 5.5&5.6&5.7广义表
一.简述 传说Lisp的基本数据结构就是广义表,广义表也是具有典型递归属性的数据结构,此外,由于建表要处理字符串,用C语言处理起来也是一脸懵逼.....最后自己还想写一个将广义表还原成字符串的函数,一 ...
- 数据结构(C语言版)-第4章 串、数组和广义表
补充:C语言中常用的串运算 调用标准库函数 #include<string.h> 串比较,strcmp(char s1,char s2) 串复制,strcpy(char to,char f ...
- 数据结构:广义表的实现(Java)
广义表的简单理解在这篇博文中:https://blog.csdn.net/lishanleilixin/article/details/87364496,在此不做赘述. Java实现广义表: pack ...
- 数据结构28:广义表及M元多项式
广义表,又称为列表.记作: LS = (a1,a2,…,an) ;( LS 为广义表的名称, an 表示广义表中的数据). 广义表可以看作是线性表的推广.两者区别是:线性表中的数据元素只能表示单个数据 ...
- 数据结构之---C语言实现广义表头尾链表存储表示
//广义表的头尾链表存储表示 //杨鑫 #include <stdio.h> #include <malloc.h> #include <stdlib.h> #in ...
- 数据结构 c++ 广义表
// CTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include &l ...
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
随机推荐
- BZOJ 1324 Exca神剑 最小割
标题效果:给定一个n*m矩阵.所有的格宝石之子,人们可选择起始位置,后除去宝石的当前位置的周围消失,然后你就可以走两步,重复上述过程 easy发现格儿子把它周围格孩子不能拿 因此,党格访问问题 黑白染 ...
- cocos2d-x v3.2 FlappyBird 各个类对象详细代码分析(6)
今天我们要讲三个类,这三个类应该算比較简单的 HelpLayer类 NumberLayer类 GetLocalScore类 HelpLayer类,主要放了两个图形精灵上去,一个是游戏的名字,一个是提示 ...
- Cocos2d-x 单点触摸--让我们用手指动起来的精灵
转载请注明出处:http://blog.csdn.net/oyangyufu/article/details/25656673 效果图: CCTouch类装载了触摸点的信息.包含触摸点的横纵坐标值和触 ...
- Jsoup一个简短的引论——采用Java抓取网页数据
转载请注明出处:http://blog.csdn.net/allen315410/article/details/40115479 概述 jsoup 是一款Java 的HTML解析器,可直接解析某个U ...
- JAVA设计模式--辛格尔顿
Singleton模式可以作为一种编程技术,让我们先从理论上说代码 单例模式三个关键点: 1).某个类仅仅能有一个实例 2).该类必须自行创建这个实例 3).该类必须自行向整个系统提供这个实例 应用场 ...
- MVC的验证 jquery.validate.unobtrusive
jQuery validate 根据 asp.net MVC的验证提取简单快捷的验证方式(jquery.validate.unobtrusive.js) 2013-07-22 19:07 4568人阅 ...
- Akka 简介与入门
Akka 简介与入门 http://www.thinksaas.cn/group/topic/344095/ 参考官网 http://akka.io/ 开源代码 https://github.co ...
- JavaEE(24) - JAAS开发安全的应用
1. 安全域.角色和用户组 容器提供的两种安全性控制:声明式安全控制和编程式安全控制 安全域是指用户.用户组和ACL的逻辑集合.服务器支持的两种常用安全域:RDBMS安全域和文件系统安全域. 2. J ...
- JavaScript-2.2 document.write 输出到页面的内容
<html> <head> <meta http-equiv="content-type" content="text/html;chars ...
- JavaEE(12) - JPA规范及实现(TopLink和Hibernate)
1. JPA规范与ORM框架之间的联系 JPA规范并不属于EJB3规范,它是一套完全独立的规范,不仅可以在基于EJB的JavaEE应用程序中使用,而且完全可以在普通JavaSE应用程序中使用. JPA ...