数组、链表、Hash(转)
在程序中,存放指定的数据最常用的数据结构有两种:数组和链表。
数组和链表的区别:
1、数组是将元素在内存中连续存放。
链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。
2、数组必须事先定义固定的长度,不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。
链表动态地进行存储分配,可以适应数据动态地增减的情况。
3、(静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小。
链表从堆中分配空间, 自由度大但是申请管理比较麻烦。
数组和链表在存储数据方面到底孰优孰劣呢?根据数组和链表的特性,分两类情况讨论。
一、当进行数据查询时,数组可以直接通过下标迅速访问数组中的元素。而链表则需要从第一个元素开始一直找到需要的元素位置,显然,数组的查询效率会比链表的高。
二、当进行增加或删除元素时,在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样,如果想删除一个元素,需要移动大量元素去填掉被移动的元素。而链表只需改动元素中的指针即可实现增加或删除元素。
那么,我们开始思考:有什么方式既能够具备数组的快速查询的优点又能融合链表方便快捷的增加删除元素的优势?HASH呼之欲出。
所谓的hash,简单的说就是散列,即将输入的数据通过hash函数得到一个key值,输入的数据存储到数组中下标为key值的数组单元中去。
我们发现,不相同的数据通过hash函数得到相同的key值。这时候,就产生了hash冲突。解决hash冲突的方式有两种。一种是挂链式,也叫拉链法。挂链式的思想在产生冲突的hash地址指向一个链表,将具有相同的key值的数据存放到链表中。另一种是建立一个公共溢出区。将所有产生冲突的数据都存放到公共溢出区,也可以使问题解决。
如何实现hash的动态增加空间的效果?这和装在因子密切相关。装填因子 = 填入表中的元素个数 / 散列表的长度。当装填因子达到一定值a时,我们就让数组增加一定的内存空间,同时rehash。
下面用两个示例来加深理解。
示例一:用链表实现队列
节点类
- package cn.netjava.hash;
- public class LinkNode {
- //构造器:传入Object对象
- public LinkNode(Object obj){
- data=obj;
- }
- public Object data; //Object对象
- public LinkNode next;//下一个节点
- //重写toString方法
- public String toString(){
- //System.out.println(data);
- return (String)data;
- }
- //返回Object对象
- public Object getData(){
- return data;
- }
- //修改Onject对象
- public Object Update(Object o){
- data=o;
- return o;
- }
- }
package cn.netjava.hash;public class LinkNode {//构造器:传入Object对象public LinkNode(Object obj){data=obj;}public Object data; //Object对象public LinkNode next;//下一个节点//重写toString方法public String toString(){//System.out.println(data);return (String)data;}//返回Object对象public Object getData(){return data;}//修改Onject对象public Object Update(Object o){data=o;return o;}
}
队列类
- package cn.netjava.hash;
- public class LinkQueue {
- public LinkNode front=null;//第一个节点
- public LinkNode last=null;//最后一个节点
- public static void main(String args[]){
- LinkQueue lq=new LinkQueue();
- LinkNode lq1=new LinkNode("郑睿1");
- LinkNode lq2=new LinkNode("郑睿2");
- LinkNode lq3=new LinkNode("郑睿3");
- LinkNode lq4=new LinkNode("郑睿4");
- lq.InsertLinkNode(lq1);
- lq.InsertLinkNode(lq2);
- lq.InsertLinkNode(lq3);
- lq.InsertLinkNode(lq4);
- int count=lq.getLength();
- System.out.println("链表的长度为"+count);
- for(int i=0;i<count;i++){
- LinkNode ln = lq.getLinkNode(i);
- System.out.println("链表的第"+i+"个元素的的值为"+ln.getData().toString());
- }
- lq.deleteLinkNode(2);
- count=lq.getLength();
- System.out.println("链表现在的长度是"+lq.getLength());
- for(int i=0;i<count;i++){
- LinkNode ln = lq.getLinkNode(i);
- System.out.println("链表的第"+i+"个元素的的值为"+ln.getData().toString());
- }
- lq.getLinkNode(1).Update("更新后的对象郑睿");
- for(int i=0;i<count;i++){
- LinkNode ln = lq.getLinkNode(i);
- System.out.println("链表的第"+i+"个元素的的值为"+ln.getData().toString());
- }
- for(int i=0;i<200;i++){
- LinkNode ln = new LinkNode(i);
- lq.InsertLinkNode(ln);
- }
- System.out.println("数组长度为"+lq.getLength());
- }
- /**
- * 插入节点
- * @param obj:插入节点的对象
- */
- public void InsertLinkNode(Object obj){
- //当链表为空,新建一个节点并设置为第一个节点
- if(front==null){
- front=new LinkNode(obj);
- last=front;
- }
- //当链表不为空,新建一个节点并插入到最后一个节点的后面
- else{
- LinkNode next=new LinkNode(obj);
- last.next=next;
- last=next;
- }
- }
- /**
- *在指定索引下插入节点
- * @param index
- */
- public void insertIndexObj(int index,Object obj){
- //判断输入的索引是否越界,如果越界,则抛出异常
- int total=getLength();
- if(index>total||index<0)
- throw new java.lang.RuntimeException("输入的索引越界了!");
- LinkNode lNode=getLinkNode(index);
- LinkNode linkNode=new LinkNode(obj);
- lNode.insert(linkNode);
- }
- /**
- * 根据索引删除链表
- * @param index:索引
- */
- public void deleteLinkNode(int index){
- //判断输入的索引是否越界,如果越界,则抛出异常
- int total=getLength();
- if(index>total||index<0)
- throw new java.lang.RuntimeException("输入的索引越界了!");
- if(front!=null){
- LinkNode n=front;
- LinkNode m=front;
- int count=0;
- while(n!=null){
- if(count==index){
- if(n.equals(front)){
- front=front.next;
- }
- else{
- m.next=n.next;
- }
- }
- m=n;
- n=n.next;
- count++;
- }
- }
- }
- /**
- * 根据索引取出节点
- * @param lNode:节点
- * @return:根据索引返回的节点
- */
- public LinkNode getLinkNode(int index){
- if(front==null)
- return null;
- LinkNode l=front;
- int count=0;
- while(l!=null){
- if(count==index)
- return l;
- count++;
- l=l.next;
- }
- return null;
- }
- /**
- * 得到链表的长度
- * @return:链表的长度
- */
- public int getLength(){
- if(front==null)
- return 0;
- LinkNode l=front;
- int count=0;
- while(l!=null){
- count++;
- l=l.next;
- }
- return count;
- }
- /**
- * 修改对象节点
- * @param index:对象节点索引
- * @param obj:修改对象内容
- */
- public void UpdateLinkNode(int index,Object obj){
- LinkNode lNode=getLinkNode(index);
- lNode.Update(obj);
- }
- }
package cn.netjava.hash;public class LinkQueue {public LinkNode front=null;//第一个节点public LinkNode last=null;//最后一个节点public static void main(String args[]){LinkQueue lq=new LinkQueue();LinkNode lq1=new LinkNode("郑睿1");LinkNode lq2=new LinkNode("郑睿2");LinkNode lq3=new LinkNode("郑睿3");LinkNode lq4=new LinkNode("郑睿4");lq.InsertLinkNode(lq1);lq.InsertLinkNode(lq2);lq.InsertLinkNode(lq3);lq.InsertLinkNode(lq4);int count=lq.getLength();System.out.println("链表的长度为"+count);for(int i=0;i<count;i++){LinkNode ln = lq.getLinkNode(i);System.out.println("链表的第"+i+"个元素的的值为"+ln.getData().toString());}lq.deleteLinkNode(2);count=lq.getLength();System.out.println("链表现在的长度是"+lq.getLength());for(int i=0;i<count;i++){LinkNode ln = lq.getLinkNode(i);System.out.println("链表的第"+i+"个元素的的值为"+ln.getData().toString());}lq.getLinkNode(1).Update("更新后的对象郑睿");for(int i=0;i<count;i++){LinkNode ln = lq.getLinkNode(i);System.out.println("链表的第"+i+"个元素的的值为"+ln.getData().toString());}for(int i=0;i<200;i++){LinkNode ln = new LinkNode(i);lq.InsertLinkNode(ln);}System.out.println("数组长度为"+lq.getLength());}/*** 插入节点* @param obj:插入节点的对象*/public void InsertLinkNode(Object obj){//当链表为空,新建一个节点并设置为第一个节点if(front==null){front=new LinkNode(obj);last=front;}//当链表不为空,新建一个节点并插入到最后一个节点的后面else{LinkNode next=new LinkNode(obj);last.next=next;last=next;}}/***在指定索引下插入节点* @param index*/public void insertIndexObj(int index,Object obj){//判断输入的索引是否越界,如果越界,则抛出异常int total=getLength(); if(index>total||index<0)throw new java.lang.RuntimeException("输入的索引越界了!");LinkNode lNode=getLinkNode(index);LinkNode linkNode=new LinkNode(obj);lNode.insert(linkNode);}/*** 根据索引删除链表* @param index:索引*/public void deleteLinkNode(int index){//判断输入的索引是否越界,如果越界,则抛出异常int total=getLength(); if(index>total||index<0)throw new java.lang.RuntimeException("输入的索引越界了!");if(front!=null){LinkNode n=front;LinkNode m=front;int count=0;while(n!=null){if(count==index){if(n.equals(front)){front=front.next;}else{m.next=n.next;}}m=n;n=n.next;count++;}}}/*** 根据索引取出节点* @param lNode:节点* @return:根据索引返回的节点*/public LinkNode getLinkNode(int index){if(front==null)return null;LinkNode l=front;int count=0;while(l!=null){if(count==index)return l;count++;l=l.next;}return null;}/*** 得到链表的长度* @return:链表的长度*/public int getLength(){if(front==null)return 0;LinkNode l=front;int count=0;while(l!=null){count++;l=l.next;}return count;}/*** 修改对象节点* @param index:对象节点索引* @param obj:修改对象内容*/public void UpdateLinkNode(int index,Object obj){LinkNode lNode=getLinkNode(index);lNode.Update(obj);}
}
示例二:保存QQ号码及QQ用户
QQ用户类
- package cn.netjava.hash;
- public class QQUser {
- public String userName;//用户姓名
- public String passWord;//用户密码
- public String sex;//用户性别
- public int age;//用户年龄
- public String getUserName() {
- return userName;
- }
- public void setUserName(String userName) {
- this.userName = userName;
- }
- public String getPassWord() {
- return passWord;
- }
- public void setPassWord(String passWord) {
- this.passWord = passWord;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
package cn.netjava.hash;public class QQUser {public String userName;//用户姓名public String passWord;//用户密码public String sex;//用户性别public int age;//用户年龄public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
队列类
- package cn.netjava.hash;
- public class LinkQueue {
- public LinkNode front=null;//第一个节点
- public LinkNode last=null;//最后一个节点
- /**
- * 根据索引删除链表
- * @param index:索引
- */
- public void deleteLinkNode(int index){
- if(index<0||index>)
- if(front!=null){
- LinkNode n=front;
- LinkNode m=front;
- int count=0;
- while(n!=null){
- if(count==index){
- if(n.equals(front)){
- front=front.next;
- }
- else{
- m.next=n.next;
- }
- }
- m=n;
- n=n.next;
- count++;
- }
- }
- }
- /**
- * 根据索引取出节点
- * @param lNode:节点
- * @return:根据索引返回的节点
- */
- public LinkNode getLinkNode(int index){
- if(front==null)
- return null;
- LinkNode l=front;
- int count=0;
- while(l!=null){
- if(count==index)
- return l;
- count++;
- l=l.next;
- }
- return null;
- }
- /**
- * 得到链表的长度
- * @return:链表的长度
- */
- public int getLength(){
- if(front==null)
- return 0;
- LinkNode l=front;
- int count=0;
- while(l!=null){
- count++;
- l=l.next;
- }
- return count;
- }
- /**
- * 修改对象节点
- * @param index:对象节点索引
- * @param obj:修改对象内容
- */
- public void UpdateLinkNode(int index,Object obj){
- LinkNode lNode=getLinkNode(index);
- lNode.Update(obj);
- }
- }
package cn.netjava.hash;public class LinkQueue {public LinkNode front=null;//第一个节点public LinkNode last=null;//最后一个节点/*** 根据索引删除链表* @param index:索引*/public void deleteLinkNode(int index){if(index<0||index>)if(front!=null){LinkNode n=front;LinkNode m=front;int count=0;while(n!=null){if(count==index){if(n.equals(front)){front=front.next;}else{m.next=n.next;}}m=n;n=n.next;count++;}}}/*** 根据索引取出节点* @param lNode:节点* @return:根据索引返回的节点*/public LinkNode getLinkNode(int index){if(front==null)return null;LinkNode l=front;int count=0;while(l!=null){if(count==index)return l;count++;l=l.next;}return null;}/*** 得到链表的长度* @return:链表的长度*/public int getLength(){if(front==null)return 0;LinkNode l=front;int count=0;while(l!=null){count++;l=l.next;}return count;}/*** 修改对象节点* @param index:对象节点索引* @param obj:修改对象内容*/public void UpdateLinkNode(int index,Object obj){LinkNode lNode=getLinkNode(index);lNode.Update(obj);}
}
QQ节点类
- package cn.netjava.hash;
- public class QQNode {
- //构造器:传入QQ号,QQ用户对象
- public QQNode(int qq,QQUser user){
- this.qq=qq;
- this.user=user;
- }
- public int qq;//QQ号
- public QQUser user;//QQ用户
- public QQNode next;//下一个QQ节点对象
- public LinkQueue lq;//队列
- public LinkQueue getLq() {
- return lq;
- }
- public void setLq(LinkQueue lq) {
- this.lq = lq;
- }
- public int getQq() {
- return qq;
- }
- public void setQq(int qq) {
- this.qq = qq;
- }
- public QQUser getUser() {
- return user;
- }
- public void setUser(QQUser user) {
- this.user = user;
- }
- public QQNode getNext() {
- return next;
- }
- public void setNext(QQNode next) {
- this.next = next;
- }
- }
package cn.netjava.hash;public class QQNode {//构造器:传入QQ号,QQ用户对象public QQNode(int qq,QQUser user){this.qq=qq;this.user=user;}public int qq;//QQ号public QQUser user;//QQ用户public QQNode next;//下一个QQ节点对象public LinkQueue lq;//队列public LinkQueue getLq() {return lq;}public void setLq(LinkQueue lq) {this.lq = lq;}public int getQq() {return qq;}public void setQq(int qq) {this.qq = qq;}public QQUser getUser() {return user;}public void setUser(QQUser user) {this.user = user;}public QQNode getNext() {return next;}public void setNext(QQNode next) {this.next = next;}}
Hash方法类
- package cn.netjava.hash;
- public class QQHash {
- private QQNode[] table=new QQNode[100];
- private float load=0.75F;//装载因子
- private int count=0;
- private int gain=100;
- public static void main(String args[]){
- QQHash qqHash=new QQHash();
- QQUser user1=new QQUser();
- user1.setUserName("用户一");
- user1.setPassWord("1");
- user1.setAge(20);
- user1.setSex("女");
- qqHash.put(1, user1);
- QQUser user2=new QQUser();
- user2.setUserName("用户二");
- user2.setPassWord("12");
- user2.setAge(20);
- user2.setSex("男");
- qqHash.put(2, user2);
- QQUser user3=new QQUser();
- user3.setUserName("用户三");
- user3.setPassWord("123");
- user3.setAge(20);
- user3.setSex("男");
- qqHash.put(3, user3);
- QQUser user4=new QQUser();
- user4.setUserName("用户四");
- user4.setPassWord("1234");
- user4.setAge(20);
- user4.setSex("女");
- qqHash.put(101, user4);
- qqHash.returnQQNode();
- user1=qqHash.get(1);
- user2=qqHash.get(2);
- user3=qqHash.get(3);
- user4=qqHash.get(101);
- QQNode[] table=qqHash.returnQQNode();
- // System.out.println("表的长度为 "+table.length);
- qqHash.returnTabLen();
- for(int i=0;i<table.length;i++){
- if(table[i]!=null){
- System.out.println("实际存在的Table["+i+"]的值"+table[i].getQq());
- LinkQueue lq=table[i].getLq();
- if(lq.getLength()>0){
- System.out.println("存在挂链");
- for(int j=0;j<lq.getLength();j++)
- System.out.println("挂链第"+i+"个值为"+((QQNode)lq.getLinkNode(i).getData()).getUser().getUserName());
- }
- }
- }
- }
- /**
- * 存放QQ及用户
- * @param qq:QQ号
- * @param user:QQ用户
- */
- public void put(int qq,QQUser user){
- //判断己放对象的个数和table的长度比是否达到装载因子,
- //如果超过,则reHash一次,增长,
- //然后再放!
- float rate=(float)count/table.length;
- if(rate>=load){
- QQNode[] table1=new QQNode[table.length+gain];
- for(int i=0;i<table.length;i++){
- QQNode q=table[i];
- int qqnum=q.getQq();
- QQUser u=q.getUser();
- int qqhash=hashQQ(qqnum);
- q.setQq(qqnum);
- q.setUser(user);
- table1[qqhash]=q;
- }
- table=table1;
- }
- System.out.println("table长度:"+table.length);
- //判断是否存在hash冲突
- boolean judge=exist(qq);
- System.out.println("是否存在冲突"+judge);
- int index=hashQQ(qq);
- System.out.println("hash值"+index);
- if(judge){//不存在hash冲突,直接将qq和用户存放在通过hash函数获得的地址中
- QQNode q=new QQNode(qq,user);
- q.setQq(qq);
- q.setUser(user);
- table[index]=q;
- count++;
- }
- else{//存在hash冲突
- QQNode q=new QQNode(qq,user);
- q.setQq(qq);
- q.setUser(user);
- System.out.println(" "+q.getQq()+" "+q.getUser());
- LinkQueue lq=q.getLq();
- lq.InsertLinkNode(q);
- for(int i=0;i<lq.getLength();i++)
- System.out.println("======"+((QQNode)lq.getLinkNode(i).getData()).getQq());
- if(lq.getLength()==0){
- table[index].setNext(q);
- }
- }
- }
- /**
- * 根据QQ号取得QQ用户信息
- * @param qq:QQ号
- * @return:QQ用户
- */
- public QQUser get(int qq){
- int index=hashQQ(qq);
- QQNode q=table[index];
- System.out.println("节点"+q.getQq());
- //看是否有下了个节点,如有,则是冲突的,就要一个一个比较
- if(q.next==null)
- return q.getUser();
- LinkQueue lq=q.getLq();
- for(int i=0;i<lq.getLength();i++){
- QQNode aa=(QQNode)lq.getLinkNode(i).data;
- int qqq=aa.getQq();
- if(qqq==qq)
- System.out.println("查找到了!");
- return aa.getUser();
- }
- return null;
- }
- //计算QQ号的has值,自定义has函数
- private int hashQQ(int qq){
- return qq%table.length;
- }
- //判断是否存在hash冲突
- private boolean exist(int qq){
- int qqhash=hashQQ(qq);
- if(table[qqhash]!=null)
- return false;
- return true;
- }
- //返回表
- private QQNode[] returnQQNode(){
- System.out.println("已存在数据个数为"+count);
- return this.table;
- }
- //返回表中实际存在的数据的个数
- private int returnTabLen(){
- return this.count;
- }
- }
http://1029975378-qq-com.iteye.com/blog/814552
转载于:https://www.cnblogs.com/softidea/p/4819875.html
数组、链表、Hash(转)相关推荐
- 用链表和数组实现HASH表,几种碰撞冲突解决方法
Hash算法中要解决一个碰撞冲突的办法,后文中描述了几种解决方法.下面代码中用的是链式地址法,就是用链表和数组实现HASH表. he/*hash table max size*/ #define HA ...
- C语言哈希表的简单实现——数组+链表(拉链法)
C语言哈希表的简单实现--数组+链表(拉链法) 1.哈希表简介 哈希表详细介绍可以参考这篇文章 2.哈希表拉链法实现 2.1完全由本人思路实现,如有错误,欢迎批评指正 哈希声明文件hash.h /* ...
- 【Java8】堆栈/队列/数组/链表/红黑树,List/set子接口,hashcode/hashset,Map/内部接口,/统计字符个数,debug,斗地主,Collections,TreeSet
文章目录 1.堆栈/队列/数组/链表:数据结构即计算机组织管理数据的方式,堆栈指的是内存图中的栈,不是堆 2.红黑树:二查,二查平,二查平1倍 3.List子接口:集合,IndexOutOfBound ...
- 存数组元素的个数_HashMap1.8之后为什么要采用数组+链表+红黑树的储存方式?
HashMap概述 HashMap是基于Map接口实现的,采取(key,value)的储存方式.其中key和value可以为空,但是key不能重复.下面我们来详细解读一下HashMap的底层实现原理. ...
- 常见数据结构和算法实现(排序/查找/数组/链表/栈/队列/树/递归/海量数据处理/图/位图/Java版数据结构)
常见数据结构和算法实现(排序/查找/数组/链表/栈/队列/树/递归/海量数据处理/图/位图/Java版数据结构) 数据结构和算法作为程序员的基本功,一定得稳扎稳打的学习,我们常见的框架底层就是各类数据 ...
- 常见的数据结构:栈 队列 数组 链表 红黑树——List集合 _ HashSet集合、可变参数 collections集合 Map集合
2021-06-07复习java 一.常见的数据结构 栈(先进后出) 队列 数组 链表 红黑树 二.List集合_介绍&常用方法 ArrayList集合 Linkedlist集合 三.Hash ...
- 哈希表(散列表_Hashtable)_数组+链表_代码实现员工管理
1.基本介绍 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映 ...
- Perl数组和hash相关函数
Perl数组和hash相关函数 内置的数组函数有: each, keys, pop, push, shift, splice, unshift, values 内置的hash函数有: delete, ...
- VIjos 晴天小猪历险记之Number (搜索+链表hash)
背景 话说上一回,晴天小猪不畏千难万险.千辛万苦.千磨万难--终于爬上了那座深山,来到了那位隐者的小屋中,但它不知道,有一个问题正等待着它-- 晴天小猪一推开门,就发现那里--空无一人?但在屋中央有一 ...
- Perl匿名数组、hash和autovivification特性
可有构建匿名的对象,这样就没必要去为只用一两次的数组.hash去取名字,有时候取名是很烦的事. 使用中括号[]构建匿名数组 使用大括号{}构建匿名hash 不包含任何元素的[]和{}分别是匿名空数组. ...
最新文章
- LeetCode简单题之最后一块石头的重量
- 谢尔排序/缩减增量排序(C++)
- python与excel结合-python3与Excel的完美结合
- Eclipse调试Android开发工具ADB
- Linux下安装Redis并添加PHP扩展(自己测试了没有问题)
- 企业级应用架构(三)三层架构之数据访问层的改进以及测试DOM的发布
- php xml 返回 微信,php版微信返回用户text输入的方法
- php二级评论怎么实现,ThinkPHP视图模型实现二级嵌套评论的查询
- poj 3624 Charm Bracelet (01背包)
- java 临时文件 删除_Java临时文件何时被删除?
- PHP常用函数归类总结【大全】
- 小米手机电池测试软件哪个比较好,教你查看小米8电池损耗
- StandUp 定时休息软件
- epoch - iteration - batch
- MiniGUI移植过程
- [转]电烙铁的使用小技巧
- 可恶的as3.0,下载一个所谓的绿色flash cs5,竟然提示JAVA运行时环境初始化错误,请重新安flash
- 30个HTML+CSS前端开发案例(一)
- discuz X2转帖工具、采集工具 使用介绍(原创)
- 在鼠标右键添加“使用WPS打开”
热门文章
- 记录一次读取hdfs文件时出现的问题java.net.ConnectException: Connection refused
- Linux操作oracle——关闭、停止、重启
- C# 连接数据库 Sql Server
- border-raduis 在IE8中的兼容性问题
- 双人五子棋对战(需要EasyX图像库)
- BZOJ1503 [NOI2004]郁闷的出纳员
- 【LeetCode】53.最大子序和
- testng 定时构建_Jenkins使用安装:持续集成自动化方案 | Web自动化测试方案
- sas和python哪个更容易_我该选择谁?SAS VS Python
- 多因素方差分析_方差分析入门