▶ 书中第二章部分程序,加上自己补充的代码,包括优先队列和索引优先队列

● 优先队列

 package package01;

 import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut; public class class01<Key> implements Iterable<Key>
{
private int n; // 实际元素数
private Key[] pq; // 放堆的数组,注意 pq[0] 不使用
private Comparator<Key> comparator; // 比较器 public class01(int initCapacity)
{
n = 0;
pq = (Key[]) new Object[initCapacity + 1];
} public class01(int initCapacity, Comparator<Key> comparator)
{
n = 0;
pq = (Key[]) new Object[initCapacity + 1];
comparator = comparator;
} public class01()
{
this(1); // 对象自身的指针可以当构造函数名用
} public class01(Comparator<Key> comparator)
{
this(1, comparator);
} public class01(Key[] keys) // 含传入数组的构造函数
{
n = keys.length;
pq = (Key[]) new Object[keys.length + 1];
for (int i = 0; i < n; i++)
pq[i + 1] = keys[i];
for (int k = n / 2; k >= 1; k--)// 逐元素下沉建堆
sink(k);
} public boolean isEmpty()
{
return n == 0;
} public int size()
{
return n;
} public Key max() // 取最大元素(堆顶)
{
if (isEmpty())
throw new NoSuchElementException("Priority queue underflow");
return pq[1];
} public Key delMax() // 弹出最大元素
{
if (isEmpty())
throw new NoSuchElementException("Priority queue underflow");
Key max = pq[1];
exch(1, n--); // 把最后的元素放到堆顶,然后下沉
sink(1);
pq[n + 1] = null; // 帮助垃圾回收
if ((n > 0) && (n == (pq.length - 1) / 4)) // 减少堆尺寸
resize(pq.length / 2);
return max;
} private void resize(int capacity) // 调整堆大小
{
assert capacity > n;
Key[] temp = (Key[]) new Object[capacity]; // 建一个新堆,然后搬进去
for (int i = 1; i <= n; i++)
temp[i] = pq[i];
pq = temp;
} public void insert(Key x) // 插入新元素
{
if (n == pq.length - 1) // 堆满了,扩建
resize(2 * pq.length); pq[++n] = x; // 把新元素放到堆最后,然后上浮
swim(n);
} private void swim(int k) // 上浮
{
for (; k > 1 && less(k / 2, k); k = k / 2)
exch(k, k / 2);
} private void sink(int k) // 下沉
{
for (int j = k + k; j <= n; exch(k, j), k = j, j = k + k)
{
if (j < n && less(j, j + 1)) // 选择 a[k] 子节点中较大者
j++;
if (!less(k, j)) // 调整 a[k] 及其子节点,若 a[k] > a[j] 则停止调整
break;
}
} private boolean less(int i, int j) // 需要小根堆时把两个不等号变向,其他所有地方都不改
{
if (comparator == null)
return ((Comparable<Key>) pq[i]).compareTo(pq[j]) < 0;
//return ((Comparable<Key>) pq[i]).compareTo(pq[j]) > 0;
else
return comparator.compare(pq[i], pq[j]) < 0;
//return comparator.compare(pq[i], pq[j]) > 0;
} private void exch(int i, int j)
{
Key swap = pq[i];
pq[i] = pq[j];
pq[j] = swap;
} private boolean isMaxHeap()
{
return isMaxHeap(1);
} private boolean isMaxHeap(int k)
{
if (k > n)
return true;
int left = 2 * k, right = 2 * k + 1;
if (left <= n && less(k, left) || right <= n && less(k, right))
return false;
return isMaxHeap(left) && isMaxHeap(right);
} public Iterator<Key> iterator() // 迭代器
{
return new HeapIterator();
} private class HeapIterator implements Iterator<Key>
{
private class01<Key> copy; public HeapIterator()
{
if (comparator == null)
copy = new class01<Key>(size());
else
copy = new class01<Key>(size(), comparator);
for (int i = 1; i <= n; i++)
copy.insert(pq[i]);
} public boolean hasNext()
{
return !copy.isEmpty();
} public void remove()
{
throw new UnsupportedOperationException();
} public Key next()
{
if (!hasNext())
throw new NoSuchElementException();
return copy.delMax();
}
} public static void main(String[] args) // 交互式出入优先队列
{
class01<String> pq = new class01<String>();
for(; !StdIn.isEmpty();)
{
String item = StdIn.readString();
if (!item.equals("-"))
pq.insert(item);
else if (!pq.isEmpty())
StdOut.print(pq.delMax() + " ");
}
StdOut.println("(" + pq.size() + " left on pq)");
}
}

● 索引优先队列

 package package01;

 import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdOut; public class class01<Key extends Comparable<Key>> implements Iterable<Integer>
{
private int maxN; // 队列最大元素个数
private int n;
private int[] pq; // 索引堆,初值为 0,pq[0] 不用,pq[i] == j 表示堆的数组表示中第 i 位置上的元素是 keys[j]
private int[] qp; // 索引堆的逆,初值为 -1,qp[pq[i]] = pq[qp[i]] = i,qp[j] == i 表示元素 keys[i] 在堆的数组表示中位于第 i 的位置
private Key[] keys; // 仅保存值(不移动) public class01(int inputMaxN)
{
if (maxN < 0)
throw new IllegalArgumentException("\n<construct> maxN < 0.\n");
maxN = inputMaxN;
n = 0;
pq = new int[maxN + 1];
qp = new int[maxN + 1];
keys = (Key[]) new Comparable[maxN + 1];
for (int i = 0; i <= maxN; i++)
qp[i] = -1;
} public boolean isEmpty()
{
return n == 0;
} public boolean contains(int i) // 判断 qp 中第 i 位置是否被占用
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
return qp[i] != -1;
} public int size()
{
return n;
} public void insert(int i, Key key)
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (contains(i))
throw new IllegalArgumentException("\n<insert> exist i already exist.\n");
n++; // 新元素插到末尾,然后上浮
qp[i] = n;
pq[n] = i;
keys[i] = key;
swim(n);
} public int topIndex()
{
if (n == 0)
throw new NoSuchElementException("\n<maxIndex> underflow.\n");
return pq[1];
} public Key topKey() // 显示堆顶元素
{
if (n == 0)
throw new NoSuchElementException("\n<maxKey> underflow.\n");
return keys[pq[1]];
} public int delTop() // 弹出堆顶元素
{
if (n == 0)
throw new NoSuchElementException("\n<delMax> underflow.\n");
int top = pq[1];
exch(1, n--); // 将堆尾元素换到堆顶,然后下沉
sink(1);
//assert pq[n + 1] == top; // 确保原来堆顶的元素被替换到了最后
qp[top] = -1; // 清除尾部元素的占用(代表被弹出的堆顶元素)
keys[top] = null; // 有助于垃圾回收
pq[n + 1] = -1; // 可以不要?
return top;
} public Key keyOf(int i) // 查询 keys 中第 i 个元素
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<KeyOf> index i not exist.\n");
else return keys[i];
} public void changeKey(int i, Key key) // 在keys 的第 i 位置上替换成元素 key,然后调整其在堆中的位置
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<changeKey> index i not exist.\n");
keys[i] = key;
swim(qp[i]);
sink(qp[i]);
} public void increaseKey(int i, Key key) // 增加某个元素的键
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<increaseKey> index i not exist.\n");
if (keys[i].compareTo(key) >= 0)
throw new IllegalArgumentException("\n<increaseKey> given key less than the older one.\n");
keys[i] = key; // 替换后只要上浮即可
swim(qp[i]);
//sink(qp[i]); // 最小有优先队列中这里要改成下沉
} public void decreaseKey(int i, Key key) // 减少某个元素的键
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<decreaseKey> index is not in the priority queue.\n");
if (keys[i].compareTo(key) <= 0)
throw new IllegalArgumentException("\n<decreaseKey> given key mroe than the older one.\n");
keys[i] = key; // 替换后只要下沉即可
sink(qp[i]);
//swim(qp[i]); // 最小有优先队列中这里要改成上浮
} public void delete(int i) // 删除节点
{
if (i < 0 || i >= maxN)
throw new IllegalArgumentException();
if (!contains(i))
throw new NoSuchElementException("\n<delete> index i not exist.\n");
int index = qp[i]; // 把目标元素与堆尾元素互换,然后调整
exch(index, n--);
swim(index);
sink(index);
keys[i] = null;
qp[i] = -1;
} private boolean less(int i, int j) // 最大优先队列用 less 来做上浮和下沉
{
return keys[pq[i]].compareTo(keys[pq[j]]) < 0;
} private boolean greater(int i, int j) // 最小优先队列用 greater 来做上浮和下沉
{
return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
} private void exch(int i, int j) // 单纯交换 i 和 j(不用调整位置?)
{
int swap = pq[i];
pq[i] = pq[j];
pq[j] = swap;
qp[pq[i]] = i;
qp[pq[j]] = j;
} private void swim(int k)
{
for (; k > 1 && less(k >> 1, k); k >>= 1)
//for (; k > 1 && greater(k >> 1, k); k >>= 1) // 最小优先队列用
exch(k, k >> 1);
} private void sink(int k)
{
for (int j = k << 1; j <= n; exch(k, j), k = j, j = k << 1)
{
if (j < n && less(j, j + 1))
//if (j < n && greater(j, j + 1)) // 最小优先队列用
j++;
if (!less(k, j))
break;
}
} public Iterator<Integer> iterator() // 迭代器,原理是临时建立一个把 key 排好序的堆用于迭代
{
return new HeapIterator();
} private class HeapIterator implements Iterator<Integer>
{
private class01<Key> copy; public HeapIterator()
{
copy = new class01<Key>(pq.length - 1);
for (int i = 1; i <= n; i++)
copy.insert(pq[i], keys[pq[i]]);
} public boolean hasNext()
{
return !copy.isEmpty();
} public void remove()
{
throw new UnsupportedOperationException();
} public Integer next()
{
if (!hasNext())
throw new NoSuchElementException();
return copy.delTop();
}
} public static void main(String[] args)
{
String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" }; class01<String> pq = new class01<String>(strings.length);
for (int i = 0; i < strings.length; i++) // 入队
pq.insert(i, strings[i]); for (int i : pq) // 用迭代器显示队列状态,等效于逐个出队
StdOut.println(i + " " + strings[i]);
StdOut.println(); for (int i = 0; i < strings.length; i++) // 尝试改变元素的键
{
if (StdRandom.uniform() < 0.5)
pq.increaseKey(i, "zzz"); // 换成优先级更高的字符串
else
pq.decreaseKey(i, strings[i].substring(0, 1)); // 换成原来字符串的子串
} for (; !pq.isEmpty();) // 诸葛弹出元素
{
String key = pq.maxKey();
int i = pq.delMax();
StdOut.println(i + " " + key);
}
StdOut.println(); for (int i = 0; i < strings.length; i++) // 再次入队
pq.insert(i, strings[i]); int[] perm = new int[strings.length]; // 随机删除,生成一个随机数组,按数组元素的值删减队列中的元素
for (int i = 0; i < strings.length; i++)
perm[i] = i;
StdRandom.shuffle(perm);
for (int i = 0; i < perm.length; i++)
{
String key = pq.keyOf(perm[i]);
pq.delete(perm[i]);
StdOut.println(perm[i] + " " + key);
}
}
}

《算法》第二章部分程序 part 4的更多相关文章

  1. 《算法》第二章部分程序 part 5

    ▶ 书中第二章部分程序,加上自己补充的代码,包括利用优先队列进行多路归并和堆排序 ● 利用优先队列进行多路归并 package package01; import edu.princeton.cs.a ...

  2. 《算法》第二章部分程序 part 3

    ▶ 书中第二章部分程序,加上自己补充的代码,包括各种优化的快排 package package01; import edu.princeton.cs.algs4.In; import edu.prin ...

  3. 《算法》第二章部分程序 part 2

    ▶ 书中第二章部分程序,加上自己补充的代码,包括若干种归并排序,以及利用归并排序计算数组逆序数 ● 归并排序 package package01; import java.util.Comparato ...

  4. 《算法》第二章部分程序 part 1

    ▶ 书中第二章部分程序,加上自己补充的代码,包括插入排序,选择排序,Shell 排序 ● 插入排序 package package01; import java.util.Comparator; im ...

  5. javascript数据结构和算法 第二章 (数组) 二

    字符串表示的数组 join() 和 toString() 函数返回数组的字符串表示.这两个函数通过将数组中的元素用逗号分隔符切割,返回字符串数组表示. 这里有个样例: var names = [&qu ...

  6. 第二章--Win32程序运行原理 (部分概念及代码讲解)

    学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...

  7. java版数据结构与算法第二章数组

    数组由一组具有相同类型的数据元素组成,并存储在一组连续存储单元中.一维数组是常量. 二维数组:若一维数组中的数据元素又是一堆数据结构,我们称之为二维数组.二维数组可以看成是n个列向量组成的线性表. 数 ...

  8. ASP.NET本质论第二章应用程序对象学习笔记1

    1.请求的处理参数—上下文对象HttpContext 1) 针对每一次请求,ASP.NET将创建一个处理这次请求所使用的HttpContext对象实例,这个对象实例将用来在ASP.NET服务器的处理过 ...

  9. 【学习总结】java数据结构和算法-第二章-数据结构和算法概述

    总目录链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 数据结构和算法的关系 几个实际编程中的问题 线性结构和非线性结构 数据结构和算法的关系 几个实际编程中 ...

随机推荐

  1. camera-arm-RPI

    这个属于先收藏着,知道有个开源的东西. luvcview是一个开源项目,专注于UVC摄像头的测试,只要您的摄像头支持UVC驱动,即可使用luvcview测试程序,如何知道自己的摄像头是不是支持UVC驱 ...

  2. 初识React:使用React完成Hello World程序

    正式学习React之前,通过一个简单的Hello Word程序来感受一下. <!DOCTYPE html> <html lang="zh-cn"> < ...

  3. 黄聪:wordpress如何携带cookie模拟浏览器访问网站

    $args = array( 'user-agent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, li ...

  4. LeetCode——7. Reverse Integer

    一.题目链接:https://leetcode.com/problems/reverse-integer/ 二.题目大意: 给定一个整数,要求反转该整数之后再返回:如果归返回的整数超过了int型整数的 ...

  5. hadoop MapReduce —— 输出每个单词所对应的文件

    下面是四个文件及其内容. 代码实现: Mapper: package cn.tedu.invert; import java.io.IOException; import org.apache.had ...

  6. 微服务之分布式跟踪系统(springboot+zipkin+mysql)

    通过上一节<微服务之分布式跟踪系统(springboot+zipkin)>我们简单熟悉了zipkin的使用,但是收集的数据都保存在内存中重启后数据丢失,不过zipkin的Storage除了 ...

  7. 微信小程序调用微信登陆获取openid及用户信息 java做为服务端

    转载的文章,很不错 https://blog.csdn.net/weilai_zhilu/article/details/77932630

  8. 1126 Eulerian Path (25 分)

    1126 Eulerian Path (25 分) In graph theory, an Eulerian path is a path in a graph which visits every ...

  9. [UE4]虚幻4链接独立服务器

    如果虚幻4只做客户端的话,应该怎么连接服务器呢? 官方并没有提供蓝图的网络函数,C++里面有. 一.自己实现,提供接口给蓝图使用. 二.第三方插件.插件下载地址:https://github.com/ ...

  10. [UE4]AIPerception,AI感知