01 昨天课程回顾
02 二叉树非递归遍历思路
用栈
03 二叉树的非递归遍历代码实现
非递归遍历二叉树
思路: 讲二叉树结点包装成一个新的结构体,增加一个flag 初始化值为false
第一次把根节点压入栈
如果栈中元素非空,进行循环:
{
从栈中弹出首部元素
如果该元素node为 null 跳过这次循环,
否则 将该元素flag设置为true // 当设置为true的时候 意味着这个节点在将来某个时刻会被访问
找到该元素 左结点 右结点 分别进行包装
对于先序遍历DLR
入栈顺序应该相反, RLD
将包装好的右结点 左节点 结点 分别入栈
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkstack.h"
#define MY_FALSE 0
#define MY_TRUE 1
// 二叉树结点
typedef struct BINARYNODE {
char ch;
struct BINARYNODE * lchild;
struct BINARYNODE * rchild;
} BinaryNode;
// 栈中元素结构体:结构体存放一个 二叉树 和一个 flag
typedef struct BITREESTACKNODE {
LinkNode node;
BinaryNode * root;
int flag;
} BiTreeStackNode;
// 创建栈中的结点
BiTreeStackNode * CreateBiTreeStackNode(BinaryNode * node,int flag) {
// 在堆上分配空间 创建newnode
BiTreeStackNode * newnode = (BiTreeStackNode *)malloc(sizeof(BiTreeStackNode));
// root值是node
newnode->root = node;
// flag是flag
newnode->flag = flag;
// 返回newnode
return newnode;
}
// 非递归遍历
void NonRecursion(BinaryNode * root)
{
// 1.创建栈
LinkStack * stack = Init_LinkStack();
// 2.把根节点扔到栈里
Push_LinkStack(stack, (LinkNode *)CreateBiTreeStackNode(root, MY_FALSE));
// 判断栈是否为空
while (Size_LinkStack(stack) > 0) {
// 先弹出栈顶元素
BiTreeStackNode * node = (BiTreeStackNode *)Top_LinkStack(stack);
Pop_LinkStack(stack);
// 判断弹出的结点是否为空
if (node->root == NULL) {
// 跳过当前循环
continue;
}
// 如果node的 flag标志是true
if (node->flag == MY_TRUE) {
printf("%c",node->root->ch);
}else
{
// 对于先序遍历,压入顺序应该倒过来:先压右 再压左 最后压根
// 对于中序遍历 压入顺序应是 先压右 再压中 最后压左
// 对于后序遍历 压入顺序应该是 先压中 再压右 最后压左
node->flag = MY_TRUE;
// 当前结点右结点入栈
Push_LinkStack(stack, (LinkNode *)CreateBiTreeStackNode(node->root->rchild, MY_FALSE));
// 当前结点入栈
// 压根
Push_LinkStack(stack, (LinkNode *)node);
// 当前结点左结点入栈
Push_LinkStack(stack, (LinkNode *)CreateBiTreeStackNode(node->root->lchild, MY_FALSE));
}
}
}
04 二叉树的创建
结论: 通过中序遍历和先序遍历可以确定一棵树。
通过中序遍历和后序遍历可以确定一棵树
通过先序遍历和后序遍历确定不了一棵树
通过先序遍历结果 确定了根是A
通过中序确定了左子树是DE 右子树是CFB
构造出来了:
#法创建树: (序列化 二叉树)
答:可以。
(https://blog.csdn.net/yusiguyuan/article/details/42687623)
先序和中序,后序和中序需要两个组合才可以唯一确定一颗二叉树。
#法这一个就可以唯一确定一颗二叉树,因为包含了空节点的信息了。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义二叉树结构体
typedef struct BINARYNODE
{
// 存放ch
char ch;
// 存放左子树
struct BINARYNODE * lchild;
// 存放右子树
struct BINARYNODE * rchild;
} BinaryNode;
// 递归
void Recursion(BinaryNode * root) {
// 设置递归退出条件
if (root == NULL) {
return;
}
// DLR
// 打印ch
printf("%c", root->ch);
// 递归左节点
Recursion(root->lchild);
// 递归右结点
Recursion(root->rchild);
}
// 创建二叉树
BinaryNode * CreateBinaryTree()
{
fflush(stdin);
char ch;
scanf("%c",&ch);
BinaryNode * node;
if (ch == '#') {
node = NULL;
}
else {
node = (BinaryNode *)malloc(sizeof(BinaryNode));
node->ch = ch;
node->lchild = CreateBinaryTree();
node->rchild = CreateBinaryTree();
}
return node;
}
int main(void)
{
// 创建树
BinaryNode * root = CreateBinaryTree();
// 打印树
Recursion(root);
printf(" ");
system("pause");
return 0;
}
// A B C D # # P # # # Q
// ???????这段代码根本跑不通… … 但是还是记录下来了 可能是fflush(stdin)的问题
// 资料: fflush(stdin) 清空输入缓冲区 只在老旧的vc编译器下有小 是一个非C官方标准的实现
05 上午课程回顾
二叉树的非递归遍历:
06 排序基本概念
补: 霍夫曼树
07 冒泡排序
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 1 time.h是个啥?
#include <time.h>
// 2.
#include <sys/timeb.h>
#define MAX 100000
long getSystemtime() {
struct timeb tb;
ftime(&tb);
return tb.time * 1000 + tb.millitm;
// 1s = 1000 ms
}
// 交换函数
void Swap(int * a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// C语言中如何创建随机数
// 冒泡排序法
void BubbleSort(int arr[], int length) {
// len:4 arr[4]
for (int i = 0; i < length; i++)
{
for (int j = i; j < length; j++)
{
// 每次把最大的放到后面
if (arr[j]<arr[i])
{
Swap(&arr[i],&arr[j]);
}
}
}
}
// 打印函数
void PrintArray(int arr[],int length) {
for (int i = 0; i < length;i++) {
printf("%d ", arr[i]);
}
printf(" ");
}
int main(void)
{
int arr[MAX];
// 设定随机种子
srand((unsigned int)time(NULL));
for (int i = 0;i<MAX;i++)
{
// 产生0 到MAX的随机数
arr[i] = rand() % MAX;
}
// 排序前
printf("排序前: ");
//PrintArray(arr, MAX);
long t_start = getSystemtime();
BubbleSort(arr,MAX);
long t_end = getSystemtime();
printf("冒泡排序后: ");
//PrintArray(arr, MAX);
printf("冒泡排序%d个元素,所需时间:%ld毫秒 ", MAX, t_end - t_start);
printf(" ");
system("pause");
return 0;
}
/*
问题:
1. include <time.h>
srand((unsigned int)time(NULL));
rand() % MAX
2. #include <sys/timeb.h> // 精确到毫秒?
*/
08 冒泡排序改进版
… …注意这种写法里面比较的是i 和 i+1
09 选择排序
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#define MAX 10000
long getSystemtime() {
struct timeb tb;
ftime(&tb);
return tb.time * 1000 + tb.millitm;
// 1s = 1000 ms
}
// 交换函数
void Swap(int * a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// 打印函数
void PrintArray(int arr[],int length) {
for (int i = 0; i < length;i++) {
printf("%d ", arr[i]);
}
printf(" ");
}
// 选择排序
void SelectSort(int arr[], int length)
{
// 选择排序减少了交换次数
for (int i = 0;i<length;i++)
{
int min = i;
for (int j = i + 1; j < length;j++ ){
if (arr[j]<arr[min]) {
min = j;
}
}
if (min != i) {
Swap(&arr[min],&arr[i]);
}
}
}
// C语言中如何创建随机数
// 冒泡排序法
void BubbleSort(int arr[], int length) {
int flag = 0; // 0 标识没有排序好
// 代表外层循环
for (int i = 0; i < length && flag == 0; i++)
{
flag = 1; // 认为已经排序好了
for (int j = i; j < length - 1; j++)
{
// 内层循环如果走了一遍都没有发生交换
// 每次把最大的放到后面
if (arr[j] > arr[j + 1])
{
flag = 0;
Swap(&arr[j + 1], &arr[j]);
}
}
}
}
int main(void)
{
int arr[MAX];
int arr2[MAX];
srand((unsigned int)time(NULL));
for (int i = 0; i < MAX;i++){
int randNum = rand() % MAX;
arr[i] = randNum;
arr2[i] = randNum;
}
// 冒泡排序
long tbubble_start = getSystemtime();
BubbleSort(arr,MAX);
long tbubble_end = getSystemtime();
printf("冒泡排序%d个元素,所需时间:%ld ",MAX,tbubble_end-tbubble_start);
// 选择排序
long tselect_start = getSystemtime();
SelectSort(arr2, MAX);
long tselec_end = getSystemtime();
printf("选择排序%d个元素,所需时间:%ld ", MAX, tselec_end - tselect_start);
printf(" ");
system("pause");
return 0;
}
选择排序:
// 选择排序
function select(arr)
{
for (let i = 0;i<arr.length;i++)
{
let min = i
for(let j = i+1 ;j<arr.length;j++)
{
if(arr[i] < arr[min])
min = i
}
// 每次交换后 将最小的放在相应位置
// 相比冒泡排序 减少了交换的次数
if(min != i){
swap(arr[i],arr[min])
}
}
}
10 插入排序
- 将无序序列插入到有序序列中
(希尔排序就是对这两个情况的改进)
// 插入排序
void InsertSort(int arr[],int length) {
int j;
for (int i = 1;i<length;i++)
{
if (arr[i] < arr[i - 1]) {
// 插入排序
int temp = arr[i];
for (j = i-1; j >= 0 && arr[j] > temp ; j-- )
{
arr[j + 1] = arr[j];
}
// 循环退出时候j指向前一个元素.. 之前所有的都交换了
// 最后把这个也给交换过去
arr[j + 1] = temp;
}
}
}
11 插入排序代码实现
12 插入排序代码思路梳理
13 希尔排序思路
在插入排序的基础上进行分组:
14 希尔排序
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#define MAX 100000
long getSystemtime() {
struct timeb tb;
ftime(&tb);
return tb.time * 1000 + tb.millitm;
// 1s = 1000 ms
}
// 交换函数
void Swap(int * a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
// 打印函数
void PrintArray(int arr[],int length) {
for (int i = 0; i < length;i++) {
printf("%d ", arr[i]);
}
printf(" ");
}
// 选择排序
void SelectSort(int arr[], int length)
{
// 选择排序减少了交换次数
for (int i = 0;i<length;i++)
{
int min = i; // min此时为0
for (int j = i + 1; j < length;j++ ){
if (arr[j]<arr[min]) {
min = j;
}
}
if (min != i) {
Swap(&arr[min],&arr[i]);
}
}
}
// C语言中如何创建随机数
// 冒泡排序法
void BubbleSort(int arr[], int length) {
int flag = 0; // 0 标识没有排序好
// 代表外层循环
for (int i = 0; i < length && flag == 0; i++)
{
flag = 1; // 认为已经排序好了
for (int j = i; j < length - 1; j++)
{
// 内层循环如果走了一遍都没有发生交换
// 每次把最大的放到后面
if (arr[j] > arr[j + 1])
{
flag = 0;
Swap(&arr[j + 1], &arr[j]);
}
}
}
}
// 插入排序
void InsertSort(int arr[],int length) {
int j;
for (int i = 1;i<length;i++)
{
if (arr[i] < arr[i - 1]) {
// 插入排序
int temp = arr[i];
for (j = i-1; j >= 0 && arr[j] > temp ; j-- )
{
arr[j + 1] = arr[j];
}
// 循环退出时候j指向前一个元素.. 之前所有的都交换了
// 最后把这个也给交换过去
arr[j + 1] = temp;
}
}
}
// 希尔排序
void ShellSort(int arr[], int length)
{
int increasement = length;
int i,j,k;
do {
// 确定分组的增量
increasement = increasement / 3 + 1;
for (int i = 0;i<increasement;i++)
{
// 分组排序
for (j = i + increasement; j < length; j+=increasement) {
if (arr[j] < arr[j-increasement] ) {
int temp = arr[j];
for (k = j - increasement; k >= 0 && temp < arr[k];k-=increasement ) {
arr[k + increasement] = arr[k];
}
arr[k + increasement] = temp;
}
}
}
} while (increasement > 1);
};
// 希尔排序是对插入排序的升级
// 分组 插入排序
/*
先分组 对每一组分别进行插入排序
分别进行插入排序
*/
// 1 元素序列基本有序的情况下
// 2 元素个数比较小的时候
/*
*/
int main(void)
{
int arr[MAX];
int arr2[MAX];
srand((unsigned int)time(NULL));
for (int i = 0; i < MAX;i++){
int randNum = rand() % MAX;
arr[i] = randNum;
arr2[i] = randNum;
}
//PrintArray(arr, MAX);
long tshell_start = getSystemtime();
ShellSort(arr, MAX);
long tshell_end = getSystemtime();
printf("希尔排序%d个元素所需时间:%ld ",MAX,tshell_end - tshell_start);
//PrintArray(arr, MAX);
long tinsert_start = getSystemtime();
InsertSort(arr2, MAX);
long tinsert_end = getSystemtime();
printf("插入排序%d个元素所需时间:%ld ", MAX, tinsert_end - tinsert_start);
printf(" ");
system("pause");
return 0;
}
/*
问题:
1. include <time.h>
srand((unsigned int)time(NULL));
rand() % MAX
2. #include <sys/timeb.h> // 精确到毫秒?
*/
惊了
插入排序:
希尔排序: