一.堆栈
堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。要点:
堆:顺序随意 ;栈:后进先出(Last-In/First-Out)
题目:实现一个栈操作,将1`12月的英文单词压入栈中,然后将其取出,使用Java代码实现.
public class Stacks {
static String[] months = { "A", "B", "C", "D", "E", "F", "G" };
public static void main(String[] args) {
Stack stack = new Stack<>();// 新建一个栈
for (int i = 0; i < months.length; i++) {
stack.push(months[i]);// 将元素一个个放进去
}
System.out.println(stack);
while (!stack.empty()) {
System.out.println(stack.pop());//将元素拿出来出来
}
}
}
二.链表与哈希表
存储结构分为以下几种:
(1)随机存取
即可以随机存取任意一个元素,可以通过下标直接存取任何一个元素如数组等:又如内存,可以通过地址访问任意一个元素
(2)顺序存储
就是只能从头到尾逐个访问.像连表这种结构.不能够直接通过下标访问,必须从表头开始,向后逐个搜索,就是顺序存储.这和磁带一样,想听后边的歌曲,就得把前面的磁带转过去,按照顺序来
(3)索引存取
是指为某个关键字建立索引表,从所有的表中得到地址,再直接访问.索引存取多用于数据管理过程中
(4)散列存储
也称为hash存储
这个可能比较陌生,那么来通俗理解下
设要存储对象的个数为num, 那么我们就用len个内存单元来存储它们(len>=num); 以每个对象ki的关键字为自变量,用一个函数h(ki)来映射出ki的内存地址,也就是ki的下标,将ki对象的元素内容全部存入这个地址中就行了。这个就是Hash的基本思路。
Hash为什么这么想呢?换言之,为什么要用一个函数来映射出它们的地址单元呢?
This is a good question.明白了这个问题,Hash不再是问题。下面我就通俗易懂地向你来解答一下这个问题。
现在我要存储4个元素 13 7 14 11
显然,我们可以用数组来存。也就是:a[1] = 13; a[2] = 7; a[3] = 14; a[4] = 11;
当然,我们也可以用Hash来存。下面给出一个简单的Hash存储:
先来确定那个函数。我们就用h(ki) = ki%5;(这个函数不用纠结,我们现在的目的是了解为什么要有这么一个函数)。
对于第一个元素 h(13) = 13%5 = 3; 也就是说13的下标为3;即Hash[3] = 13;
对于第二个元素 h(7) = 7 % 5 = 2; 也就是说7的下标为2; 即Hash[2] = 7;
同理,Hash[4] = 14; Hash[1] = 11;
好了,存现在是存好了。但是,这并没有体现出Hash的妙处,也没有回答刚才的问题。下面就来揭开它神秘的面纱吧。
现在我要你查找11这个元素是否存在。你会怎么做呢?当然,对于数组来说,那是相当的简单,一个for循环就可以了。
也就是说我们要找4次。
下面我们来用Hash找一下。
首先,我们将要找的元素11代入刚才的函数中来映射出它所在的地址单元。也就是h(11) = 11%5 = 1 了。下面我们来比较一下Hash[1]?=11, 这个问题就很简单了。也就是说我们就找了1次。这个就是Hash的妙处了。至此,刚才的问题也就得到了解答。至此,你也就彻底的明白了Hash了。
题目:有一千万条重复的短信,以文本形式保存,一行一条,也有重复.请用5分钟时间找出重复出现最多的前十条短信
分析:
刚开始肯定会冒出导入数据库,然后用select语句进行查找.但是你再仔细想想这个可是一千万条数据,全部导入后都不止5分钟了,你还要建立索引啥的.
可以采用内存映射办法.首先,一千万条短信长度将不会超过1内存空间,使用内存映射文件比较合适.可以一次映射(如果有更大的数据量,可以采用分段映射),由于不需要频繁使用文件I/O和频繁分配内存大小,这将大大提高了数据的加载速度.其次,对每条短信的第i(i从0到70)个字母按照ASCII码进行分组,也就是创建树.i是树的深度也是短信的第i个字母
三,树
题目:前序遍历二叉树值为abcdefg,下面哪一个不可能是中序遍历?
A.abcdefg B.gfedcba C.bcdefga D.bceadfg
二叉树遍历原则,前序遍历是根左右,中序遍历是左根右,后序遍历是左右根。
题目既然说前序遍历abcdefg,所以根为a,D中bce在左,dfg在右,显然与先序遍历冲突
二叉树遍历分析
简单二叉树遍历,可分为:先序,中序,后序。
在此分别总结先序,中序,后序的结点输出顺序。
先序: 1.访问根结点
2.访问左子树
3.访问右子树
先序较简单,不予以即系解释。
中序:1.访问左子树
2.访问根结点
3.访问右子树
原则:访问左子树。【先访问左子树中的左子树,再访问左子树中的右子树。】直到访问到叶子结点后输出。
输出根。
访问右子树。【先访问右子树中的左子树,再访问右子树中的右子树。】直到访问到叶子结点后输出。
具体步骤如下:
A作为根。从A开始,先访问A的左子树。即。
在看B的左子树,D。则输出D。B无左子树。访问完B的左子树。然后访问B。输出B。再看B的右子树。F有左子树E,则输出E。返回输出F。A的左子树全部输出完,再返回A,输出A。
同理,看A的右子树。。输出顺序为G,H,C,I。
所以,中序遍历输出的结果为:(D B E F)A(G H C I).
后序:1.访问左子树
2.访问右子树
3.访问根
原则:访问左子树。【先访问左子树中的左子树,再访问左子树中的右子树】。直到访问到叶子结点后输出。
访问右子树。【先访问右子树中的左子树,再访问右子树中的右子树】。直到访问到叶子结点后输出。
再返回访问根,并输出。
具体步骤:
先访问A的左子树。再访问左子树中的左子树。【即:A的左子树为B,再访问B的左子树D。D没有左右子树,输出D。】,然后访问左子树中的右子树。【即:访问B的右子树F,F还有左子树,再访问F的左子树E,E没有左右子树。输出E。再输出F,再输出B。】。
然后访问A的右子树。再访问右子树中的左子树。【即:A的右子树为C,再访问C的左子树G。G还有右子树H,输出H。再输出G,再输出G】,然后访问右子树中的右子树。【即:访问C的右子树I,I没有左右子树,输出I。在输出C。再输出A。】。
所以,后序遍历输出结果为:(D E F B)(H G I C)A
一个包含n个节点的四叉树,每一个结点都有4个指向该节点的指针,这个四叉树有_个空指针
分析:n个节点有n-1个非空指针,其余为空指针、4*n-(n-1)