《算法》第二章部分程序 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 目录 数据结构和算法的关系 几个实际编程中的问题 线性结构和非线性结构 数据结构和算法的关系 几个实际编程中 ...
随机推荐
- Delphi代码模拟“显示桌面”的功能
今天有人问我:“用shell打开文件(显示桌面.scf)的方式还是用模拟键盘(Win+D)显示桌面”这应该有更好的方法,就搜了搜,关键字定位“ToggleDesktop”因为显示桌面.scf的内容是: ...
- linux 修改mac地址,干坏事必备
首先关闭无线 wlan0 ifconfig wlan0 down 修改mac地址 macchanger -m [MAC] [INTERFACE] 例如:macchanger -m ::::: wlan ...
- git add , git commit 添加错文件 撤销
1. git add 添加 多余文件 这样的错误是由于, 有的时候 可能 git add . (空格+ 点) 表示当前目录所有文件,不小心就会提交其他文件 git add 如果添加了错误的文件的话 撤 ...
- if的各种真假判断
- 第一个react
个人觉着react和vue是很相似的,之前还转载过一篇介绍两个异同点的文章,那个时候还完全不懂react,现在才慢慢开始接触,所以只能总结一些个人的心得,首先自然是react的优点了,个人觉着主要有以 ...
- MySQL总论
1. MySQL基本概念 1.1. 数据库的概念 数据库,简而言之就是存储数据的仓库,可以按照一定的数据结构存储管理大量的数据及数据与数据之间的关系,它本质上是一种信息管理系统.数据库根据存储采用的 ...
- Spring Boot 容器选择 Undertow 而不是 Tomcat
Spring Boot 内嵌容器Undertow参数设置 配置项: # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 # 不要设置过大,如果过大,启动 ...
- Jmeter(三十八)Jmeter Question 之 ‘批量执行SQL语句’
知识使我们变得玩世不恭,智慧使我们变得冷酷无情,我们思考的太多,感知太少,除了机器,我们更需要人性,除了智慧,我们需要仁慈和善良. ------出自查理卓别林的演讲 前面有提到Jmeter使用JDBC ...
- [UE4]创建动画的3中方法
一.基于现有动画的骨骼,从头开始创建一个全新的动画.(不推荐) 选中左边的骨骼节点做旋转变化. 调整完成了别忘记点击添加“Key”以创建一个关键帧,然后再保存. 二.基于当前动画的姿势创建一个动画.( ...
- html代码段
添加icon<link rel="shortcut icon" href="img/100du.ico"/>