binary tree
Full binary tree: satisfy two conditions at the same time
1. Either have two kids or have no kids
2. Leaf nodes are on the same layer
law:
If it is the nth layer, then the number of nodes in this layer must be 2 to the n-1th power
How many nodes are there in total: 2 to the nth power -1
complete binary tree
That is, a full binary tree is deleted from right to left, from bottom to top, not deleted in the middle, or a complete binary tree
A full binary tree must be a complete binary tree
A complete binary tree is not necessarily a full binary tree
Why is there a complete binary tree, because although it is a tree structure, it does not want to describe it with a tree structure (it can be described with an array)
Because except for the last row of a complete binary tree, everything else is in order and can be represented by subscripts, that is, it has the advantages of a tree structure and an array.
heap
As long as you get the heap, you can get the complete binary tree
Because the heap is a special complete binary tree: an ordered complete binary tree, the heap
Its order is different, it requires the order between father and son (no matter between brothers or other nodes)
Parent is greater than child: max heap (big top heap)
Parent is smaller than child: min heap (small top heap)
Use an array to describe the heap
The subscript of the parent node is n
Then the left child: 2n+1
Right child: 2n+2
so
It is known that the subscript of the left child is m, and the subscript of the parent node is: (m-1)/2
It is known that the subscript of the right child is m, and the subscript of the parent node is: (m-2)/2
It is known that the subscript of the child is m, and the subscript of the parent node must be: (m-1)/2 [because the left child must be an odd number, and the right child must be an even number] because it can be calculated, so there is no need for a pointer
The time complexity is log2n, not particularly stable
head File:
#pragma once
//小顶堆
#include<iostream>
using namespace std;
//不需要写节点来搞指针,因为做的是数组
template<class T>
class myHeap
{
public:
myHeap()
{
pRoot = NULL;
len = maxLen = 0;
}
~myHeap()
{
if (pRoot)
{
delete[]pRoot;
};
pRoot = NULL; len = maxLen = 0;
}
//数组需要什么函数,它就需要什么函数
//插入
void insertNode(const T& data);
//删除
void deleteNode(const T& data);
//删除堆顶 这个比较特殊
T pop();
//遍历
void travel();
//直接用数组的方式来构建堆
void initHeap(T* arr, int size);
public:
T* pRoot; //指向根节点的指针
size_t len; //元素个数
size_t maxLen; //容量
};
//插入
template<class T>
void myHeap<T>::insertNode(const T& data)
{
//要往上做插入排序,因为小顶堆,子大于父
//一开始直接进来,然后比较,覆盖
//1.插入进来
if (maxLen<=len)//需不需要申请内存
{
maxLen = maxLen+(((maxLen >> 1) > 1) ? maxLen >> 1 : 1);
//开内存
T* pNew = new T[maxLen];
if (pRoot)
{
memcpy(pNew, pRoot, sizeof(T) * len);
delete[] pRoot;
}
pRoot = pNew;
}
//上面开内存是可以省略的
#if 0 //下面可以优化
pRoot[len++] = data;
//2.循环和父节点比较,如果冲突,交换,不冲突,循环结束(和插入排序很像)
if (len==1)//根节点进来直接结束
{
return;
}
int currentIdx = len - 1;//插入数的下标
int parentIdx = (currentIdx - 1) / 2;
while (1)
{
if (currentIdx<=0)//没有父节点
{
break;
}
parentIdx = (currentIdx - 1) / 2;
if (pRoot[parentIdx]<pRoot[currentIdx])//不冲突则循环结束
{
break;
}
//交换
temp = pRoot[currentIdx];
pRoot[parentIdx]; = pRoot[currentIdx];
pRoot[currentIdx] = temp;
//上移
currentIdx = parentIdx;
}
#else //优化部分
if (len==0)
{
pRoot[len++] = data;
return;
}
int currentIdx = len;//插入数的下标
int parentIdx = (currentIdx - 1) / 2;
//数据先放进来
pRoot[currentIdx] = data;
while (1)
{
if (currentIdx <= 0)//没有父节点
{
break;
}
parentIdx = (currentIdx - 1) / 2;
if (pRoot[parentIdx] < pRoot[currentIdx])//不冲突则循环结束
{
break;
}
//冲突,父节点覆盖子节点
pRoot[currentIdx] = pRoot[parentIdx];
currentIdx = parentIdx;
}
//新数据覆盖回来
pRoot[currentIdx] = data;
//个数的增加
len++;
#endif // 0
}
//删除
template<class T>
void myHeap<T>::deleteNode(const T& data)
{
}
//删除堆顶 这个比较特殊
template<class T>
T myHeap<T>::pop()
{
if (len==0)
{
cout << "堆是空的"<<endl;
return (T)0;
}
if (len == 1)//只有一个
{
len--;
return pRoot[0];
}
//临时保存堆顶元素
T temp = pRoot[0];
//最后一个覆盖堆顶
pRoot[0] = pRoot[len - 1];
int currentIdx = 0;//从堆顶开始
int minChild;// 最小的孩子
while (1)
{
if ((currentIdx * 2 + 1) > (len - 1)||(currentIdx * 2 + 2) > (len - 1))//数组结束
{
break;
}
// 找到最小的孩子
minChild = currentIdx * 2 + 1;//假定左孩子比较小
if (pRoot[minChild]>pRoot[minChild+1])//如果左比右大,右小
{
minChild++;
}
if (pRoot[len-1]<pRoot[minChild])
{
break;
}
// 进行交换(覆盖)
pRoot[currentIdx] = pRoot[minChild];
currentIdx = minChild;
}
//临时保存的堆顶元素覆盖回来
pRoot[currentIdx] = pRoot[len-1];
//结束
len--;
return temp;
}
//遍历
template<class T>
void myHeap<T>::travel()
{
cout << "heap:";
for (int i = 0; i < len; i++)
{
cout << pRoot[i] << " ";
}
cout<< endl;
}
//直接用数组的方式来构建堆
template<class T>
void myHeap<T>::initHeap(T* arr, int size)
{
//开内存
maxLen= size;
len = 0;
pRoot = new T[size];
//数据进入
pRoot[len++] = arr[0];
int currentIdx = len;//插入数的下标
int parentIdx = (currentIdx - 1) / 2;
for (int i = 1; i < size; i++)
{
currentIdx = len;
parentIdx = (currentIdx - 1) / 2;
//数据先放进来
pRoot[currentIdx] = arr[i];
while (1)
{
if (currentIdx <= 0)//没有父节点
{
break;
}
parentIdx = (currentIdx - 1) / 2;
if (pRoot[parentIdx] < pRoot[currentIdx])//不冲突则循环结束
{
break;
}
//冲突,父节点覆盖子节点
pRoot[currentIdx] = pRoot[parentIdx];
currentIdx = parentIdx;
}
//新数据覆盖回来
pRoot[currentIdx] = arr[i];
//个数的增加
len++;
travel();
}
}
main file:
#include"SmallDui.h"
int main()
{
int arr[9] = { 1992,636,54,87,542,88 ,77,8888,932};
myHeap<int> h;
#if 0
for (int i = 0; i < 9; i++)
{
h.insertNode(arr[i]);
h.travel();
}
#else
h.initHeap(arr, 9);
//堆排序,删除出来是有序的
for (int i = 0; i < 9; i++)
{
cout<<h.pop() << endl;
h.travel();
}
#endif // 0
while (1)
{
}
return 0;
}