heapInsert
就是插入操作,heapify
是取出数组后进行堆结构调整的操作public class Heap {
// 大根堆结构
public static class MyMaxHeap {
private int[] heap;
private final int limit;
private int heapSize;
public MyMaxHeap(int limit) {
heap = new int[limit];
this.limit = limit;
heapSize = 0;
}
public boolean isEmpty() {
return heapSize == 0;
}
public boolean isFull() {
return heapSize == limit;
}
public void push(int value) {
if(heapSize == limit) {
throw new RuntimeException("Heap is full!");
}
heap[heapSize] = value;
heapInsert(heap, heapSize++);
}
public int pop() {
if(heapSize == 0) {
throw new RuntimeException("Heap is empty!");
}
int ans = heap[0];
swap(heap, 0, --heapSize);
heapify(heap, 0, heapSize);
return ans;
}
private void heapify(int[] heap, int index, int heapSize) {
int left = index * 2 + 1;
while (left < heapSize) {
int largest = left + 1 > heapSize ? left : (heap[left] > heap[left + 1] ? left : left + 1);
largest = heap[largest] > heap[index] ? largest : index;
if (largest == index) {
return;
}
swap(heap, index, largest);
index = largest;
left = index * 2 - 1;
}
}
private void heapInsert(int[] heap, int index) {
while (heap[index] > heap[(index - 1) / 2]) {
swap(heap, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
private void swap(int[] heap, int i, int j) {
int temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
}
// 参照组:暴力
public static class RightMaxHeap {
private int[] heap;
private final int limit;
private int heapSize;
public RightMaxHeap(int limit) {
heap = new int[limit];
this.limit = limit;
heapSize = 0;
}
public boolean isEmpty() {
return heapSize == 0;
}
public boolean isFull() {
return heapSize == limit;
}
public void push(int value) {
if(heapSize == limit) {
throw new RuntimeException("Heap is full!");
}
heap[heapSize++] = value;
}
public int pop() {
if(heapSize == 0) {
throw new RuntimeException("Heap is empty!");
}
int maxIndex = 0;
for (int i = 1; i < heap.length; i++) {
if(heap[maxIndex] < heap[i]) {
maxIndex = i;
}
}
int ans = heap[maxIndex];
heap[maxIndex] = heap[--heapSize];
return ans;
}
}
public static void main(String[] args) {
// 写对数器验证堆结构
int value = 1000;
int limit = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
int curLimit = (int)(Math.random() * limit) + 1;
RightMaxHeap test = new RightMaxHeap(curLimit);
MyMaxHeap my = new MyMaxHeap(curLimit);
int curOpTimes = (int)(Math.random() * limit);
for (int j = 0; j < curOpTimes; j++) {
if (my.isEmpty() != test.isEmpty()) {
System.out.println("Oops!");
}
if (my.isFull() != test.isFull()) {
System.out.println("Oops!");
}
if (my.isEmpty()) {
int curValue = (int)(Math.random() * value);
my.push(value);
test.push(value);
}else if (my.isFull()) {
if(my.pop() != test.pop()) {
System.out.println("Oops!");
}
}else {
if(Math.random() < 0.5) {
int curValue = (int)(Math.random() * value);
my.push(value);
test.push(value);
}else {
if(my.pop() != test.pop()) {
System.out.println("Oops!");
}
}
}
}
}
System.out.println("Finish!");
}
}
为什么要改进?
Student
类,我不修改这个类的任何值,用原始堆没问题。Student
类修改一下,比如修改年龄或者id,那么就必须要使用改进的堆。resign
方法,可以在修改已经在堆里面的值之后还能形成堆结构。改进的堆:
public class MyHeap<T> {
private ArrayList<T> heap;
private HashMap<T, Integer> indexMap;
private int heapSize;
private Comparator<? super T> comparator;
public MyHeap(Comparator<? super T> comparator) {
heap = new ArrayList<>();
indexMap = new HashMap<>();
heapSize = 0;
this.comparator = comparator;
}
public boolean isEmpty() {
return heapSize == 0;
}
public int getHeapSize() {
return heapSize;
}
public void push(T value) {
heap.add(value);
indexMap.put(value, heapSize);
heapInsert(heapSize++);
}
public T poll() {
T ans = heap.get(0);
int end = heapSize - 1;
swap(0, end);
heap.remove(end);
indexMap.remove(ans);
heapify(0, --heapSize);
return ans;
}
public void resign(T value) {
int valueIndex = indexMap.get(value);
heapify(valueIndex, heapSize);
heapInsert(valueIndex);
}
private void heapify(int index, int heapSize) {
int left = index * 2 + 1;
while (left < heapSize) {
int largest = (left + 1 < heapSize) && (comparator.compare(heap.get(left + 1), heap.get(left)) < 0) ? left + 1 : left;
largest = (comparator.compare(heap.get(largest), heap.get(index)) < 0) ? largest : index;
if (largest == index) {
return;
}
swap(largest, index);
index = largest;
left = index * 2 + 1;
}
}
private void heapInsert(int index) {
while (comparator.compare(heap.get(index), heap.get((index - 1) / 2)) < 0) {
swap(index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
private void swap(int i, int j) {
T o1 = heap.get(i);
T o2 = heap.get(j);
heap.set(i, o2);
heap.set(j, o1);
indexMap.put(o1, j);
indexMap.put(o2, i);
}
}
学生类:
public class Student {
private int id;
private String name;
private int age;
private String address;
public Student() {
}
public Student(int id, String name, int age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
/**
* 获取
* @return id
*/
public int getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(int id) {
this.id = id;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return address
*/
public String getAddress() {
return address;
}
/**
* 设置
* @param address
*/
public void setAddress(String address) {
this.address = address;
}
public String toString() {
return "Student{id = " + id + ", name = " + name + ", age = " + age + ", address = " + address + "}";
}
}
测试:
public class test {
public static void main(String[] args) {
Student s1 = new Student(1, "张三", 18, "西安");
Student s2 = new Student(2, "李四", 20, "重庆");
Student s3 = new Student(3, "王五", 19, "成都");
Student s4 = new Student(4, "赵六", 22, "深圳");
Student s5 = new Student(5, "钱七", 21, "北京");
MyHeap<Student> myHeap = new MyHeap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getId() - o1.getId();
}
});
myHeap.push(s1);
myHeap.push(s2);
myHeap.push(s3);
myHeap.push(s4);
myHeap.push(s5);
System.out.println(myHeap.isEmpty());
System.out.println(myHeap.getHeapSize());
System.out.println("====================");
s1.setId(15);
myHeap.resign(s1);
while (!myHeap.isEmpty()) {
System.out.println(myHeap.poll().toString());
}
}
}
可以完成前缀相关的查询
// Node和TrieTree结合使用,Node2和TrieTree2结合使用。
// TrieTree2只能加入小写字符组成的字符串,有局限性
// TrieTree可以都加入
public class TrieTreeSearch {
public static class Node {
public int pass;
public int end;
public HashMap<Integer, Node> next;
public Node() {
pass = 0;
end = 0;
next = new HashMap<>();
}
}
public static class TrieTree {
private final Node root;
public TrieTree() {
root = new Node();
}
public void insert(String word) {
if (word == null) {
return;
}
Node node = root;
node.pass++;
char[] chars = word.toCharArray();
int index = 0;
for (char aChar : chars) {
index = aChar;
if (!node.next.containsKey(index)) {
node.next.put(index, new Node());
}
node = node.next.get(index);
node.pass++;
}
node.end++;
}
public void delete(String word) {
if (search(word) != 0) {
Node node = root;
node.pass--;
int index = 0;
char[] chars = word.toCharArray();
for (char aChar : chars) {
index = aChar;
if (node.next.containsKey(index)) {
node = node.next.get(index);
}
node.pass--;
}
node.end--;
}
}
public int search(String word) {
return research(word).end;
}
public int prefixNum(String word) {
return research(word).pass;
}
private Node research(String word) {
if (word == null) {
return new Node();
}
Node node = root;
char[] chars = word.toCharArray();
int index = 0;
for (char aChar : chars) {
index = aChar;
if (!node.next.containsKey(index)) {
return new Node();
}
node = node.next.get(index);
}
return node;
}
}
public static class Node2 {
public int pass;
public int end;
public Node2[] next;
public Node2() {
pass = 0;
end = 0;
next = new Node2[26];
}
}
public static class TrieTree2 {
private final Node2 root;
// 无参构造
public TrieTree2() {
root = new Node2();
}
// 添加字符串
public void insert(String word) {
if (word == null) {
return;
}
char[] chars = word.toCharArray();
Node2 node = root;
node.pass++;
int index = 0;
for (char aChar : chars) {
index = aChar - 'a';
if (node.next[index] == null) {
node.next[index] = new Node2();
}
node = node.next[index];
node.pass++;
}
node.end++;
}
// 查找字符串有多少个
public int search(String word) {
if (word == null) {
return 0;
}
char[] chars = word.toCharArray();
Node2 node = root;
int index = 0;
for (char aChar : chars) {
index = aChar - 'a';
if (node.next[index] == null) {
return 0;
}
node = node.next[index];
}
return node.end;
}
// 删除字符串
public void delete(String word) {
if (search(word) != 0) {
Node2 node = root;
node.pass--;
int index = 0;
char[] chars = word.toCharArray();
for (char aChar : chars) {
index = aChar - 'a';
if (--node.next[index].pass == 0) {
node.next[index] = null;
return;
}
node = node.next[index];
}
node.end--;
}
}
// 有几个字符串前缀是word
public int prefixNum(String word) {
if (word == null) {
return 0;
}
char[] chars = word.toCharArray();
Node2 node = root;
int index = 0;
for (char aChar : chars) {
index = aChar - 'a';
if (node.next[index] == null) {
return 0;
}
node = node.next[index];
}
return node.pass;
}
}
public static String generateRandomString(int strLen) {
char[] ans = new char[(int) (Math.random() * strLen) + 1];
for (int i = 0; i < ans.length; i++) {
int value = (int) (Math.random() * 26);
ans[i] = (char) (value + 97);
}
return String.valueOf(ans);
}
public static String[] generateRandomString(int arrLen, int strLen) {
String[] ans = new String[(int) (Math.random() * arrLen) + 1];
for (int i = 0; i < ans.length; i++) {
ans[i] = generateRandomString(strLen);
}
return ans;
}
// 写对数器进行测试
public static void main(String[] args) {
int strLen = 20;
int arrLen = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
String[] strings = generateRandomString(arrLen, strLen);
TrieTree my = new TrieTree();
TrieTree2 test = new TrieTree2();
for (String word : strings) {
double decide = Math.random();
if (decide < 0.25) {
my.insert(word);
test.insert(word);
} else if (decide < 0.5) {
my.delete(word);
test.delete(word);
} else if (decide < 0.75) {
int ans1 = my.search(word);
int ans2 = test.search(word);
if(ans1 != ans2) {
System.out.println("Oops!");
}
}else {
int ans1 = my.prefixNum(word);
int ans2 = test.prefixNum(word);
if (ans1 != ans2) {
System.out.println("Oops!");
}
}
}
}
System.out.println("Finish!");
}
}