笔者在学习算法导论中的堆排序和优先队列时,迫切的想要实时打印二叉堆
上网找代码时发现大家都是基于这种数据类型写的
typedef struct Node {
ElemType data;
struct Node *LChild;//指向左孩子
struct Node *RChild;//指向右孩子
} BinNode, *BinTree;
可我的堆排序和优先队列用的是数组
偶然找到一个也是用数组的,结果调半天调不明白,有莫名其妙的bug
干脆自己写了个头文件
引用案例1
#include "my_heap.h"
int main() {
int a[20 + 1] = {0,
3, 6, 8, 5, 9,
7, 4, 1, 26, 35,
67, 49, 16, 54, 85,
12, 34, 20, 10, 20};
heap_size = 20;//堆的大小
// display_heap_slash(数组,行宽,字宽)
//数组从下标1开始(即a[0]不算)
//行宽单位是一个字符的宽度
//字宽等于数组中的最大位数(负号算上)
display_heap_slash(a, 63, 2);//格式1
display_heap_vertical(a, 63, 2);//格式2
}
输出:(对了最好用等宽字体)
C:\test_heap.exe
---------------------------------------------------------------
3
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ |
6 8
/ \ / \
/ \ / \
/ \ / \
/ \ / \
/ \ / \
/ \ / |
/ | / |
| | / |
5 9 7 4
/ \ / \ / | /|
/ \ / | / | / |
/ | / | / | / |
| | / | / | / |
| | | | / | / |
| | | | | | / |
1 26 35 67 49 16 54 85
/ | /| /
| | / | /
| | | | /
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
12 34 20 10 20
---------------------------------------------------------------
---------------------------------------------------------------
3
|
6 ------------------------------8
| |
5 --------------9 7 --------------4
| | | |
1 ------26 35------67 49------16 54------85
| | |
12--34 20--10 20-
---------------------------------------------------------------
进程已结束,退出代码0
引用案例2
#include "my_heap.h"
int heap[1000] = {0};//为方便使用,从1开始
int length;
void error(const string &error_content) {//报错
cout << error_content << endl;
}
int parent(int i) {//父节点
return i >> 1;
}
int left(int i) {//左孩子
return i << 1;
}
int right(int i) {//右孩子
return (i << 1) + 1;
}
void max_heapify(HeapType *a, int i) {//维护最大堆性质,与较大子节点交换
int l = left(i), r = right(i), largest;
if (l <= heap_size && a[l] > a[i])
largest = l;
else largest = i;
if (r <= heap_size && a[r] > a[largest])
largest = r;
if (largest != i) {
exchange(&a[i], &a[largest]);
max_heapify(a, largest);
}
}
void build_max_heap(HeapType *a, int length) {//建堆,维护新堆最大堆性质
heap_size = length;
for (int i = length / 2; i >= 1; --i) {
max_heapify(a, i);
}
}
void size_error() {//下溢报错
error("heap_underflow");
}
void key_error() {
error("new key is smaller than current key");
}
int heap_maximum(int *a) {//1.返回优先队列最大key元素
cout << endl;
cout << "the element with max key is :>" << a[1] << endl;
return a[1];
}
int heap_extract_max(int *a) {//2.返回并去除优先队列最大key元素
if (heap_size < 1) {
size_error();
return EOF;
}
heap_maximum(a);
cout << "now it has been moved." << endl;
int max = a[1];
a[1] = a[heap_size];
heap_size--;
max_heapify(a, 1);
return max;
}
void heap_increase_key(int *a, int i, int key) {//3.将元素i的关键字值增加到key
if (key < a[i]) {
key_error();
return;
}
cout << "the no." << i << " element has been increased!" << endl;
cout << "previous:" << a[i] << "->now:" << key << endl;
a[i] = key;
while (i > 1 && a[parent(i)] < a[i]) {
exchange(&a[i], &a[parent(i)]);
i = parent(i);
}
}
void max_heap_insert(int *a, int key) {//4.把元素i插入集合a中
cout << "now insert a new element with the value of " << key << "." << endl;
heap_size++;
a[heap_size] = MIN;
heap_increase_key(a, heap_size, key);
}
void optimized_max_heap_increase_key(int *a, int i, int key) {
//函数heap_increase_key的优化
//使得交换部分只需要赋值一次(原函数第67行)
//练习6.5-6
if (i > heap_size) {
size_error();
return;
}
if (key < a[i]) {
key_error();
return;
}
cout << "now insert a new element with the value of " << key << "." << endl;
while (i > 1 && a[parent(i)] < key) {
a[i] = a[parent(i)];
i = parent(i);
}
a[i] = key;
}
void max_heap_delete(int *a, int i) {
//从集合a中删去元素i
//练习6.5-8
if (i > heap_size) {
size_error();
return;
}
cout << "now the no." << i << " element(" << a[i] << ") has been moved!" << endl;
if (a[heap_size] <= a[i]) {
a[i] = a[heap_size];
heap_size--;
max_heapify(a, i);
} else {
heap_increase_key(a, i, a[heap_size]);
heap_size--;
}
}
int main() {
cout << "input length :>";
cin >> length;
heap_size = length;
for (int i = 1; i <= length; ++i) {
cin >> heap[i];
}
build_max_heap(heap, length);
// display_heap_slash(heap,63,2);
display_heap_vertical(heap, 63, 2);
max_heap_delete(heap, 2);
display_heap_vertical(heap, 63, 2);
max_heap_insert(heap, 50);
display_heap_vertical(heap, 63, 2);
heap_maximum(heap);
display_heap_vertical(heap, 63, 2);
heap_increase_key(heap, 7, 60);
display_heap_vertical(heap, 63, 2);
heap_extract_max(heap);
display_heap_vertical(heap, 63, 2);
max_heap_delete(heap, 2);
display_heap_vertical(heap, 63, 2);
return 0;
}
输出:
C:\Users\msiadmin\CLionProjects\ye++\sf_heap_priority_queue.exe
input length :>10
1 23 4 5 6 7 8 9 6 2
---------------------------------------------------------------
23
|
9 ------------------------------8
| |
6 --------------6 7 --------------4
| |
5 ------1 2 ---
---------------------------------------------------------------
now the no.2 element(9) has been moved!
---------------------------------------------------------------
23
|
6 ------------------------------8
| |
5 --------------6 7 --------------4
|
2 ------1
---------------------------------------------------------------
now insert a new element with the value of 50.
the no.10 element has been increased!
previous:-1000000->now:50
---------------------------------------------------------------
50
|
23------------------------------8
| |
5 --------------6 7 --------------4
| |
2 ------1 6 ---
---------------------------------------------------------------
the element with max key is :>50
---------------------------------------------------------------
50
|
23------------------------------8
| |
5 --------------6 7 --------------4
| |
2 ------1 6 ---
---------------------------------------------------------------
the no.7 element has been increased!
previous:4->now:60
---------------------------------------------------------------
60
|
23------------------------------50
| |
5 --------------6 7 --------------8
| |
2 ------1 6 ---
---------------------------------------------------------------
the element with max key is :>60
now it has been moved.
---------------------------------------------------------------
50
|
23------------------------------8
| |
5 --------------6 7 --------------6
|
2 ------1
---------------------------------------------------------------
now the no.2 element(23) has been moved!
---------------------------------------------------------------
50
|
6 ------------------------------8
| |
5 --------------1 7 --------------6
|
2 ---
---------------------------------------------------------------
进程已结束,退出代码0
头文件:(删掉了没用的)
#ifndef YE___MY_HEAP_H
#define YE___MY_HEAP_H
#include "my_include.h"
#include "iostream"
#include "cstring"
#include "cmath"
using namespace std;
#define MAX 1000000;
#define MIN (-1000000);
#define HeapType int//影响第35行输出格式
int heap_size;
HeapType heap_display[1000][1000];
char heap_display_slash[1000][1000] = {0};
char format[1000];
void error(const string &error_content) {//报错
cout << error_content << endl;
}
void exchange(int *a, int *b) {//交换
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
char turn_int_to_char(int i) {
return i + '0';
}
void string_copy_to_from(char *to, char *from) {
strcpy(to, from);
}
void mass_print(char i, int s) {
for (int j = 0; j < s; ++j) {
cout << i;
}
}
void back_space(int i) {
for (int j = 0; j < i; ++j) {
cout << "\b";
}
}
void print_space(int i) {
mass_print(' ', i);
}
void print_delimiter(char ch, int i) {
mass_print(ch, i);
cout << endl;
}
int max_int(int a, int b) {
return a > b ? a : b;
}
int min_int(int a, int b) {
return a < b ? a : b;
}
void display_heap_format(int DataWidth) {
char temp_format[5] = "%-0d";
temp_format[2] = turn_int_to_char(DataWidth);
string_copy_to_from(format, temp_format);
}
void display_heap_frame_left(int p, int l, int p_abscissa, int max) {
int left = heap_display[p_abscissa + 1][l];
int parent = heap_display[p_abscissa][p];
int length = parent - left - 1;
for (int i = 0; i < length; ++i) {
heap_display_slash[i + 1][parent - 1 - i] = '/';
}
for (int i = 0; i < (max - length); ++i) {
heap_display_slash[length + 1 + i][left] = '|';
}
}
void display_heap_frame_right(int p, int r, int p_abscissa, int max) {
int right = heap_display[p_abscissa + 1][r];
int parent = heap_display[p_abscissa][p];
int length = right - parent - 1;
for (int i = 0; i < length; ++i) {
heap_display_slash[i + 1][parent + 1 + i] = '\\';
}
for (int i = 0; i < (max - length); ++i) {
heap_display_slash[length + 1 + i][right] = '|';
}
}
void reset_heap_display_slash(int x, int y) {
for (int i = 1; i <= y; ++i) {
for (int j = 1; j <= x; ++j) {
heap_display_slash[i][j] = 0;
}
}
}
void display_heap_slash(HeapType *a, int ScreenWidth, int DataWidth) {//格式一
//变量
int now_displayed;//目前已打印的数据个数
int now_data_width = ScreenWidth;//当前字宽
int now_screen_width = ScreenWidth;//当前屏宽
int now_number;//当前行所含数据个数
int now_ordinate;//当前纵坐标
int now_abscissa;//当前横坐标
int space_number;//空格数
int max;//斜线行数
//初始化
print_delimiter('-', ScreenWidth);
display_heap_format(DataWidth);
now_displayed = 0;
now_number = 1;
now_abscissa = 1;
now_data_width = now_screen_width / now_number;//当前字宽更新
now_screen_width = now_data_width * now_number;//当前屏宽更新
for (int i = 1; i <= now_number; ++i) {//纵坐标计算
now_ordinate = (now_data_width * (i - 1)) + (now_data_width / 2);
heap_display[now_abscissa][i] = now_ordinate;
}
while (now_displayed < heap_size) {//终止:已打印的数据个数=堆的大小
//本行内
//斜线模组
if (now_abscissa != 1) {
max = 0;
//得到max
for (int i = 1; i <= now_number; ++i) {
int p = (i + 1) / 2;
int temp;
if (i % 2 == 1)
temp = heap_display[now_abscissa - 1][p] - heap_display[now_abscissa][i] - 1;
if (i % 2 == 0)
temp = heap_display[now_abscissa][i] - heap_display[now_abscissa - 1][p] - 1;
max = max_int(max, temp);
}
reset_heap_display_slash(ScreenWidth, ScreenWidth);
for (int i = 1; i <= min_int((heap_size - now_displayed), now_number); ++i) {
int p = (i + 1) / 2;
if (i % 2 == 1) {
display_heap_frame_left(p, i, now_abscissa - 1, max);
} else if (i % 2 == 0) {
display_heap_frame_right(p, i, now_abscissa - 1, max);
}
}
}
//打印斜线
if (now_abscissa != 1) {
for (int i = 1; i <= max; ++i) {
for (int j = 1; j <= ScreenWidth; ++j) {
cout << (!heap_display_slash[i][j] ? ' ' : heap_display_slash[i][j]);
}
cout << endl;
}
reset_heap_display_slash(ScreenWidth, ScreenWidth);
}
for (int i = 1; i <= now_number; ++i) {
if (now_displayed >= heap_size) {
cout << endl;
reset_heap_display_slash(max, ScreenWidth);
print_delimiter('-', ScreenWidth);
return;//终止检测
}
space_number = (now_data_width / 2) - 1;
print_space(space_number);//前空
printf(format, a[now_displayed + 1]);//数据
space_number = now_data_width - 1 - space_number;
print_space(space_number);//后空
back_space(DataWidth - 1);//每输出一个数据后退格
now_displayed++;
}
cout << endl;
//下一行的准备
now_number *= 2;
now_abscissa++;
now_data_width = now_screen_width / now_number;//当前字宽更新
now_screen_width = now_data_width * now_number;//当前屏宽更新
for (int i = 1; i <= now_number; ++i) {//纵坐标计算
now_ordinate = (now_data_width * (i - 1)) + (now_data_width / 2);
heap_display[now_abscissa][i] = now_ordinate;
}
}
print_delimiter('-', ScreenWidth);
}
void display_heap_vertical(HeapType *a, int ScreenWidth, int DataWidth) {//格式二
//变量
int now_displayed;//目前已打印的数据个数
int now_data_width = ScreenWidth;//当前字宽
int last_data_width;//上一行字宽
int now_screen_width = ScreenWidth;//当前屏宽
int now_number;//当前行所含数据个数
int now_ordinate;//当前纵坐标
int now_abscissa;//当前横坐标
int space_number;//空格数
//初始化
print_delimiter('-', ScreenWidth);
display_heap_format(DataWidth);
now_displayed = 0;
now_number = 1;
now_abscissa = 1;
now_data_width = now_screen_width / now_number;//当前字宽更新
now_screen_width = now_data_width * now_number;//当前屏宽更新
for (int i = 1; i <= now_number; ++i) {//纵坐标计算
now_ordinate = (now_data_width * (i - 1)) + (now_data_width / 2);
heap_display[now_abscissa][i] = now_ordinate;
}
while (now_displayed < heap_size) {//终止:已打印的数据个数=堆的大小
//本行内
//竖线
if (now_abscissa != 1) {
space_number = heap_display[now_abscissa - 1][1] - 1;
for (int i = 1; i <= (now_number / 2); ++i) {
if (now_displayed + (2 * i) - 1 > heap_size)
break;
print_space(space_number);
cout << "|";
space_number = last_data_width;
}
cout << endl;
}
space_number = (now_data_width / 2) - 1;
print_space(space_number);//前空
for (int i = 1; i <= now_number; ++i) {
if (now_displayed >= heap_size) {
if (i % 2 == 0) {
space_number = heap_display[now_abscissa - 1][1] - (now_data_width / 2) - 1;
back_space(space_number);
mass_print(' ', space_number);
}
cout << endl;
print_delimiter('-', ScreenWidth);
return;//终止检测
}
printf(format, a[now_displayed + 1]);//数据
space_number = now_data_width;
char temp;
if (i % 2 == 1)
temp = '-';
if (i % 2 == 0)
temp = ' ';
mass_print(temp, space_number);//后空
back_space(DataWidth - 1);//每输出一个数据后退格
mass_print(' ', DataWidth - 1);
back_space(DataWidth - 1);
now_displayed++;
}
back_space(space_number - (DataWidth - 1));
mass_print(' ', space_number - (DataWidth - 1));
cout << endl;
//下一行的准备
now_number *= 2;
now_abscissa++;
last_data_width = now_data_width;
now_data_width = now_screen_width / now_number;//当前字宽更新
now_screen_width = now_data_width * now_number;//当前屏宽更新
for (int i = 1; i <= now_number; ++i) {//纵坐标计算
now_ordinate = (now_data_width * (i - 1)) + (now_data_width / 2);
heap_display[now_abscissa][i] = now_ordinate;
}
}
print_delimiter('-', ScreenWidth);
}
#endif //YE___MY_HEAP_H