布谷鸟散列
1、接口
package com;
public interface HashFamily<AnyType> {
int hash(AnyType a,int which);
int getNumberOfFunctions();
void generateNewFunction();
}
2、接口实现
package com;
import java.util.Random;
public class StringHashFamily implements HashFamily<String>{
private final int[] MUTLIPLIERS;
private final Random r = new Random();
public StringHashFamily(int size) {
MUTLIPLIERS = new int[size];
generateNewFunction();
}
@Override
public int getNumberOfFunctions() {
return MUTLIPLIERS.length;
}
@Override
public void generateNewFunction() {
for (int i = 0; i < MUTLIPLIERS.length; i++)
MUTLIPLIERS[i] = r.nextInt();
}
@Override
public int hash(String e, int which) {
final int mutliplier = MUTLIPLIERS[which];
int hashVal = 0;
for (int i = 0; i < e.length(); i++)
hashVal = mutliplier * hashVal + e.charAt(i);
return hashVal;
}
}
3、布谷鸟散列实现
package com;
import java.util.Random;
public class CuckooHashTable<AnyType> {
private static final double MAX_LOAD=0.4;
private static final int ALLOWED_REHASHES=1;
private static final int DEFAULT_TABLE_SIZE=101;
private final HashFamily<? super AnyType> hashFunctions;
private final int numHashFunctions;
private AnyType[] array;
private int currentSize;
public CuckooHashTable(HashFamily<? super AnyType> hf){
this(hf,DEFAULT_TABLE_SIZE);
}
public CuckooHashTable(HashFamily<? super AnyType> hf,int size){
allocateArray(nextPrime(size));
doClear();
hashFunctions=hf;
numHashFunctions=hf.getNumberOfFunctions();
}
public void makeEmpty(){
doClear();
}
public boolean contains(AnyType a){
return findPos(a)!=-1;
}
public boolean remove(AnyType a){
int pos = findPos(a);
if(pos!=-1){
array[pos]=null;
currentSize--;
}
return pos!=-1;
}
public boolean insert(AnyType a){
if(contains(a)){
return false;
}
if(currentSize>=array.length*MAX_LOAD){
expand();
}
return insertHelperl(a);
}
private int rehashs=0;
private Random r=new Random();
/**
* 布谷鸟的核心方法应该就是这个,大致谢谢自己的理解
* ①根据闯过来的值numHashFunctions遍历查找插入位置,先假设查找的位置上都有了元素
* ②通过随机数找一个位置,把里边的数赶出来,自己进去,像布谷鸟一样
* ③被赶出来的数,循环找到他的插入位置。
* ④如果实在是查找不到插入的位置,进行扩容,再试。
* @param a
* @return
*/
private boolean insertHelperl(AnyType a) {
final int COUNT_LIMIT=100;
while(true){
int lastPos=-1;
int pos;
for (int count = 0; count < COUNT_LIMIT; count++) {
for (int i = 0; i < numHashFunctions; i++) {
pos=myhash(a, i);
if(array[pos]==null){
array[pos]=a;
currentSize++;
return true;
}
}
int i=0;
do {
pos=myhash(a, r.nextInt(numHashFunctions));
} while (pos==lastPos && i++<5);
AnyType tmp = array[lastPos=pos];
array[pos]=a;
a=tmp;
}
if(++rehashs>ALLOWED_REHASHES){
expand();
rehashs=0;
}else{
rehash();
}
}
}
private void expand() {
rehash((int)(array.length/MAX_LOAD));
}
private void rehash(){
hashFunctions.generateNewFunction();
rehash(array.length);
}
private void rehash(int length) {
AnyType[] oldArray = array;
allocateArray(nextPrime(length));
currentSize=0;
for (AnyType a : oldArray) {
if(a!=null){
insert(a);
}
}
}
private int findPos(AnyType a){
for (int i = 0; i < numHashFunctions; i++) {
int pos=myhash(a, i);
if(array[pos]!=null && array[pos].equals(a)){
return pos;
}
}
return -1;
}
private int myhash(AnyType a,int which){
int hashVal = hashFunctions.hash(a, which);
hashVal%=array.length;
if(hashVal<0){
hashVal+=array.length;
}
return hashVal;
}
private void allocateArray(int nextPrime) {
array=(AnyType[]) new Object[nextPrime];
}
private void doClear(){
currentSize=0;
for (int i = 0; i < array.length; i++) {
array[i]=null;
}
}
private boolean isPrime(int num){
if(num==2 || num==3){
return true;
}
if(num%6!=1 && num%6!=5){
return false;
}
for (int i = 5; i*i<=num; i+=6) {
if(num%i==0 || num%(i+2)==0){
return false;
}
}
return true;
}
private int nextPrime(int n){
boolean state = isPrime(n);
while(!state){
state=isPrime(++n);
}
return n;
}
public static void main(String[] args) {
CuckooHashTable<String> a = new CuckooHashTable<>(new StringHashFamily(3));
a.insert("1");
a.insert("2");
a.insert("3");
a.insert("3");
a.remove("1");
System.out.println();
}
}
二叉堆
*结构特性:数组任意位置 i 的元素,其左儿子 2i 其右儿子 2i+1 其父节点 i/2,通过数组就可以显示二叉堆。不需要通过链表
*堆序特性:在一个堆中,对于一个节点X,X的父节点总是小于等于节点X。根节点除外
package com;
/**
* 通配符的解释:
* 通过extends指定上界通配符:传入的数据类型必须实现comparable接口
* 通过super指定了下界通配符:Compable中类型可以是传入的AnyType或者是其父类
* @author Administrator
*
* @param <AnyType>
*/
public class BinaryHeap<AnyType extends Comparable<? super AnyType>>{
private static final int DEFAULT_CAPACITY=10;
private int currentSize;
private AnyType[] array;
public BinaryHeap(){
currentSize=0;
array=(AnyType[]) new Comparable[DEFAULT_CAPACITY];
}
public BinaryHeap(int capacity){
currentSize=0;
array=(AnyType[]) new Comparable[capacity];
}
public BinaryHeap(AnyType[] items){
currentSize=items.length;
array=(AnyType[]) new Comparable[(currentSize+2)*11/10];
int i=1;
for (AnyType a : items) {
array[i++]=a;
}
buildHeap();
}
private void buildHeap() {
for(int i=currentSize/2;i>0;i--){
percolateDown(i);
}
}
/**
* 这里是核心方法,但是理解不了先放下来。
* @param hole
*/
private void percolateDown(int hole) {
int child;
AnyType tmp = array[hole];
for(;hole*2<=currentSize;hole=child){
child=hole*2;
if(child!=currentSize && array[child+1].compareTo(array[child])<0){
child++;
}
if(array[child].compareTo(tmp)<0){
array[hole]=array[child];
}else{
break;
}
}
array[hole]=tmp;
}
public void insert(AnyType a){
if(currentSize==array.length-1){
enlargeArray(array.length*2+1);
}
int hole=++currentSize;
for(;hole>1 && a.compareTo(array[hole/2])<0;hole/=2){
array[hole]=array[hole/2];
}
array[hole]=a;
}
private void enlargeArray(int size) {
AnyType[] oldArray=array;
array=(AnyType[]) new Comparable[size];
for(int i=1;i<=currentSize;i++){
array[i]=oldArray[i];
}
}
public AnyType findMin(){
return currentSize>0?array[1]:null;
}
public boolean isEmpty(){
return currentSize==0;
}
public void makeEmpty(){
currentSize=0;
array=(AnyType[]) new Comparable[DEFAULT_CAPACITY];
}
public AnyType deleteMin(){
AnyType a = findMin();
array[1]=array[currentSize--];
percolateDown(1);
array[currentSize+1]=null;
return a;
}
public static void main(String[] args) {
Integer[] a={6,4,3,2,8,9,5};
BinaryHeap<Integer> b = new BinaryHeap<>(a);
b.insert(10);
b.insert(7);
b.insert(1);
b.deleteMin();
b.deleteMin();
Integer f = b.deleteMin();
b.makeEmpty();
System.out.println(f);
}
}
左式堆:左式堆的混合其实很好理解,只要分析清楚,代码实现很简单。
package com;
public class LeftistHeap<AnyType extends Comparable<? super AnyType>>{
private Node<AnyType> root;
public LeftistHeap(){
this.root=null;
}
public void merge(LeftistHeap<AnyType> rhs){
if(this==rhs){
return;
}
root=merge(root,rhs.root);
rhs.root=null;
}
public void insert(AnyType a){
root=merge(new Node(a),root);
}
public AnyType findMin(){
return root.element;
}
public AnyType deleteMin(){
AnyType min = root.element;
root=merge(root.left,root.right);
return min;
}
private Node<AnyType> merge(Node<AnyType> h1, Node<AnyType> h2) {
if(h1==null){
return h2;
}
if(h2==null){
return h1;
}
if(h1.element.compareTo(h2.element)<0){
return merge1(h1,h2);
}else{
return merge1(h2,h1);
}
}
private Node<AnyType> merge1(Node<AnyType> h1, Node<AnyType> h2) {
if(h1.left==null){
h1.left=h2;
}else{
h1.right=merge(h1.right,h2);
if(h1.left.npl<h1.right.npl){
swapChildren(h1);
}
h1.npl=h1.right.npl+1;
}
return h1;
}
private void swapChildren(Node<AnyType> h1) {
Node<AnyType> tmp=h1.left;
h1.left=h1.right;
h1.right=tmp;
}
public void makeEmpty(){
root=null;
}
public boolean isEmpty(){
return root==null;
}
private static class Node<AnyType>{
AnyType element;
Node<AnyType> left;
Node<AnyType> right;
int npl;
Node(AnyType a,Node<AnyType> l,Node<AnyType> r){
this.element=a;
this.left=l;
this.right=r;
npl=0;
}
Node(AnyType a){
this(a,null,null);
}
}
}
二项队列
package com;
public class BinomiaQueue<AnyType extends Comparable<? super AnyType>> {
private static final int DEFAULT_TREES=1;
private int currentSize;
private Node<AnyType>[] theTrees;
public BinomiaQueue(){
theTrees = new Node[DEFAULT_TREES];
}
public BinomiaQueue(AnyType a){
this();
theTrees[0]=new Node(a);
currentSize=1;
}
public void merge(BinomiaQueue<AnyType> rhs){
if(rhs==null){
return;
}
currentSize+=rhs.currentSize;
if(currentSize>capacity()){
int maxLength=Math.max(theTrees.length, rhs.theTrees.length);
expandTheTrees(maxLength+1);
}
Node<AnyType> carry=null;
for(int i=0,j=1;j<=currentSize;i++,j*=2){
Node<AnyType> t1=theTrees[i];
Node<AnyType> t2=i<rhs.theTrees.length?rhs.theTrees[i]:null;
int whichCase=t1==null?0:1;
whichCase+=t2==null?0:2;
whichCase+=carry==null?0:4;
switch(whichCase){
case 0:
case 1:
break;
case 2:
theTrees[i]=t2;
rhs.theTrees[i]=null;
break;
case 4:
theTrees[i]=carry;
carry=null;
break;
case 3:
carry=combineTrees(t1,t2);
theTrees[i]=rhs.theTrees[i]=null;
break;
case 5:
carry=combineTrees(t1, carry);
theTrees[i]=null;
break;
case 6:
carry=combineTrees(t2, carry);
rhs.theTrees[i]=null;
break;
case 7:
theTrees[i]=carry;
carry=combineTrees(t1, t2);
rhs.theTrees[i]=null;
break;
}
}
for(int i=0;i<rhs.theTrees.length-1;i++){
rhs.theTrees[i]=null;
}
rhs.currentSize=0;
}
public void insert(AnyType a){
merge(new BinomiaQueue<>(a));
}
public AnyType findMin(){
AnyType min=theTrees[0].element;
for(int i=1;i<theTrees.length;i++){
Node<AnyType> node=theTrees[i];
if(node!=null && min.compareTo(node.element)>0){
min=theTrees[i].element;
}
}
return min;
}
private int findMinIndex(){
AnyType min = findMin();
for(int i=0;i<theTrees.length;i++){
Node<AnyType> node=theTrees[i];
if(node!=null && node.element.compareTo(min)==0){
return i;
}
}
return -1;
}
public boolean isEmpty(){
return currentSize==0;
}
public AnyType deleteMin(){
int minIndex = findMinIndex();
AnyType minItem=theTrees[minIndex].element;
Node<AnyType> deleteTree=theTrees[minIndex].leftChild;
BinomiaQueue<AnyType> deleteQueue=new BinomiaQueue<>();
deleteQueue.expandTheTrees(minIndex+1);
deleteQueue.currentSize=(1<<minIndex)-1;
for(int j=minIndex-1;j>=0;j--){
deleteQueue.theTrees[j]=deleteTree;
deleteTree=deleteTree.nextSibling;
deleteQueue.theTrees[j].nextSibling=null;
}
theTrees[minIndex]=null;
currentSize-=deleteQueue.currentSize+1;
merge(deleteQueue);
return minItem;
}
private Node<AnyType> combineTrees(Node<AnyType> t1, Node<AnyType> t2) {
if(t1.element.compareTo(t2.element)>0){
return combineTrees(t2, t1);
}
t2.nextSibling=t1.leftChild;
t1.leftChild=t2;
return t1;
}
private void expandTheTrees(int newNumTrees) {
Node<AnyType>[] newTrees = new Node[newNumTrees];
for (int i = 0; i < Math.min(theTrees.length, newNumTrees); i++) {
newTrees[i] = theTrees[i];
}
theTrees = newTrees;
}
private int capacity(){
return (1<<theTrees.length-1);
}
private static class Node<AnyType>{
AnyType element;
Node<AnyType> leftChild;
Node<AnyType> nextSibling;
public Node(AnyType a,Node<AnyType> l,Node<AnyType> n){
this.element=a;
this.leftChild=l;
this.nextSibling=n;
}
public Node(AnyType a){
this(a,null,null);
}
}
}