二叉树
满二叉树:同时满足两个条件
1.要么有两个孩子,要么没有孩子
2.叶子节点在同一层
规律:
如果是第n层,那么该层的节点数一定是2的n-1次方
总共有多少节点:2的n次方-1
完全二叉树
就是满二叉树从右往左,从下往上删,不是中间删除,就是完全二叉树
满二叉树一定是完全二叉树
完全二叉树不一定是满二叉树
为什么有完全二叉树,因为他虽然是树结构,但并不希望用树结构去描述它(用数组即可描述)
因为完全二叉树除了最后一行,其他的都是有顺序的,可以用下标表示,即有树结构的优点,也有数组的优点。
堆
只要搞定堆,就能搞定完全二叉树
因为堆是特殊的完全二叉树:有序的完全二叉树,即堆
它的有序不一样,是要求父子之间的有序(兄弟或其他节点之间不管)
父大于子:最大堆(大顶堆)
父小于子:最小堆(小顶堆)
用数组去描述堆
父节点下标为n
则 左孩子:2n+1
右孩子:2n+2
所以
已知左孩子下标为m,父节点的下标为:(m-1)/2
已知右孩子下标为m,父节点的下标为:(m-2)/2
已知孩子下标为m,父节点的下标一定为:(m-1)/2【因为左孩子一定是奇数,右孩子一定是偶数】因为能算出来,所以就不需要指针了
时间复杂度是log2n,不是特别稳定
头文件:
#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();
}
}
主文件:
#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;
}