堆相关知识复习(y总版)
我们本次预计使用Java来实现一个链式的大根堆,支持插入节点,修改节点值,堆排序,打印堆结构等功能。并将项目打包为jar包在cmd控制台运行。
1.功能设计
大根堆是一个完全二叉树,每个父节点的值大于两个子节点的值,那么要实现插入节点的操作,我们就需要知道从根节点插入所要经过的路径,以在节点5插入为例:
5的二进制表示为101,第一个1代表从根节点1开始,第二个0表示向左儿子走,第三个1表示向右儿子走,最终走到了节点5这里。这个找到插入节点路径的函数用getPath(x)
实现。
数据结构设计
我们的每个堆中包括一个堆容量
s
i
z
siz
siz、堆二叉树
∗
∗
h
e
a
d
**head
∗∗head、数组
s
o
r
t
e
d
A
r
r
a
y
sortedArray
sortedArray用于存储堆排序结果
每个堆二叉树节点包括节点值**
v
a
l
val
val,左右儿子编号
l
e
f
t
left
left、
r
i
g
h
t
right
right,父亲节点编号
f
a
fa
fa
为了能够较为直观地打印出树,编写一个DefaultBinaryTreeNodePrinter
和DefaultBinaryTreePrinter
类用于树的打印。
堆排序,操作简单来讲就是将堆顶的元素拿出来,之后找到堆最后的一个元素的值 g e t P a t h ( 堆的大小 ) getPath(堆的大小) getPath(堆的大小),用其替换堆顶元素的值,之后从堆顶开始执行下沉操作 d o w n ( ) down() down(),同时堆大小 s i z − 1 siz-1 siz−1,循环往复直到堆大小siz=0。
将排序好的结果存入数组 s o r t e d A r r a y sortedArray sortedArray。
我们的堆支持一下几种操作:
- 0: 堆初始化
- 1: 堆中插入一个元素
- 2: 修改堆节点v的元素值为k
- 3: 堆排序操作
- 4: 打印堆的树结构
- 5: 打印堆排序结果
- 6: 输入一个数组构建堆
- 9: 退出程序
2.代码实现
先上C++代码(没有操作6和画树操作):
#include<bits/stdc++.h>
using namespace std;
struct node{
int val;
node *left;
node *right;
node *fa;
node(int x): val(x),left(NULL),right(NULL),fa(NULL) {};
node(int x,node *fa):val(x),left(NULL),right(NULL),fa(fa) {};
};
struct Heap{
int siz;
node *head;
vector<int> sortedArray;
string getPath(int t)
{
string s="";
while(t!=1)
{
int k=t%2;
s=(char)(k+'0')+s;
t/=2;
}
return s;
}
void up(node *root,string s,int idx)
{
if(idx==s.size()){
if(root->val>root->fa->val)
{
swap(root->val,root->fa->val);
}
return ;
}
if(s[idx]=='1'){
up(root->right,s,idx+1);
if(root->fa){
if(root->val>root->fa->val) swap(root->val,root->fa->val);
}
}
else{
up(root->left,s,idx+1);
if(root->fa){
if(root->val>root->fa->val) swap(root->val,root->fa->val);
}
}
}
void insert(int x){
if(!siz){
head=new node(x);
siz++;
}
else{
string s=getPath(siz+1);
head=insert(head,NULL,s,0,x);
siz++;
s=getPath(siz);
up(head,s,0);
}
}
node* insert(node *root,node *pre,string s,int idx,int x)
{
if(!root){
return new node(x,pre);
}
if(s[idx]=='1'){
root->right=insert(root->right,root,s,idx+1,x);
}
else{
root->left=insert(root->left,root,s,idx+1,x);
}
return root;
}
node* modify(node *root,string s,int idx,int x)
{
if(idx==s.size()){
if(x < root->val){
puts("Value k < key value!");
return root;
}
root->val=x;
return root;
}
if(s[idx]=='1'){
root->right=modify(root->right,s,idx+1,x);
}
else{
root->left=modify(root->left,s,idx+1,x);
}
return root;
}
void increaseKey(int v,int k)
{
if(v>siz)
{
puts("Node v not exist!");
return ;
}
else{
string s=getPath(v);
head=modify(head,s,0,k);
down(v,head,siz);
up(head,s,0);
}
}
node *copyHeap(node *a,node *b)
{
if(b)
a=new node(b->val,b->fa);
else
return NULL;
a->left=copyHeap(a->left,b->left);
a->right=copyHeap(a->right,b->right);
return a;
}
int query(node *root,string s,int idx)
{
if(idx==s.size()){
return root->val;
}
if(s[idx]=='1'){
return query(root->right,s,idx+1);
}
else{
return query(root->left,s,idx+1);
}
}
node *queryNode(node *root,string s,int idx)
{
if(idx==s.size()){
return root;
}
if(s[idx]=='1'){
return queryNode(root->right,s,idx+1);
}
else{
return queryNode(root->left,s,idx+1);
}
}
//下沉操作
void down(int x,node *root,int len)
{
//找到左右儿子中最大的数,替换父亲节点的值
int t=x;
if(x*2<=len && query(root,getPath(2*x),0)>query(root,getPath(t),0)) t=2*x;
if(x*2+1<=len && query(root,getPath(2*x+1),0)>query(root,getPath(t),0)) t=2*x+1;
if(x!=t)
{
node *a=queryNode(root,getPath(x),0);
node *b=queryNode(root,getPath(t),0);
swap(a->val,b->val);
down(t,root,len);
}
}
void output(node *root)
{
queue<node*> q;
q.push(root);
while(q.size())
{
int len=q.size();
for(int i=0;i<len;i++)
{
auto t=q.front(); q.pop();
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
cout<<t->val<<" ";
}
puts("");
}
}
void outputSortResult()
{
reverse(sortedArray.begin(),sortedArray.end());
for(auto x:sortedArray) cout<<x<<" ";
puts("");
}
void heapSort(Heap hp)
{
sortedArray.clear();
Heap temp;
temp.siz=hp.siz;
temp.head=copyHeap(temp.head,hp.head);
queue<node*> q;
q.push(temp.head);
//output(temp.head);
for(int i=0;i<siz;i++)
{
sortedArray.push_back(temp.head->val);
string s=getPath(temp.siz--);
temp.head->val=query(temp.head,s,0);
//int val=query(siz)->val;
//cout<<temp.head->val<<endl;
down(1,temp.head,temp.siz);
//output(temp.head);
}
}
Heap():siz(0){}
};
int main()
{
Heap h;
h.insert(5);
h.insert(6);
h.insert(7);
h.insert(1);
h.insert(2);
h.increaseKey(4,10);
h.output(h.head);
h.heapSort(h);
h.outputSortResult();
h.insert(15);
h.insert(25);
h.insert(36);
h.heapSort(h);
h.outputSortResult();
return 0;
}
Java代码
MaxHeap.java
package com.joy187.re8joymod;
import java.util.*;
//定义二叉树节点
class node{
int val;
node left;
node right;
node fa;
node(int x){
this.val=x;
this.left=null;
this.right=null;
this.fa=null;
}
node(int x,node fa){
this.val=x;
this.left=null;
this.right=null;
this.fa=fa;
}
};
//定义我们的堆
class Heap{
int siz;
node head;
List<Integer> sortedArray=new ArrayList<Integer>();
Heap(){
this.siz=0;
this.head=null;
}
void init()
{
this.siz=0;
this.head=null;
this.sortedArray.clear();
}
void swap(node a,node b)
{
int temp=a.val;
a.val=b.val;
b.val=temp;
}
//find a path to the position of the new node
String getPath(int t)
{
String s="";
while(t!=1)
{
int k=t%2;
s=(char)(k+'0')+s;
t/=2;
}
return s;
}
//place the new node in the right place of the heap
void up(node root,String s,int idx)
{
if(idx==s.length()){
if(root.val > root.fa.val)
{
//int temp=root.val;
//root.val=root.fa.val;
//root.fa.val=temp;
swap(root,root.fa);
}
return ;
}
if(s.charAt(idx)=='1'){
up(root.right,s,idx+1);
if(root.fa!=null){
if(root.val > root.fa.val) swap(root,root.fa);
}
}
else{
up(root.left,s,idx+1);
if(root.fa!=null){
if(root.val > root.fa.val) swap(root,root.fa);
}
}
}
//insert a node to the binary tree heap
node insert(node root,node pre,String s,int idx,int x)
{
if(root==null){
return new node(x,pre);
}
if(s.charAt(idx)=='1'){
root.right=insert(root.right,root,s,idx+1,x);
}
else{
root.left=insert(root.left,root,s,idx+1,x);
}
return root;
}
//insert a node to the binary tree heap
void insert(int x) {
if (this.siz == 0) {
this.head = new node(x);
this.siz++;
} else {
String s = getPath(this.siz + 1);
this.head = insert(this.head, null, s, 0, x);
this.siz++;
s = getPath(this.siz);
up(this.head, s, 0);
}
}
//modify the vertex v with new key valule x
node modify(node root,String s,int idx,int x)
{
if(idx==s.length()){
if(x < root.val){
System.out.println("Value k < key value!");
return root;
}
root.val=x;
return root;
}
if(s.charAt(idx)=='1'){
root.right=modify(root.right,s,idx+1,x);
}
else{
root.left=modify(root.left,s,idx+1,x);
}
return root;
}
//assigns to vertex v the new key value k.
void increaseKey(int v,int k)
{
if(v>this.siz)
{
System.out.println("Node v not exist!");
return ;
}
else{
String s=getPath(v);
this.head=modify(this.head,s,0,k);
up(this.head,s,0);
}
}
void output(node root)
{
// Queue<node> q=new LinkedList();
// q.add(root);
// while(q.size()>0)
// {
// int len=q.size();
// for(int i=0;i<len;i++)
// {
// node t=q.poll();
// if(t.left!=null) q.offer(t.left);
// if(t.right!=null) q.offer(t.right);
// //if(t->fa) cout<<t->fa->val<<" ";
// System.out.print(t.val+" ");
// }
// System.out.println("");
// }
}
void outputSortResult()
{
for(int i=siz-1;i>=0;i--)
System.out.print(sortedArray.get(i)+" ");
System.out.println("");
}
node copyHeap(node a,node b)
{
if(b!=null)
a=new node(b.val,b.fa);
else
return null;
a.left=copyHeap(a.left,b.left);
a.right=copyHeap(a.right,b.right);
return a;
}
int query(node root,String s,int idx)
{
if(idx==s.length()){
return root.val;
}
if(s.charAt(idx)=='1'){
return query(root.right,s,idx+1);
}
else{
return query(root.left,s,idx+1);
}
}
node queryNode(node root,String s,int idx)
{
if(idx==s.length()){
return root;
}
if(s.charAt(idx)=='1'){
return queryNode(root.right,s,idx+1);
}
else{
return queryNode(root.left,s,idx+1);
}
}
void down(int x,node root,int len)
{
int t=x;
if(x*2<=len && query(root,getPath(2*x),0) > query(root,getPath(t),0)) t=2*x;
if(x*2+1<=len && query(root,getPath(2*x+1),0) > query(root,getPath(t),0)) t=2*x+1;
if(x!=t)
{
node a=queryNode(root,getPath(x),0);
node b=queryNode(root,getPath(t),0);
swap(a,b);
down(t,root,len);
}
}
void heapSort(Heap hp)
{
this.sortedArray.clear();
Heap temp=new Heap();
temp.siz=hp.siz;
temp.head=copyHeap(temp.head,hp.head);
for(int i=0;i<siz;i++)
{
sortedArray.add(temp.head.val);
String s=getPath(temp.siz--);
temp.head.val=query(temp.head,s,0);
//int val=query(siz)->val;
//cout<<temp.head->val<<endl;
down(1,temp.head,temp.siz);
//output(temp.head);
}
}
//use an array to build a heap
void arrayBuildHeap(Heap h,List<Integer> v)
{
h.head=null;
h.siz=0;
for(int i=0;i<v.size();i++)
{
insert(v.get(i));
}
}
};
//定义树节点的绘画类
class DefaultBinaryTreeNodePrinter<T> {
/**
* The default top padding.
*/
private static final int DEFAULT_TOP_PADDING = 0;
/**
* The default right padding.
*/
private static final int DEFAULT_RIGHT_PADDING = 0;
/**
* The default bottom padding.
*/
private static final int DEFAULT_BOTTOM_PADDING = 0;
/**
* The default left padding.
*/
private static final int DEFAULT_LEFT_PADDING = 0;
/**
* The default character used to print node corners.
*/
private static final char DEFAULT_CORNER_CHARACTER = '+';
/**
* The default character used to print horizontal node borders.
*/
private static final char DEFAULT_HORIZONTAL_BORDER_CHARACTER = '-';
/**
* The default character used to print vertical node borders.
*/
private static final char DEFAULT_VERTICAL_BORDER_CHARACTER = '|';
/**
* The top padding.
*/
private int paddingTop = DEFAULT_TOP_PADDING;
/**
* The right padding.
*/
private int paddingRight = DEFAULT_RIGHT_PADDING;
/**
* The bottom padding.
*/
private int paddingBottom = DEFAULT_BOTTOM_PADDING;
/**
* The left padding.
*/
private int paddingLeft = DEFAULT_LEFT_PADDING;
/**
* The character used to represent top left corners.
*/
private char topLeftCornerCharacter = DEFAULT_CORNER_CHARACTER;
/**
* The character used to represent top right corners.
*/
private char topRightCornerCharacter = DEFAULT_CORNER_CHARACTER;
/**
* The character used to represent bottom left corners.
*/
private char bottomLeftCornerCharacter = DEFAULT_CORNER_CHARACTER;
/**
* The character used to represent bottom right corners.
*/
private char bottomRightCornerCharacter = DEFAULT_CORNER_CHARACTER;
/**
* The character used to print the top border.
*/
private char topBorderCharacter = DEFAULT_HORIZONTAL_BORDER_CHARACTER;
/**
* The character used to print the right border.
*/
private char rightBorderCharacter = DEFAULT_VERTICAL_BORDER_CHARACTER;
/**
* The character used to print the bottom border.
*/
private char bottomBorderCharacter = DEFAULT_HORIZONTAL_BORDER_CHARACTER;
/**
* The character used to print the left border.
*/
private char leftBorderCharacter = DEFAULT_VERTICAL_BORDER_CHARACTER;
public TextSprite print(node Node) {
String value = String.valueOf(Node.val);
String[] lines = value.split("\n");
int maximumLineLength = getMaximumLineLength(lines);
int width = 2 + paddingLeft + paddingRight + maximumLineLength;
int height = 2 + paddingTop + paddingBottom + lines.length;
TextSprite textSprite = new TextSprite(width, height);
printCorners(textSprite);
printBorders(textSprite);
printLines(textSprite, lines);
Utils.setEmptyTextSpriteCellsToSpace(textSprite);
return textSprite;
}
public int getTopPadding() {
return paddingTop;
}
public int getRightPadding() {
return paddingRight;
}
public int getBottomPadding() {
return paddingBottom;
}
public int getLeftPadding() {
return paddingLeft;
}
public char getTopLeftCornerCharacter() {
return topLeftCornerCharacter;
}
public char getTopRightCornerCharacter() {
return topRightCornerCharacter;
}
public char getBottomLeftCornerCharacter() {
return bottomLeftCornerCharacter;
}
public char getBottomRightCornerCharacter() {
return bottomRightCornerCharacter;
}
public char getTopBorderCharacter() {
return topBorderCharacter;
}
public char getRightBorderCharacter() {
return rightBorderCharacter;
}
public char getBottomBorderCharacter() {
return bottomBorderCharacter;
}
public char getLeftBorderCharacter() {
return leftBorderCharacter;
}
public void setTopPadding(int paddingTop) {
this.paddingTop = checkPaddingTop(paddingTop);
}
public void setRightPadding(int paddingRight) {
this.paddingRight = checkPaddingRight(paddingRight);
}
public void setBottomPadding(int paddingBottom) {
this.paddingBottom = checkPaddingBottom(paddingBottom);
}
public void setLeftPadding(int paddingLeft) {
this.paddingLeft = checkPaddingLeft(paddingLeft);
}
public void setTopLeftCornerCharacter(char c) {
topLeftCornerCharacter = c;
}
public void setTopRightCornerCharacter(char c) {
topRightCornerCharacter = c;
}
public void setBottomLeftCornerCharacter(char c) {
bottomLeftCornerCharacter = c;
}
public void setBottomRightCornerCharacter(char c) {
bottomRightCornerCharacter = c;
}
public void setTopBorderCharacter(char c) {
topBorderCharacter = c;
}
public void setRightBorderCharacter(char c) {
rightBorderCharacter = c;
}
public void setBottomBorderCharacter(char c) {
bottomBorderCharacter = c;
}
public void setLeftBorderCharacter(char c) {
leftBorderCharacter = c;
}
private int checkPadding(int padding, String errorMessage) {
if (padding < 0) {
throw new IllegalArgumentException(
errorMessage + ": the given padding is negative: " +
padding + ". Must be at least 0!");
}
return padding;
}
private int checkPaddingTop(int padding) {
return checkPadding(padding, "Top padding is invalid");
}
private int checkPaddingRight(int padding) {
return checkPadding(padding, "Right padding is invalid");
}
private int checkPaddingBottom(int padding) {
return checkPadding(padding, "Bottom padding is invalid");
}
private int checkPaddingLeft(int padding) {
return checkPadding(padding, "Left padding is invalid");
}
private int getMaximumLineLength(String[] lines) {
int maximumLineLength = 0;
for (String line : lines) {
maximumLineLength = Math.max(maximumLineLength, line.length());
}
return maximumLineLength;
}
private void printCorners(TextSprite textSprite) {
int width = textSprite.getWidth();
int height = textSprite.getHeight();
textSprite.setChar(0, 0, topLeftCornerCharacter);
textSprite.setChar(width - 1, 0, topRightCornerCharacter);
textSprite.setChar(0, height - 1, bottomLeftCornerCharacter);
textSprite.setChar(width - 1, height - 1, bottomRightCornerCharacter);
}
private void printBorders(TextSprite textSprite) {
int width = textSprite.getWidth();
int height = textSprite.getHeight();
for (int x = 1; x < width - 1; ++x) {
textSprite.setChar(x, 0, topBorderCharacter);
textSprite.setChar(x, height - 1, bottomBorderCharacter);
}
for (int y = 1; y < height - 1; ++y) {
textSprite.setChar(0, y, leftBorderCharacter);
textSprite.setChar(width - 1, y, rightBorderCharacter);
}
}
private void printLines(TextSprite textSprite, String[] lines) {
int startY = 1 + paddingTop;
int startX = 1 + paddingLeft;
for (int y = 0; y < lines.length; ++y) {
char[] chars = lines[y].toCharArray();
for (int x = 0; x < chars.length; ++x) {
textSprite.setChar(startX + x, startY + y, chars[x]);
}
}
}
}
class TextSprite {
/**
* The minimum width of a sprite in characters.
*/
private static final int MINIMUM_SPRITE_WIDTH = 1;
/**
* The minimum height of a sprite in characters.
*/
private static final int MINIMUM_SPRITE_HEIGHT = 1;
/**
* The width of this text sprite.
*/
private final int width;
/**
* The height of this text sprite.
*/
private final int height;
/**
* Contains all the characters.
*/
private final char[][] window;
/**
* Constructs a new empty text sprite.
*
* @param spriteWidth the number of text columns.
* @param spriteHeight the number of text rows.
*/
public TextSprite(int spriteWidth, int spriteHeight) {
this.width = checkWidth(spriteWidth);
this.height = checkHeight(spriteHeight);
this.window = new char[spriteHeight*3][spriteWidth*3];
}
/**
* Sets a particular cell to {@code c}.
*
* @param x the x-coordinate of the cell.
* @param y the y-coordinate of the cell.
* @param c the character to set.
*/
public void setChar(int x, int y, char c) {
checkX(x);
checkY(y);
window[y][x] = c;
}
/**
* Reads the content of a particular cell.
*
* @param x the x-coordinate of the cell.
* @param y the y-coordinate of the cell.
* @return the contents of the cell.
*/
public char getChar(int x, int y) {
checkX(x);
checkY(y);
return window[y][x];
}
/**
* Returns the number of columns in this sprite.
*
* @return the number of columns.
*/
public int getWidth() {
return width;
}
/**
* Returns the number of rows in this sprite.
*
* @return the number of rows.
*/
public int getHeight() {
return height;
}
/**
* Applies the input text sprite on top of a rectangle of this text sprite.
*
* @param textSprite the text sprite to apply.
* @param xOffset the horizontal offset from the left border.
* @param yOffset the vertical offset from the top border.
*/
public void apply(TextSprite textSprite, int xOffset, int yOffset) {
Objects.requireNonNull(textSprite, "The input TextSprite is null!");
if (xOffset < 0) {
throw new IndexOutOfBoundsException("xOffset (" + xOffset + ") " +
"may not be negative!");
}
if (yOffset < 0) {
throw new IndexOutOfBoundsException("yOffset (" + yOffset + ") " +
"may not be negative!");
}
if (xOffset + textSprite.getWidth() > getWidth()) {
throw new IndexOutOfBoundsException("xOffset (" + xOffset + ") " +
"is too large! Must be at most " +
(getWidth() - textSprite.getWidth()) + ".");
}
if (yOffset + textSprite.getHeight() > getHeight()) {
throw new IndexOutOfBoundsException("yOffset (" + yOffset + ") " +
"is too large! Must be at most " +
(getHeight() - textSprite.getHeight()) + ".");
}
for (int y = 0; y < textSprite.getHeight(); ++y) {
for (int x = 0; x < textSprite.getWidth(); ++x) {
setChar(xOffset + x, yOffset + y, textSprite.getChar(x, y));
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder((width + 1) * height - 1);
String separator = "";
for (int y = 0; y < height; ++y) {
sb.append(separator);
separator = "\n";
for (int x = 0; x < width; ++x) {
sb.append(getChar(x, y));
}
}
return sb.toString();
}
private int checkWidth(int width) {
if (width < MINIMUM_SPRITE_WIDTH) {
throw new IllegalArgumentException(
"The sprite width is too small (" + width + "). " +
"Must be at least " + MINIMUM_SPRITE_WIDTH + ".");
}
return width;
}
private int checkHeight(int height) {
if (height < MINIMUM_SPRITE_HEIGHT) {
throw new IllegalArgumentException(
"The sprite height is too small (" + height + "). " +
"Must be at least " + MINIMUM_SPRITE_HEIGHT + ".");
}
return height;
}
private void checkX(int x) {
if (x < 0) {
throw new IndexOutOfBoundsException("x = " + x + " is negative.");
} else if (x >= width) {
throw new IndexOutOfBoundsException("x = " + x + " exceeds the " +
"width = " + width);
}
}
private void checkY(int y) {
if (y < 0) {
throw new IndexOutOfBoundsException("y = " + y + " is negative.");
} else if (y >= height) {
throw new IndexOutOfBoundsException("y = " + y + " exceeds the " +
"height = " + height);
}
}
};
//二叉树打印
class DefaultBinaryTreePrinter<T> {
/**
* When combining the text sprites of two sibling subtrees, by default, at
* least one character worth horizontal space will be put between the two
* sprites.
*/
private static final int DEFAULT_MINIMUM_SIBLING_SPACE = 1;
/**
* The default character for printing arrow tips.
*/
private static final char DEFAULT_ARROW_TIP_CHARACTER = 'V';
/**
* The minimum number of spaces between two siblings.
*/
private int siblingSpace = DEFAULT_MINIMUM_SIBLING_SPACE;
/**
* The arrow tip character.
*/
private char arrowTipCharacter = DEFAULT_ARROW_TIP_CHARACTER;
public String print(node root, DefaultBinaryTreeNodePrinter<T> nodePrinter) {
if (root == null) {
return "null";
}
TextSprite textSprite = printImpl(root, nodePrinter).textSprite;
Utils.setEmptyTextSpriteCellsToSpace(textSprite);
return textSprite.toString();
}
public int getSiblingSpace() {
return siblingSpace;
}
public char getArrowTipCharacter() {
return arrowTipCharacter;
}
public void setSiblingSpace(int siblingSpace) {
this.siblingSpace = checkSiblingSpace(siblingSpace);
}
public void setArrowTipCharacter(char arrowTipCharacter) {
this.arrowTipCharacter = arrowTipCharacter;
}
private static final class SubtreeDescriptor {
TextSprite textSprite;
int rootNodeOffset;
int rootNodeWidth;
}
private SubtreeDescriptor printImpl(node node,DefaultBinaryTreeNodePrinter<T> nodePrinter) {
if (node.left == null && node.right == null) {
TextSprite leafNodeTextSprite = nodePrinter.print(node);
SubtreeDescriptor subtreeDescriptor = new SubtreeDescriptor();
subtreeDescriptor.rootNodeOffset = 0;
subtreeDescriptor.rootNodeWidth = leafNodeTextSprite.getWidth();
subtreeDescriptor.textSprite = leafNodeTextSprite;
return subtreeDescriptor;
}
if (node.left != null && node.right != null) {
return printWithTwoChildrenImpl(node, nodePrinter);
}
if (node.left != null) {
return printWithLeftChildImpl(node, nodePrinter);
}
return printWithRightChildImpl(node, nodePrinter);
}
private SubtreeDescriptor printWithTwoChildrenImpl(node node, DefaultBinaryTreeNodePrinter<T> nodePrinter) {
SubtreeDescriptor subtreeDescriptor = new SubtreeDescriptor();
SubtreeDescriptor leftChildDescriptor = printImpl(node.left, nodePrinter);
SubtreeDescriptor rightChildDescriptor = printImpl(node.right, nodePrinter);
TextSprite nodeTextSprite = nodePrinter.print(node);
TextSprite leftChildTextSprite = leftChildDescriptor.textSprite;
TextSprite rightChildTextSprite = rightChildDescriptor.textSprite;
// The height of the resulting text sprite.
int subtreeTextSpriteHeight = 1 + nodeTextSprite.getHeight() +
Math.max(leftChildTextSprite.getHeight(),
rightChildTextSprite.getHeight());
int aLeft = (nodeTextSprite.getWidth() - siblingSpace) / 2;
int aRight = nodeTextSprite.getWidth() - siblingSpace - aLeft;
int bLeft = leftChildTextSprite.getWidth() -
leftChildDescriptor.rootNodeOffset -
leftChildDescriptor.rootNodeWidth;
int leftPartOffset = 0;
if (aLeft + 2 > bLeft + leftChildDescriptor.rootNodeWidth) {
leftPartOffset = aLeft + 2
- bLeft
- leftChildDescriptor.rootNodeWidth;
}
int rightPartOffset = 0;
if (rightChildDescriptor.rootNodeOffset +
rightChildDescriptor.rootNodeWidth < aRight + 2) {
rightPartOffset = aRight + 2 - rightChildDescriptor.rootNodeOffset
- rightChildDescriptor.rootNodeWidth;
}
// The width of the resulting text sprite.
int subtreeTextSpriteWidth =
leftChildTextSprite.getWidth() +
leftPartOffset +
siblingSpace +
rightPartOffset +
rightChildTextSprite.getWidth();
TextSprite subtreeTextSprite = new TextSprite(subtreeTextSpriteWidth,
subtreeTextSpriteHeight);
subtreeTextSprite.apply(leftChildTextSprite,
0,
nodeTextSprite.getHeight() + 1);
subtreeTextSprite.apply(rightChildTextSprite,
leftChildTextSprite.getWidth() +
leftPartOffset +
siblingSpace +
rightPartOffset,
nodeTextSprite.getHeight() + 1);
int leftArrowLength = Math.max(1,
leftChildTextSprite.getWidth() +
leftPartOffset
- aLeft + 1
- leftChildDescriptor.rootNodeOffset
- leftChildDescriptor.rootNodeWidth / 2);
int rightArrowLength = Math.max(1,
rightPartOffset +
rightChildDescriptor.rootNodeOffset +
rightChildDescriptor.rootNodeWidth / 2 -
aRight);
int totalArrowLength = leftArrowLength + rightArrowLength;
int nodeSpriteShift = totalArrowLength / 2 - leftArrowLength;
subtreeTextSprite.apply(nodeTextSprite,
nodeSpriteShift +
leftChildTextSprite.getWidth() +
leftPartOffset - aLeft,
0);
rightArrowLength = totalArrowLength / 2;
leftArrowLength = totalArrowLength - rightArrowLength;
int arrowStartX = leftChildTextSprite.getWidth() + leftPartOffset
- aLeft
+ nodeSpriteShift;
int arrowY = nodeTextSprite.getHeight() - 2;
for (int x = 0; x < leftArrowLength; ++x) {
subtreeTextSprite.setChar(arrowStartX - x , arrowY, '-');
}
subtreeTextSprite.setChar(Math.max(arrowStartX - leftArrowLength,0),
arrowY,
'+');
subtreeTextSprite.setChar(Math.max(arrowStartX - leftArrowLength,0),
arrowY + 1,
'|');
subtreeTextSprite.setChar(Math.max(arrowStartX - leftArrowLength,0),
arrowY + 2,
arrowTipCharacter);
arrowStartX = leftChildTextSprite.getWidth()
+ leftPartOffset
- aLeft
+ nodeTextSprite.getWidth()
+ nodeSpriteShift;
for (int x = 0; x < rightArrowLength; ++x) {
subtreeTextSprite.setChar(arrowStartX + x, arrowY, '-');
}
subtreeTextSprite.setChar(arrowStartX + rightArrowLength, arrowY, '+');
subtreeTextSprite.setChar(arrowStartX + rightArrowLength,
arrowY + 1,
'|');
subtreeTextSprite.setChar(arrowStartX + rightArrowLength,
arrowY + 2,
arrowTipCharacter);
subtreeDescriptor.rootNodeOffset = leftChildTextSprite.getWidth()
+ leftPartOffset
- aLeft;
subtreeDescriptor.rootNodeWidth = nodeTextSprite.getWidth();
subtreeDescriptor.textSprite = subtreeTextSprite;
return subtreeDescriptor;
}
private SubtreeDescriptor printWithLeftChildImpl(
node node,
DefaultBinaryTreeNodePrinter<T> nodePrinter) {
SubtreeDescriptor subtreeDescriptor = new SubtreeDescriptor();
SubtreeDescriptor leftChildDescriptor = printImpl(node.left,
nodePrinter);
TextSprite nodeTextSprite = nodePrinter.print(node);
TextSprite leftChildTextSprite = leftChildDescriptor.textSprite;
// The height of the resulting text sprite.
int subtreeTextSpriteHeight = 1 + nodeTextSprite.getHeight()
+ leftChildTextSprite.getHeight();
int a = (nodeTextSprite.getWidth() - siblingSpace) / 2;
int b = leftChildDescriptor.textSprite.getWidth()
- leftChildDescriptor.rootNodeOffset
- leftChildDescriptor.rootNodeWidth;
int leftPartOffset = 0;
if (a + 2 > b + leftChildDescriptor.rootNodeWidth) {
leftPartOffset = a + 2 - b - leftChildDescriptor.rootNodeWidth;
}
// The width of the resulting text sprite.
int subtreeTextSpriteWidth =
leftChildTextSprite.getWidth() +
leftPartOffset +
nodeTextSprite.getWidth() -
a;
TextSprite subtreeTextSprite = new TextSprite(subtreeTextSpriteWidth,
subtreeTextSpriteHeight);
subtreeTextSprite.apply(nodeTextSprite,
leftChildDescriptor.textSprite.getWidth() +
leftPartOffset - a,
0);
subtreeTextSprite.apply(leftChildTextSprite,
0,
nodeTextSprite.getHeight() + 1);
int arrowLength = Math.max(1, leftChildTextSprite.getWidth() +
leftPartOffset
- a + 1
- leftChildDescriptor.rootNodeOffset
- leftChildDescriptor.rootNodeWidth / 2);
int arrowStartX = leftChildDescriptor.textSprite.getWidth()
+ leftPartOffset - a;
int arrowY = nodeTextSprite.getHeight() - 2;
for (int x = 0; x < arrowLength; ++x) {
subtreeTextSprite.setChar(arrowStartX - x - 1, arrowY, '-');
}
subtreeTextSprite.setChar(arrowStartX - arrowLength, arrowY, '+');
subtreeTextSprite.setChar(arrowStartX - arrowLength, arrowY + 1, '|');
subtreeTextSprite.setChar(arrowStartX - arrowLength, arrowY + 2, '|');
subtreeDescriptor.rootNodeOffset = leftChildTextSprite.getWidth()
+ leftPartOffset - a;
subtreeDescriptor.rootNodeWidth = nodeTextSprite.getWidth();
subtreeDescriptor.textSprite = subtreeTextSprite;
return subtreeDescriptor;
}
private SubtreeDescriptor printWithRightChildImpl(
node node, DefaultBinaryTreeNodePrinter<T> nodePrinter) {
SubtreeDescriptor subtreeDescriptor = new SubtreeDescriptor();
SubtreeDescriptor rightChildDescriptor = printImpl(node.left, nodePrinter);
TextSprite nodeTextSprite = nodePrinter.print(node);
TextSprite rightChildTextSprite = rightChildDescriptor.textSprite;
// The height of the resulting text sprite.
int subtreeTextSpriteHeight = 1 + nodeTextSprite.getHeight()
+ rightChildTextSprite.getHeight();
// Number of spaces on the right side of the sibling separator.
int a = (nodeTextSprite.getWidth() - siblingSpace) / 2;
int rightPartOffset = 0;
if (rightChildDescriptor.rootNodeOffset +
rightChildDescriptor.rootNodeWidth < a + 2) {
rightPartOffset = a + 2 - rightChildDescriptor.rootNodeOffset -
rightChildDescriptor.rootNodeWidth;
}
// The width of the resulting text sprite.
int subtreeTextSpriteWidth =
nodeTextSprite.getWidth()
- a
+ rightPartOffset
+ rightChildTextSprite.getWidth();
TextSprite subtreeTextSprite = new TextSprite(subtreeTextSpriteWidth,
subtreeTextSpriteHeight);
subtreeTextSprite.apply(nodeTextSprite, 0, 0);
subtreeTextSprite.apply(rightChildTextSprite,
nodeTextSprite.getWidth() - a + rightPartOffset,
1 + nodeTextSprite.getHeight());
int arrowLength = Math.max(1,
rightPartOffset +
rightChildDescriptor.rootNodeOffset +
rightChildDescriptor.rootNodeWidth / 2 - a);
int arrowStartX = nodeTextSprite.getWidth();
int arrowY = nodeTextSprite.getHeight() - 2;
for (int x = 0; x < arrowLength; ++x) {
subtreeTextSprite.setChar(arrowStartX + x, arrowY, '-');
}
subtreeTextSprite.setChar(arrowStartX + arrowLength, arrowY, '+');
subtreeTextSprite.setChar(arrowStartX + arrowLength, arrowY + 1, '|');
subtreeTextSprite.setChar(arrowStartX + arrowLength, arrowY + 2, '|');
subtreeDescriptor.rootNodeOffset = 0;
subtreeDescriptor.rootNodeWidth = nodeTextSprite.getWidth();
subtreeDescriptor.textSprite = subtreeTextSprite;
return subtreeDescriptor;
}
private int checkSiblingSpace(int siblingSpace) {
if (siblingSpace < 0) {
throw new IllegalArgumentException("Sibling space is negative: " +
siblingSpace);
}
return siblingSpace;
}
}
class Utils {
public static void setEmptyTextSpriteCellsToSpace(TextSprite textSprite) {
for (int y = 0; y < textSprite.getHeight(); ++y) {
for (int x = 0; x < textSprite.getWidth(); ++x) {
char c = textSprite.getChar(x, y);
if (c == '\u0000') {
textSprite.setChar(x, y, ' ');
}
}
}
}
}
public class MaxHeap {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
boolean flag=true;
Heap h=new Heap();
while(flag)
{
System.out.print("Please input your operation:");
int op=cin.nextInt();
switch (op){
case 0:
System.out.println("Initialize a new heap");
h.init();
System.out.println("Initialization complete!");
break;
case 1:
System.out.print("Insert a key value:");
h.insert(cin.nextInt());
System.out.println("Insert complete!");
break;
case 2:
System.out.print("Increase Key,input a vertex:");
int v=cin.nextInt();
System.out.print("Input the key value:");
h.increaseKey(v,cin.nextInt());
System.out.println("Increase Key complete!");
break;
case 3:
h.heapSort(h);
System.out.println("Heap sort complete!");
break;
case 4:
System.out.println("---------Heap structure----------");
DefaultBinaryTreeNodePrinter<Integer> nodePrinter =
new DefaultBinaryTreeNodePrinter<>();
DefaultBinaryTreePrinter<Integer> printer =
new DefaultBinaryTreePrinter<>();
System.out.println(printer.print(h.head, nodePrinter));
//h.output(h.head);
break;
case 5:
if(h.sortedArray.size()<1){
System.out.println("Heap not sort yet,please do opeation 3 first.");
}
else{
System.out.print("Heapsort result:");
h.outputSortResult();
}
break;
case 6:
System.out.print("Input an array to build a heap.Your array length:");
int len=cin.nextInt();
System.out.print("Input the element:");
List<Integer> arr=new ArrayList<Integer>();
for(int i=0;i<len;i++)
arr.add(cin.nextInt());
h.arrayBuildHeap(h,arr);
System.out.println("Build complete!");
break;
case 9:
System.out.println("exit");
flag=false;
break;
default:
break;
}
}
}
}
项目运行测试结果:
3.Maven项目导出jar包
我们新建一个Maven项目
之后找到项目的pom文件,输入一个maven-plugin-shade的启动依赖。
maven-plugin-shade
必须和Maven构建生命周期中的package
阶段绑定,也就是说,当执行mvn package时会自动触发shade。
我们的项目主类的路径为com.joy187.MaxHeap
:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>maxHeapProject</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<!--你的项目主类名称-->
<mainClass>com.joy187.MaxHeap</mainClass>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
刷新Maven项目后找到package并点击,进行打包操作
打包完成出现success字样:
4.cmd控制台运行项目
项目构建好后,我们找到target
文件夹,里面不带有original的就是我们的可执行jar包了:
在该文件夹中输入cmd进入控制台:
控制台输入指令:
java -jar 项目名称.jar