二叉树
树的概念
树是一种非线性结构,树是递归定义的。
树形结构中子树之间不能有交集

相关概念
子节点,父节点,兄弟节点
叶节点或终结点,节点的度,树的深度,森林
定义方法
左孩子右兄弟表示法
1 2 3 4 5 6 7
| typedef int DataType; struct TreeNode { struct TreeNode* firstChild1; struct TreeNode* pNextBrother; DataType data; };
|
二叉树的概念和结构
特殊的二叉树
满二叉树:
每一层的节点都达到了最大值,如果有k层。那么最多有2**k-1个节点。
完全二叉树
前k-1层是满的,最后一层从左到右是连续的。高度为h的完全二叉树节点范围是【2^(h-1), 2^h-1】,最后一层最少一个。
完全二叉树不一定是满二叉树
小结论
二叉树的存储方式
二叉树顺序存储是用数组来存储,现实使用只有堆才会用数组来存储。在物理上是数组,在逻辑上是二叉树。

逻辑结构是树的形状,是想象出来的。
物理结构在内存中是用数组存储的。数组表示二叉树仅适用完全二叉树。
物理存储的下标关系:
parent=(child-1)/2 两个孩子算出来的整数部分都是相同的
leftchild=parent*2+1
rightchild=parent*2+2
数组可以存储二叉树,会浪费很多空间。数组存储表示只适用于完全二叉树。
堆
堆总是一个完全二叉树。
小根堆:树中所有父亲都小于等于孩子
大根堆:树中所有父亲都大于等于孩子。堆不一定有序。

操作的是数组,插入数据需要与父辈比较,讨论是否需要交换位置。
堆的实现(以大根堆为例)
Heap.h文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<malloc.h> #include<stdbool.h>
typedef int HPDataType; typedef struct Heap { HPDataType* a; int size; int capacity; }HP;
void HeapInit(HP* php); void AdjustUp(HPDataType* a, int child); void HeapPush(HP* php, HPDataType x); void HeapPop(HP* php); void HeapPrint(HP php); HPDataType HeapTop(HP* php); bool HeapEmpty(); int HeapSize();
|
Heap.c文件
实现插入功能PUSH需要向上调整,向上调整最多调logN次。
实现删除功能POP需要向下调整,向下调整最多调logN次。需要和孩子中较大第一个数交换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
| #define _CRT_SECURE_NO_WARNINGS #include "heap.h"
void HeapInit(HP* php) { assert(php);
php->a = (HPDataType*)malloc(sizeof(HPDataType)*4); if (php->a == NULL) { perror("malloc failed"); return; }
php->size = 0; php->capacity = 4; }
void Swap(HPDataType* p1, HPDataType* p2) { HPDataType tmp = *p1; *p1 = *p2; *p2 = tmp; }
void AdjustUp(HPDataType* a, int child) { int parent = (child - 1) / 2; while (child > 0) { if (a[child] > a[parent]) { Swap(&a[parent], &a[child]); child = parent; parent = (child - 1) / 2; } else { break; } } }
void HeapPush(HP* php, HPDataType x) { assert(php);
if (php->size == php->capacity) { HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * php->capacity * 2); if (tmp == NULL) { perror("realloc failed"); return; }
php->a = tmp; php->capacity *= 2; }
php->a[php->size] = x; php->size++;
AdjustUp(php->a, php->size - 1);
}
void AdjustDown(HPDataType* a, int n, int parent) { int child = parent * 2 + 1; while (child < n) { if (child+1<n && a[child] < a[child + 1]) { ++child; } if(a[child]>a[parent]) { Swap(&a[child], &a[parent]); parent = child; child = parent * 2 + 1; } else { break; } } }
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 HeapPrint(HP php) { HPDataType x = php.size; for (int i = 0; i < x; i++) { printf("%d ", php.a[i]); } printf("\n"); }
HPDataType HeapTop(HP* php) { assert(php); return php->a[0]; }
bool HeapEmpty(HP* php) { assert(php); return php->size == 0; }
int HeapSize(HP* php) { assert(php); return php->size; }
|
Test.c文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include "heap.h" int main() { HP hp; HeapInit(&hp);
HeapPush(&hp, 1); HeapPush(&hp, 5); HeapPush(&hp, 6); HeapPush(&hp, 7); HeapPush(&hp, 9); HeapPush(&hp, 2); HeapPush(&hp, 29); HeapPush(&hp, 72); HeapPush(&hp, 1022); HeapPrint(hp);
HeapPop(&hp); HeapPrint(hp);
while (!HeapEmpty(&hp)) { printf("%d ", HeapTop(&hp)); HeapPop(&hp); }
return 0; }
|
堆的排序
时间负责度为O(N*logN),冒泡排序的时间复杂度为O(N*N)
升序排列最好建立大堆。
先交换首尾,再向下调整选出次大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<malloc.h> #include<stdbool.h>
typedef int HPDataType; typedef struct Heap { HPDataType* a; int size; int capacity; }HP;
void HeapInit(HP* php) { assert(php);
php->a = (HPDataType*)malloc(sizeof(HPDataType) * 4); if (php->a == NULL) { perror("malloc failed"); return; }
php->size = 0; php->capacity = 4; }
void Swap(HPDataType* p1, HPDataType* p2) { HPDataType tmp = *p1; *p1 = *p2; *p2 = tmp; }
void AdjustUp(HPDataType* a, int child) { int parent = (child - 1) / 2; while (child > 0) { if (a[child] > a[parent]) { Swap(&a[parent], &a[child]); child = parent; parent = (child - 1) / 2; } else { break; } } }
void AdjustDown(HPDataType* a, int n, int parent) { int child = parent * 2 + 1; while (child < n) { if (child + 1 < n && a[child] < a[child + 1]) { ++child; } if (a[child] > a[parent]) { Swap(&a[child], &a[parent]); parent = child; child = parent * 2 + 1; } else { break; } } }
void HeapSort(int* a, int n) { HP hp; HeapInit(&hp);
for (int i = 1; i < n; i++) { AdjustUp(a, i); }
int end = n - 1; while (end > 0) { Swap(&a[0], &a[end]); AdjustDown(a, end, 0); --end; }
}
int main() { int a[10] = { 2,1,5,6,3,4,7,8,9,0 };
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); } printf("\n");
HeapSort(a, 10);
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); } printf("\n"); return 0; }
|