【数据结构】二叉树顺序结构及实现(一)

简介: 【数据结构】二叉树顺序结构及实现(一)

前言


 在前面的学习中,我们实现了栈与队列的实现。今天我们就通过顺序表来实现二叉树!


a004f90e77cc5b5c625c6fd2b3684e42_1304f5049c4f4a408a4df6230bf1cde5.png


一. 二叉树的顺序结构


我们如何让顺序表和二叉树建立联系呢?


我们可以先对二叉树的每个结点进行编号,通过数组的连续排列建立以下联系:


5f83a0c7ebcc85aa0cdf4953d2caeab2_be49312fb955419db247f7bc0fb63da4.png


这样我们就可以通过数组的下标来模拟实现二叉树了!


5f83a0c7ebcc85aa0cdf4953d2caeab2_be49312fb955419db247f7bc0fb63da4.png


但是普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。


cde7747ff8a2144d593b8f607fae43b0_18b40ce79f1347b8b84630a6bb98756d.png


所以我们的数组存储表示二叉树只适合完全二叉树。


二.堆的概念及结构


b1908d8d19bc5ba3453010ffe35f6ed7_d0fe48ae29b94f44a331bd4bc03821a7.png


简单的来说,堆就是一颗完全二叉树,并且有以下性质:


堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

其中分为小根堆和大根堆:


小根堆:

树中所有父亲都小于等于孩子:


f6d2401f676bec91fd353776e9b4209f_f89d367936324d10b7330b3fbc619dfb.png


大根堆:

树中所有父亲都大于等于孩子


6b213da452199673d16be32262766886_b2140a0239354853b310ba2312b19d0d.png


注意:

在数据结构里面我们所学的栈,堆都是一种数据结构,他们与操作系统

中的栈和堆是两回事,一个是数据结构,一个是操作系统相关的知识,一定不要搞混淆!


三.堆的实现:


typedef int HPDataType;
typedef struct Heap
{
  HPDataType* a;
  int size;
  int capacity;
}HP;
void HeapInit(HP* php);
void HeapDestroy(HP* php);
void HeapPush(HP* php, HPDataType x);
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
bool HeapEmpty(HP* php);
int HeapSize(HP* php);
void AdjustUp(HPDataType* a, int child);
void AdjustDown(HPDataType* a, int n, int parent);




1.堆的插入(向上调整算法):


 先插入一个数到数组的尾上,再进行向上调整算法,直到满足堆。


向上调整算法的条件是:

除了child结点,之前的结点都是堆


e45e8f8f926f40994c38127d9d70b3d5_ad740e4e1f904fb9ad8b531e1b8043e4.png


代码实现:


void AdjustUp(HPDataType* a, int child)
{
  int parent = (child - 1) / 2;
  while (child>0)
  {
  if (a[child] > a[parent])
  {
    swap(&a[child],&a[parent]);
    child = parent;
    parent = (child - 1) / 2;
  }
  else
  {
    break;
  }
  }
}
void HeapPush(HP* php, HPDataType x)
{
  assert(php);
  if (php->capacity == php->size)
  {
  HPDataType* ptr = (HPDataType*)realloc(php->a, sizeof(HPDataType) * php->capacity * 2);
  if (ptr == NULL)
  {
    perror("realloc::fail");
    return;
  }
  php->a = ptr;
  php->capacity *= 2;
  }
  php->a[php->size] = x;
  php->size++;
  AdjustUp(php->a, php->size-1);
}



2.堆的删除(向下调整算法):


 在这里删除堆是指删除堆顶的数据,因为删除堆尾元素没有什么实际的意义。将堆顶的数据与最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。


向下调整算法的条件是:


左右子树都为堆!


df61abfd9fdb0fbfec32b6e4cbe12961_0ae7df0eef554abdaece48964d9b6ad9.png


代码实现:


void HeapPop(HP* php)
{
  assert(php);
  assert(!HeapEmpty(php));
  // 删除数据
  Swap(&php->a[0], &php->a[php->size - 1]);
  php->size--;
  AdjustDown(php->a, php->size, 0);
}
void AdjustDown(HPDataType* a, int n, int parent)
{
  int child = parent * 2 + 1;
  while (child < n)
  {
  // 选出左右孩子中大的那一个
  if (child + 1 < n && a[child+1] > a[child])
  {
    ++child;
  }
  if (a[child] > a[parent])
  {
    Swap(&a[child], &a[parent]);
    parent = child;
    child = parent * 2 + 1;
  }
  else
  {
    break;
  }
  }
}



3.堆的构建:


这里建议把后面的堆排序看了在来看这段代码:


void HeapInitArray(HP* php, int* a, int n)
{
  assert(php);
  php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
  if (php->a == NULL)
  {
  perror("malloc fail");
  return;
  }
  php->size = n;
  php->capacity = n;
  // 建堆
  for (int i = (n-2)/2; i >= 0; --i)
  {
  AdjustDown(php->a, php->size, i);
  }
}



这里的意思是给你一个属数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。

目录
相关文章
|
2天前
【数据结构】二叉树(遍历,递归)
【数据结构】二叉树(遍历,递归
16 2
|
2天前
|
算法 编译器 C语言
数据结构——二叉树四种遍历的实现-3
数据结构——二叉树四种遍历的实现
数据结构——二叉树四种遍历的实现-3
|
2天前
|
存储
数据结构——二叉树四种遍历的实现-2
数据结构——二叉树四种遍历的实现
数据结构——二叉树四种遍历的实现-2
|
2天前
|
机器学习/深度学习
数据结构——二叉树四种遍历的实现-1
数据结构——二叉树四种遍历的实现
数据结构——二叉树四种遍历的实现-1
|
2天前
【数据结构】二叉树的三种遍历(非递归讲解)
【数据结构】二叉树的三种遍历(非递归讲解)
9 1
|
2天前
|
存储
【数据结构】二叉树相关oj题(一)
【数据结构】二叉树相关oj题(一)
10 1
|
2天前
|
存储 分布式数据库
[数据结构]~二叉树
[数据结构]~二叉树
|
2天前
|
C语言
【C语言/数据结构】二叉树(层序遍历|判断完全二叉树|性质)
【C语言/数据结构】二叉树(层序遍历|判断完全二叉树|性质)
280 52
|
2天前
【数据结构】二叉树-堆(top-k问题,堆排序,时间复杂度)
【数据结构】二叉树-堆(top-k问题,堆排序,时间复杂度)
17 4
|
2天前
【数据结构】二叉树-堆(函数实现)
【数据结构】二叉树-堆(函数实现)
13 2