树与二叉树
1.定义:树是一种非线性的结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。我们平常在生活中所看到的树是根在下,枝叶在上面。而对于数据结构中的树则是根朝上,枝叶朝下,正好与生活中的树的结构相反。
2.特点:
<1>.每个结点有零个或多个子节点。
<2>.一个非根结点有且只有一个父节点。
<3>.只有根节点没有父节点。
<4>.除了根结点外,每个子节点可以分为多个不相交的子树。
3.树内的基本概念
结点:树中的元素,包含数据项及若干指向其子树的分支。
结点的度:所有结点当中,子树分支最最多的就是树的度
结点的层次:从根结点开始算起,根为第一层,
叶子:度为零的结点,也称端结点。
孩子:结点子树的根称为该结点的孩子结点。
双亲:孩子结点的上层结点,称为这些结点的双亲。
兄弟:同一双亲的孩子。
深度: 树中结点的最大层次数
森林:互不相交的树的集合
4.二叉树的遍历
A.先序遍历:
访问根结点
访问左子树的左子树,再访问左子树中的右子树
访问右子树的左子树,再访问右子树中的右子树
任意子树输出顺序为:父结点——左子结点——右子结点
如上图先序遍历顺序为:A-B-D-H-I-E-J-C-F-K-G
B.中序遍历:
先访问左子树中的左子树,再访问左子树中的右子树
访问根结点。
后访问右子树中的左子树,再访问右子树中的右子树
任意子树输出顺序为:左子结点——父结点——右子结点
如上图中序遍历顺序为:H-D-I-B-E-J-A-F-K-C-G
C.后序遍历:
先访问左子树中的左子树,再访问左子树中的右子树
再访问右子树中的左子树,再访问右子树中的右子树
访问根结点
任意子树输出顺序为:左子结点——右子结点——父结点
如上图后序遍历顺序为:H-I-D-J-E-B-K-F-G-C-A
快速排序与归并排序
1.归并排序
思想:分治思想:分解,合并。
过程:分解:在归并排序中,一个数组取下标中点的数字对应的值。将数组分成两部分。重复上述这个动作,直到每一小块至多只有2个数字。然后再做对比。
合并:两个小的数据集。依次比较。第1位比较另一个数据集的第1位。哪个小,哪个先进tmp数据集(append)。然后进去的那个数据所属的数据集往后稍1个,继续和另一个数据集的第1位比较。
模板:
private static int[] helper;
public static void mergeSort(int[] arr) {
if (helper == null)
helper = new int[arr.length];
else {
helper = null;
helper = new int[arr.length];
}
mergeSort(arr, 0, arr.length - 1);
helper = null;
}
private static void mergeSort(int[] arr, int lo, int hi) {
if (lo >= hi)
return;
int mid = (lo + hi) >>> 1;
mergeSort(arr, lo, mid);
mergeSort(arr, mid + 1, hi);
merge(arr, lo, mid, hi);
}
private static void merge(int[] arr, int lo, int mid, int hi) {
System.arraycopy(arr, lo, helper, lo, hi - lo + 1);
int left = lo;
int right = mid + 1;
int current = lo;
while (left <= mid && right <= hi) {
if (helper[left] <= helper[right])
arr[current++] = helper[left++];
else
arr[current++] = helper[right++];
}
// 这里注意我们只需要处理这种情况,right > hi,但是 left <= mid
// 也就是左边的数组还没有走完,右边不需要管,自己画画就知道为什么了
while (left <= mid)
arr[current++] = helper[left++];
}
2.快速排序
思想:分治思想
过程:随便选取一项(一般是中间值),然后形成三个组,小于被选项组,大于被选项组合等于被选项组,递归的对小于被选项组,大于被选项组进行排序,然后合并这三个组。
模板:
public class QuickSort {
/**
* 快速排序 O(NlogN)
* @param list
*/
private static void quickSort(ArrayList<Integer> list) {
if(list.size()>1) {
ArrayList<Integer> smallerlist = new ArrayList<>();
ArrayList<Integer> centerList = new ArrayList<>();
ArrayList<Integer> largeList = new ArrayList<>();
//中间元素
Integer center = list.get(list.size()/2);
//分类
for(Integer i : list) {
if(i < center) {
//比中间元素小
smallerlist.add(i);
}else if (i > center) {
//比中间元素大
largeList.add(i);
}else {
//与中间元素相等
centerList.add(i);
}
}
//分组排序
quickSort(smallerlist);
quickSort(largeList);
//清空
list.clear();
//合并
list.addAll(smallerlist);
list.addAll(centerList);
list.addAll(largeList);
}
}
public static void main(String[] args) {
int[] a = {1,8,2,6,4,2,3,8,4,6,10,12,45,21,31};
ArrayList<Integer> list = new ArrayList<>();
for(int i = 0;i<a.length;i++) {
list.add(a[i]);
}
quickSort(list);
for(Integer integer : list) {
System.out.println(integer+"\t");
}
}
}
BFS和DFS
1.BFS
思路:算法自始至终一直通过已找到和未找到顶点之间的边界向外扩展,即算法首先搜索和s距离为k的所有顶点,然后再去搜索和S距离为k+l的其他顶点。
模板:
#include<iostream>
#include<queue>
#include<cstring> //string.h
using namespace std;
typedef pair<int,int> PII;
int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1};
const int N = 25;
char g[N][N]; //存图的
int st[N][N]; //标记这个点有没有被搜过
int n,m; //n行m列
int res;
void bfs(int x,int y)
{
queue<PII> q;
q.push({x,y});
while(q.size() > 0) //队列不空
{
PII t = q.front(); //取出队头
q.pop();//出队
for(int i=0; i<4; i++) //遍历四个方向
{
int a = t.first + dx[i], b = t.second + dy[i]; //队头邻接点的坐标
if(a<0 || a>=n || b<0 || b>=m) continue; //出界
if(st[a][b] == 1) continue; //已经被访问过
if(g[a][b] != '.') continue; //不能走
res++;
q.push({a,b});
st[a][b] = 1; //标记(a,b)已经被访问过
}
}
}
int main()
{
while(cin >> m >> n)
{
if(m==0 && n==0) break;
res = 1;
memset(st,0,sizeof st); //memset(数组名,值,sizeof 数组名); 0/-1/0x3f
for(int i=0; i<n; i++) cin >> g[i];
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
if(g[i][j] == '@')
{
bfs(i,j);
break;
}
cout << res << endl;
}
2.DFS
思路:将节点按照深度优先的次序压栈,后面再以相反的次序出栈进行新的检测
模板:
const int32_t maxn = 100;
bool visted[maxn][maxn]; // 访问标记
int32_t positionRange[maxn][maxn]; // 坐标范围
int32_t direction[][2] = {0, 1, 0, -1, 1, 0, -1, 0}; // 方向向量,(x,y)周围的四个方向
// 边界条件和约束条件的判断
bool CheckEdge(int32_t x, int32_t y)
{
// 满足条件
if (!visted[x][y] && ...) {
return true;
} else {
return false;
}
}
void dfs(int32_t x,int32_t y)
{
visted[x][y] = true; // 标记该节点被访问过
// 出现目标态G
if (positionRange[x][y] == G) {
... // 做相应处理
return;
}
for (int32_t i = 0; i < 4; i++) {
// 按照规则生成下一个节点,上面左右四个点
if (CheckEdge(x + direction[i][0], y + direction[i][1])) {
dfs(x + direction[i][0], y + direction[i][1]);
}
}
return; // 没有下层搜索节点,回溯
}