admin 管理员组

文章数量: 887021

数据结构

二叉树的顺序存储

    • 二叉树的概念及结构
    • 二叉树的性质
    • 顺序存储
    • 堆的初始化
    • 堆的插入
    • 堆的删除

二叉树的概念及结构

概念
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树
的二叉树组成。
二叉树的特点:

  1. 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
  2. 二叉树的子树有左右之分,其子树的次序不能颠倒。
    现实中的二叉树

    数据结构中的二叉树

    3.特殊的二叉树
    3.1满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
    3.2完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

二叉树的性质

  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h- 1.
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为 n0, 度为2的分支结点个数为 n2,则有n0=n2+1
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=Log2(n+1). (ps:Log2(n+1)是log以2为
    底,n+1为对数)
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对
    于序号为i的结点有:
  6. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
  7. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
  8. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

顺序存储

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

堆的初始化

先定义一个结构体,malloc一个数组来初始化。

typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;
void HeapInit(HP* php,HPDataType * a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType)*n);if (php->a == NULL)//判断是否开辟成功 {printf("malloc fail\n");exit(-1);}memcpy(php->a, a, sizeof(HPDataType)*n);php->size = n;php->capacity = n;// 建堆for (int i = (n - 2) / 2; i >= 0; --i){AdjustDown(php->a, n, i);}}

建堆的详细介绍

本片文章以建大堆为例
测试一下

	int a[] = { 27, 37, 28, 18, 19, 34, 65,25, 49, 15 };HP hp;HeapInit(&hp, a, sizeof(a) / sizeof(int));PrintfHeap(&hp);//打印

堆的插入

先插入一个到数组的尾上,再进行向上调整算法,直到满足堆。插入数据还需注意空间够不够用,不够则需要扩容。

void AdjustUp(int* 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->size == php->capacity){HPDataType* tmp = realloc(php->a, php->capacity * 2 * sizeof(HPDataType));if (php->a == NULL){printf("realloc fail\n");exit(-1);}php->capacity *= 2;}//size的位置给xphp->a[php->size] = x;php->size++;AdjustUp(php->a,php->size-1);
}



满足大堆。
动态演示:

堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

// 堆的删除
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);}

测试一下

    HeapPop(&hp);PrintfHeap(&hp);HeapPop(&hp);PrintfHeap(&hp);HeapPop(&hp);PrintfHeap(&hp);


删除成功。

源码链接:
提取码:g29w

希望和大家一起进步!

本文标签: 数据结构