1.树和二叉树
1.1树的基本概念
树的定义:
由一个或多个(n≥0)结点组成的有限集合T,有且仅有一个结点称为根(root),
当n>1时,其余的结点分为m(m≥0)个互不相交的有限集合T1,T2,…,Tm。每个集合
本身又是棵树,被称作这个根的子树 。
树的结构特点:
非线性结构,有一个直接前驱,但可能有多个直接后继(1:n)
树的定义具有递归性,树中还有树。
树可以为空,即节点个数为0。
各类名称:
根 即根结点(没有前驱)
叶子 即终端结点(没有后继)
森林 指m棵不相交的树的集合(例如删除A后的子树个数)
有序树 结点各子树从左至右有序,不能互换(左为第一)
无序树 结点各子树可互换位置。
双亲 即上层的那个结点(直接前驱) parent
孩子 即下层结点的子树 (直接后继) child
兄弟 同一双亲下的同层结点(孩子之间互称兄弟)sibling
堂兄弟 即双亲位于同一层的结点(但并非同一双亲)cousin
祖先 即从根到该结点所经分支的所有结点
子孙 即该结点下层子树中的任一结点
结点的度 结点挂接的子树数(有几个直接后继就是几度)
树深度/高度 指所有结点中最大的层数(Max{各结点的层次})
1.2 左孩子右兄弟表示法
左孩子右兄弟表示法可以将一颗多叉树转化为一颗二叉树:即节点有两个指针域,
其中一个指针指向子节点,另一个指针指向其兄弟节点
1.3二叉树概念
1.3.1二叉树基本概念
定义:
n(n≥0)个结点的有限集合,由一个根结点以及两棵互不相交的、分别称为
左子树和右子树的二叉树组成 。
逻辑结构:一对二(1:2)
基本特征:
每个结点最多只有两棵子树(不存在度大于2的结点);
左子树和右子树次序不能颠倒(有序树)。
二叉树性质:
性质1: 在二叉树的第i层上至多有2i-1个结点(i>0)
性质2: 深度为k的二叉树至多有2k-1个结点(k>0)
性质3: 对于任何一棵二叉树,若度为2的结点数有n2个,则叶子数(n0)
必定为n2+1 (即n0=n2+1)
满二叉树:一棵深度为k 且有2k -1个结点的二叉树。
完全二叉树:除最后一层外,每一层上的节点数均达到最大值;在最后一层上
只缺少右边的若干结点。
1.3.2 二叉树遍历
先序:先根、再左子树、再右子树
中序:先左、再根子树、再右子树
后序:先左子树、再右子树、再根
1.使用递归的方式遍历二叉树
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct BinaryTree
{
char c;
struct BinaryTree* Lnode;
struct BinaryTree* Rnode;
};
void foreach_BinaryTree1(struct BinaryTree* b)
{
if (b == NULL)
return;
printf("%c", b->c);
foreach_BinaryTree1(b->Lnode);
foreach_BinaryTree1(b->Rnode);
}
void foreach_BinaryTree2(struct BinaryTree* b)
{
if (b == NULL)
return;
foreach_BinaryTree2(b->Lnode);
printf("%c", b->c);
foreach_BinaryTree2(b->Rnode);
}
void foreach_BinaryTree3(struct BinaryTree* b)
{
if (b == NULL)
return;
foreach_BinaryTree3(b->Lnode);
foreach_BinaryTree3(b->Rnode);
printf("%c", b->c);
}
void test()
{
struct BinaryTree b1 = { 'A',NULL,NULL };
struct BinaryTree b2 = { 'B',NULL,NULL };
struct BinaryTree b3 = { 'C',NULL,NULL };
struct BinaryTree b4 = { 'D',NULL,NULL };
struct BinaryTree b5 = { 'E',NULL,NULL };
struct BinaryTree b6 = { 'F',NULL,NULL };
struct BinaryTree b7 = { 'G',NULL,NULL };
struct BinaryTree b8 = { 'H',NULL,NULL };
b1.Lnode = &b2;
b1.Rnode = &b6;
b2.Rnode = &b3;
b3.Lnode = &b4;
b3.Rnode = &b5;
b6.Rnode = &b7;
b7.Lnode = &b8;
foreach_BinaryTree1(&b1);
printf("\n");
foreach_BinaryTree2(&b1);
printf("\n");
foreach_BinaryTree3(&b1);
printf("\n");
}
int main()
{
test();
return 0;
}
2.使用非递归的方式遍历二叉树
利用栈可以实现二叉树的非递归遍历:
1.给二叉树每个结点设置标志为,默认为0;
2. 将根节点压入栈中
3.执行循环(当栈中元素个数大于0时执行)
4.弹出栈顶元素
5.如果栈顶标志位真,直接输出并进行下一次循环
6.如果标志位假 将标志改为真
7.再将右子树、左子树、根(弹出元素)入栈(这一步决定了遍历方式,由栈的
先入后出的特性,所示的遍历方式为中序遍历)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct BinaryTree
{
char c;
struct BinaryTree* Lnode;
struct BinaryTree* Rnode;
int flag;
};
struct Stack
{
void* buffer[1024];
int m_size;
};
struct Stack* init_Stack()
{
struct Stack* m_stack = malloc(sizeof(struct Stack));
if (m_stack == NULL)
return NULL;
memset(m_stack->buffer, 0, sizeof(void*) * 1024);
m_stack->m_size = 0;
return m_stack;
}
void push_Stack(struct Stack* m_stack, void* value)
{
if (m_stack == NULL || value == NULL)
return;
struct Stack* stack1 = m_stack;
if (stack1->m_size == 1024)
return;
stack1->buffer[stack1->m_size] = value;
stack1->m_size++;
}
void* pop_Stack(struct Stack* m_stack)
{
if (m_stack == NULL)
return NULL;
struct Stack* stack1 = m_stack;
if (stack1->m_size == 0)
return NULL;
void* tempValue = stack1->buffer[stack1->m_size - 1];
stack1->buffer[stack1->m_size - 1] = NULL;
stack1->m_size--;
return tempValue;
}
void foreach_BinaryTree1(struct BinaryTree* b,struct Stack* m_stack)
{
if (b == NULL )
{
printf("错误1\n");
return;
}
if (m_stack == NULL)
{
printf("错误2\n");
return;
}
push_Stack(m_stack, b);
while (m_stack->m_size > 0)
{
struct BinaryTree* temp = pop_Stack(m_stack);
if (temp->flag == 1)
{
printf("%c", temp->c);
continue;
}
else
{
temp->flag = 1;
push_Stack(m_stack, temp->Rnode);
push_Stack(m_stack, temp->Lnode);
push_Stack(m_stack, temp);
}
}
}
void test()
{
struct BinaryTree b1 = { 'A',NULL,NULL ,0};
struct BinaryTree b2 = { 'B',NULL,NULL ,0 };
struct BinaryTree b3 = { 'C',NULL,NULL ,0 };
struct BinaryTree b4 = { 'D',NULL,NULL ,0 };
struct BinaryTree b5 = { 'E',NULL,NULL ,0 };
struct BinaryTree b6 = { 'F',NULL,NULL ,0 };
struct BinaryTree b7 = { 'G',NULL,NULL ,0 };
struct BinaryTree b8 = { 'H',NULL,NULL ,0 };
b1.Lnode = &b2;
b1.Rnode = &b6;
b2.Rnode = &b3;
b3.Lnode = &b4;
b3.Rnode = &b5;
b6.Rnode = &b7;
b7.Lnode = &b8;
struct Stack* m_stack = init_Stack();
foreach_BinaryTree1(&b1, m_stack);
}
int main()
{
test();
return 0;
}
1.3.3 计算二叉树叶子节点数目以及二叉树的深度
注:计算二叉树深度时:
1.根结点左子树高度与根结点右子树高度比较,比较出的最大高度再+1。
2.若左子树还是树,重复步骤1;若右子树还是树,重复步骤1。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct BinaryTree
{
char c;
struct BinaryTree* Lnode;
struct BinaryTree* Rnode;
};
void foreach_BinarySonTree(struct BinaryTree* b,int* p)
{
if (b == NULL)
return;
if (b->Lnode == NULL && b->Rnode == NULL)
{
(*p)++;
}
foreach_BinarySonTree(b->Lnode,p);
foreach_BinarySonTree(b->Rnode,p);
}
int foreach_BinaryHighTree(struct BinaryTree* b)
{
if (b == NULL)
{
return 0;
}
int lhight = foreach_BinaryHighTree(b->Lnode);
int rlight = foreach_BinaryHighTree(b->Rnode);
int hight = lhight > rlight ? lhight + 1 : rlight + 1;
return hight;
}
void test()
{
struct BinaryTree b1 = { 'A',NULL,NULL };
struct BinaryTree b2 = { 'B',NULL,NULL };
struct BinaryTree b3 = { 'C',NULL,NULL };
struct BinaryTree b4 = { 'D',NULL,NULL };
struct BinaryTree b5 = { 'E',NULL,NULL };
struct BinaryTree b6 = { 'F',NULL,NULL };
struct BinaryTree b7 = { 'G',NULL,NULL };
struct BinaryTree b8 = { 'H',NULL,NULL };
b1.Lnode = &b2;
b1.Rnode = &b6;
b2.Rnode = &b3;
b3.Lnode = &b4;
b3.Rnode = &b5;
b6.Rnode = &b7;
b7.Lnode = &b8;
int num_son = 0;
foreach_BinarySonTree(&b1,&num_son);
printf("叶子结点的个数为:%d\n",num_son);
int hight = foreach_BinaryHighTree(&b1);
printf("计算出层数为:%d\n", hight);
}
int main()
{
test();
return 0;
}
1.3.4 拷贝二叉树
按以下步骤来即可:
1.malloc新结点,
2.拷贝左子树,拷贝右子树,让新结点连接左子树,右子树。若左子树还
是树,重复步骤1、2;若右子树还是树,重复步骤1、2。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct BinaryTree
{
char c;
struct BinaryTree* Lnode;
struct BinaryTree* Rnode;
};
struct BinaryTree* copy_BinaryTree(struct BinaryTree* b)
{
if (b == NULL)
return NULL;
struct BinaryTree* newNode = malloc(sizeof(struct BinaryTree));
newNode->Lnode = copy_BinaryTree(b->Lnode);
newNode->Rnode = copy_BinaryTree(b->Rnode);
newNode->c = b->c;
return newNode;
}
void foreach_BinaryTree1(struct BinaryTree* b)
{
if (b == NULL)
return;
printf("%c", b->c);
foreach_BinaryTree1(b->Lnode);
foreach_BinaryTree1(b->Rnode);
}
void free_BinaryTree(struct BinaryTree* b)
{
if (b == NULL)
return;
free_BinaryTree(b->Lnode);
free_BinaryTree(b->Rnode);
free(b);
}
void test()
{
struct BinaryTree b1 = { 'A',NULL,NULL };
struct BinaryTree b2 = { 'B',NULL,NULL };
struct BinaryTree b3 = { 'C',NULL,NULL };
struct BinaryTree b4 = { 'D',NULL,NULL };
struct BinaryTree b5 = { 'E',NULL,NULL };
struct BinaryTree b6 = { 'F',NULL,NULL };
struct BinaryTree b7 = { 'G',NULL,NULL };
struct BinaryTree b8 = { 'H',NULL,NULL };
b1.Lnode = &b2;
b1.Rnode = &b6;
b2.Rnode = &b3;
b3.Lnode = &b4;
b3.Rnode = &b5;
b6.Rnode = &b7;
b7.Lnode = &b8;
struct BinaryTree* new_BinaryTree = copy_BinaryTree(&b1);
foreach_BinaryTree1(new_BinaryTree);
free_BinaryTree(new_BinaryTree);
}
int main()
{
test();
return 0;
}
2.排序算法
2.1排序基本概念
2.1.1概念:
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的数据元素
调整为“有序”的数据元素。
2.1.2排序的稳定性
如果在序列中有两个数据元素r[i]和r[j],它们的关键字k[i] == k [j],
且在排序之前,对象r[i]排在r[j]前面。如果在排序之后,对象r[i]仍在r[j]
前面,则称这个排序方法是稳定的,否则称这个排序方法是不稳定的。
2.2基本排序算法
2.2.1 冒泡排序
冒泡排序是通过内外层循环,对数字进行不断比较,通过一个临时元素来存
储进行比较的元素,如果符合条件,则进行更换。
2.2.2 选择排序
选择排序通过记录当前元素的下标值,在进行数据比较后决定是否更换当前
下标和之前记录的下标,如果下标更换了,则进行相应的元素交换,否则不交换。
2.2.3 插入排序
可以理解为在数组中有一条隐藏的线,一开始这个线的位置在数组的第一个
元素之后,因此从第二个元素开始取遍历数组,如果数据比较后满足条件利用
临时值保存住当前值,开始内层循环,内存循环从外层循环减一开始,并且执
行有比对元素大小的条件,进行数据后移,然后定位到符合条件的位置上去,
再将之前存储的临时变量赋值给内层循环变量加一的位置上去,因为经过内存
循环后,内层循环所指的位置是要插入位置的前一个位置。
代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void insertSort(int arr[],int len)
{
for (int i = 1; i < len; i++)
{
if (arr[i] < arr[i - 1])
{
int temp = arr[i];
int j = i-1;
for (; j >= 0 && temp < arr[j]; j--)
{
arr[j+1] = arr[j];
}
arr[j + 1] = temp;
}
}
}
void bubbleSort(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
void selectSort(int arr[],int len)
{
for (int i = 0; i < len; i++)
{
int min = i;
for (int j = i; j < len; j++)
{
if (arr[j] < arr[min])
{
min = j;
}
}
if (min != i)
{
int temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
}
void test()
{
int arr[] = { 9,5,6,7,8,3,1,2,4 };
int len = sizeof(arr) / sizeof(arr[0]);
selectSort(arr, len);
for (int i = 0; i < len; i++)
{
printf("%d\n", arr[i]);
}
}
int main()
{
test();
return 0;
}