堆
1,头文件
#pragma once
#include<iostream>
using std::cout;
using std::endl;
//小顶堆
template<typename T>
class heap
{
public:
heap():pRoot(NULL),len(0),maxLen(0){}
~heap()
{
pRoot = NULL;
len = 0;
maxLen = 0;
}
void insertNode(const T& data);//插入
void insertNode1(int*arr);
void travel();//遍历
T pop();//删除堆顶
private:
T* pRoot;//指向根结点的指针 数组首地址
int len;//元素个数 数组长度
int maxLen;//容量
private:
void _clear();//堆的删除(堆排序)
};
/*
堆的插入:(小顶堆)
1 直接放堆中
2 临时保存新插入元素
3 往上检查是否冲突(注意是用父结点和新插入元素比较)
如果不冲突,或者不能再往上了,插入完毕:
冲突:父结点覆盖子节点
4 新插入元素覆盖当前位置
*/
template<typename T>
inline void heap<T>::travel()
{
cout << "heap:";
for (int i = 0; i < 10; i++)
{
cout << pRoot[i] << " ";
}
cout << endl;
}
/*
堆的删除:(堆排序)
1 删堆顶 先输出堆顶
2 最后一个元素覆盖堆顶元素
3 从堆顶开始,往下循环(不要越界,如果比孩子中最小的还小,就停止
3.1 找出左右孩子中较小的那一个
3.2 用孩子覆盖父结点
*/
template<typename T>
T heap<T>::pop()
{
if (0 == len)return (T)0;
if (1 == len)
{
cout << "删掉了:" << pRoot[0] << endl;
len--;
return pRoot[0];
}
//1 删堆顶 先输出堆顶
T temp = pRoot[0];
//2 最后一个元素覆盖堆顶元素
pRoot[0] = pRoot[len - 1];
//3 从堆顶开始, 往下循环(不要越界, 如果比孩子中最小的还小, 就停止
int CurrentIdx = 0;
int MinChildIdx;
while (1)
{
if (CurrentIdx >= len/2-1)break;
MinChildIdx = CurrentIdx * 2 + 1;
//确定孩子中最小的那一个
if (pRoot[MinChildIdx] > pRoot[MinChildIdx + 1])
{
MinChildIdx += 1;
}
if (pRoot[len - 1] < pRoot[MinChildIdx])
{
break;
}
// 用孩子覆盖父结点
pRoot[CurrentIdx] = pRoot[MinChildIdx];
//当前结点变化
CurrentIdx = MinChildIdx;
}
//覆盖回来
pRoot[CurrentIdx] = pRoot[len - 1];
len--;
cout << "删掉了:" << temp << endl;
return temp;
}
template<typename T>
inline void heap<T>::_clear()
{
}
template<typename T>
inline void heap<T>::insertNode(const T& data)
{
if (maxLen <= len)
{
maxLen = maxLen + (((maxLen >> 1) > 1) ? (maxLen >> 1) : 1);
T* pNew = new T[maxLen];
memcpy(pNew, pRoot, sizeof(T) * len);
delete[] pRoot;
pRoot = pNew;
}
//如果父为0
if (0 == len)
{
pRoot[len++] = data;
return;
}
//1 直接放进来
int CurrentIdx = len;//插入数据的下标
pRoot[CurrentIdx] = data;
int ParentIdx = (CurrentIdx - 1) / 2;
//2 临时存储新插入数据
//3 循环 没有父或者不冲突就结束
//while(CurrentIdx>0&&pRoot[CurrentIdx]<pRoot[ParentIdx])
while (1)
{
if (CurrentIdx <= 0)break;
ParentIdx = (CurrentIdx - 1) / 2;
if (data > pRoot[ParentIdx])break;
//冲突,父结点覆盖子节点
pRoot[CurrentIdx] = pRoot[ParentIdx];
//上升
CurrentIdx = ParentIdx;
}
//4 新插入数据覆盖到当前位置
pRoot[CurrentIdx] = data;
len++;
}
/*
template<typename T>
inline void heap<T>::insertNode1(int* arr)
{
//1 先直接开内存, 整个数组入堆
len = 10;
pRoot = new T[10];
for (int i = 0; i < 10; i++)
{
pRoot[i] = arr[i];
}
/*int a=pRoot[CurrentIdx];
int b = pRoot[ParentIdx];*/
//2 从当前无序堆的最后一个元素开始循环 下标为n(len - 1 到1)
//while (LastIdx)
//{
// while ((pRoot[LastIdx] < pRoot[ParentIdx])&& LastIdx !=0)
// {
// int t = pRoot[LastIdx];
// pRoot[LastIdx] = pRoot[ParentIdx];
// pRoot[ParentIdx] = t;
// }
// LastIdx = ParentIdx;
// LastIdx--;
//}
//3 循环中循环拿当前元素pRoot[n]和它的父节点比较,
//一直到下标为0 如果冲突就交换
int t;
for (int i = 0; i <= len - 2; i++)//轮数
{
for (int j = 0; j <= len - 2 - i; j++)//每一轮j交换范围
{
if (pRoot[j] > pRoot[j + 1])
{
t = pRoot[j];
pRoot[j] = pRoot[j + 1];
pRoot[j + 1] = t;
}
}
}
}
2,源文件
/*
满二叉树:同时满足以下两个特征的二叉树
特征一:节点要么有两个孩子,要么没孩子;
特征二:叶子节点在同一层(高度相同);
完全二叉树:一个满二叉树 从最底层(叶子节点)从右往左删;
满二叉树一定是完全二叉树;
完全二叉树不一定是满二叉树;
已知父结点下标为n:
左孩子下标为:2*n+1
右孩子下标为:2*n+2
已知左孩子m:
父结点为:(m-1)/2
已知右孩子m:
父结点为:(m-2)/2
由于右孩子下标一定是偶数,所以:
已知孩子下标为m,其父结点下标(m-1)/2;
堆:有序的完全二叉树;
堆的有序和有序二叉树的有序不同,堆的有序只是父子之间;
分类:
大顶堆(最小堆):父大于子
小顶堆(最大堆):子大于父
兄弟之间无序;
*/
#include "heap.h"
#include<stdio.h>
int main()
{
int arr[10] = { 89,45,66,78,93,24,454,61,20,17 };
heap<int> h;
h.insertNode1(arr);
h.travel();
/*for (int i = 0; i < 10; i++)
{
h.pop();
h.travel();
}*/
return 0;
}