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

● 优先队列

 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. [蓝桥杯]ALGO-122.算法训练_未名湖边的烦恼

    问题描述 每年冬天,北大未名湖上都是滑冰的好地方.北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩. 每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个.现在 ...

  2. mina2中的session

    简介 session类图 Mina每建立一个连接同时会创建一个session对象,用于保存这次读写需要用到的所有信息.从抽象类AbstractIoSession中可以看出session具有如下功能: ...

  3. 1125 Chain the Ropes (25 分)

    1125 Chain the Ropes (25 分) Given some segments of rope, you are supposed to chain them into one rop ...

  4. go中redis使用小结

    最近做了个关于redis的项目,那么就整理下遇到和未遇到的问题 1.redis的简介安装 2.redis的数据结构 3.Redis基本使用 4.Redis的并发 5.Redis的落地 一.redis的 ...

  5. centos7安装zabbix4.2

    附zabbixdocker镜像地址 https://hub.docker.com/u/zabbix/ zabbix官方文档 https://www.zabbix.com/cn/download 1.关 ...

  6. centos7 搭建DHCP服务器

    一.DHCP简单讲解 DHCP就是动态主机配置协议(Dynamic Host Configuration Protocol)是一种基于UDP协议且仅限用于局域网的网络协议,它的目的就是为了减轻TCP/ ...

  7. [UE4]保存游戏数据

    新建一个继承自“SaveGame”的蓝图.

  8. Visual Ribbon Editor for CRM 连接

  9. [TFS]TFS强制删除离职人员签出锁定项的方法

    步骤: 1.连接到TFS数据库服务器的tfsversioncontrol库: 2.查tbl_workspace表,找出那哥们的工作目录, 如select * from tbl_workspace wh ...

  10. Shiro 权限注解

      Shiro 权限注解:   Shiro 提供了相应的注解用于权限控制,如果使用这些注解就需要使用AOP 的功能来进行 判断,如Spring AOP:Shiro 提供了Spring AOP 集成用于 ...