《算法》第二章部分程序 part 4
▶ 书中第二章部分程序,加上自己补充的代码,包括优先队列和索引优先队列
● 优先队列
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的更多相关文章
- 《算法》第二章部分程序 part 5
▶ 书中第二章部分程序,加上自己补充的代码,包括利用优先队列进行多路归并和堆排序 ● 利用优先队列进行多路归并 package package01; import edu.princeton.cs.a ...
- 《算法》第二章部分程序 part 3
▶ 书中第二章部分程序,加上自己补充的代码,包括各种优化的快排 package package01; import edu.princeton.cs.algs4.In; import edu.prin ...
- 《算法》第二章部分程序 part 2
▶ 书中第二章部分程序,加上自己补充的代码,包括若干种归并排序,以及利用归并排序计算数组逆序数 ● 归并排序 package package01; import java.util.Comparato ...
- 《算法》第二章部分程序 part 1
▶ 书中第二章部分程序,加上自己补充的代码,包括插入排序,选择排序,Shell 排序 ● 插入排序 package package01; import java.util.Comparator; im ...
- javascript数据结构和算法 第二章 (数组) 二
字符串表示的数组 join() 和 toString() 函数返回数组的字符串表示.这两个函数通过将数组中的元素用逗号分隔符切割,返回字符串数组表示. 这里有个样例: var names = [&qu ...
- 第二章--Win32程序运行原理 (部分概念及代码讲解)
学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...
- java版数据结构与算法第二章数组
数组由一组具有相同类型的数据元素组成,并存储在一组连续存储单元中.一维数组是常量. 二维数组:若一维数组中的数据元素又是一堆数据结构,我们称之为二维数组.二维数组可以看成是n个列向量组成的线性表. 数 ...
- ASP.NET本质论第二章应用程序对象学习笔记1
1.请求的处理参数—上下文对象HttpContext 1) 针对每一次请求,ASP.NET将创建一个处理这次请求所使用的HttpContext对象实例,这个对象实例将用来在ASP.NET服务器的处理过 ...
- 【学习总结】java数据结构和算法-第二章-数据结构和算法概述
总目录链接 [学习总结]尚硅谷2019java数据结构和算法 github:javaDSA 目录 数据结构和算法的关系 几个实际编程中的问题 线性结构和非线性结构 数据结构和算法的关系 几个实际编程中 ...
随机推荐
- [蓝桥杯]ALGO-122.算法训练_未名湖边的烦恼
问题描述 每年冬天,北大未名湖上都是滑冰的好地方.北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩. 每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个.现在 ...
- mina2中的session
简介 session类图 Mina每建立一个连接同时会创建一个session对象,用于保存这次读写需要用到的所有信息.从抽象类AbstractIoSession中可以看出session具有如下功能: ...
- 1125 Chain the Ropes (25 分)
1125 Chain the Ropes (25 分) Given some segments of rope, you are supposed to chain them into one rop ...
- go中redis使用小结
最近做了个关于redis的项目,那么就整理下遇到和未遇到的问题 1.redis的简介安装 2.redis的数据结构 3.Redis基本使用 4.Redis的并发 5.Redis的落地 一.redis的 ...
- centos7安装zabbix4.2
附zabbixdocker镜像地址 https://hub.docker.com/u/zabbix/ zabbix官方文档 https://www.zabbix.com/cn/download 1.关 ...
- centos7 搭建DHCP服务器
一.DHCP简单讲解 DHCP就是动态主机配置协议(Dynamic Host Configuration Protocol)是一种基于UDP协议且仅限用于局域网的网络协议,它的目的就是为了减轻TCP/ ...
- [UE4]保存游戏数据
新建一个继承自“SaveGame”的蓝图.
- Visual Ribbon Editor for CRM 连接
- [TFS]TFS强制删除离职人员签出锁定项的方法
步骤: 1.连接到TFS数据库服务器的tfsversioncontrol库: 2.查tbl_workspace表,找出那哥们的工作目录, 如select * from tbl_workspace wh ...
- Shiro 权限注解
Shiro 权限注解: Shiro 提供了相应的注解用于权限控制,如果使用这些注解就需要使用AOP 的功能来进行 判断,如Spring AOP:Shiro 提供了Spring AOP 集成用于 ...