代码补充

This commit is contained in:
yinkanglong_lab
2021-03-15 01:30:55 +08:00
parent e67d805774
commit 5a0f883edb
16 changed files with 790 additions and 48 deletions

21
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.19041.0",
"compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29910/bin/Hostx64/x64/cl.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-msvc-x64"
}
],
"version": 4
}

161
C++/test.cpp Normal file
View File

@@ -0,0 +1,161 @@
//二叉树的链表实现
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct TreeNode{
int val;
TreeNode* left;//左子树
TreeNode* right;//右子树
TreeNode* parent;//可以不用
};
class BinaryTree{
//TreeNode* root;//二叉树的根节点
//vector<int> tree;//二叉树的数组表示-1表示不存在的值
public:
// 创建二叉树
void build(TreeNode* &node,vector<int> &vec,int i){
if(i>vec.size() || vec[i]<0){
return ;
}
node =new TreeNode();
node->val = vec[i];
build(node->left,vec,2*i+1);
build(node->right,vec,2*i+2);
return;
}
//可视化二叉树
void display(TreeNode*node){
queue<TreeNode*> que;
que.push(node);
int i=1;
int j=0;
TreeNode* temp;
while(!que.empty()){
if(que.front()==nullptr){
que.pop();
cout<<"\t";
continue;
}
temp=que.front();
que.pop();
cout<<temp->val<<"\t";
que.push(temp->left);
que.push(temp->right);
j++;
if(j==i){
j=0;
i=2*i;
cout<<endl;
}
}
}
//处理节点值
void process(TreeNode * node){
cout<<node->val<<" ";
}
//前序遍历
void pre_order(TreeNode*node){
if(node == nullptr){
return;
}
process(node);
pre_order(node->left);
pre_order(node->right);
return;
}
//中序遍历
void mid_order(TreeNode*node){
if(node == nullptr){
return;
}
mid_order(node->left);
process(node);
mid_order(node->right);
return;
}
//后续遍历
void lst_order(TreeNode* node){
if(node == nullptr){
return;
}
lst_order(node->left);
lst_order(node->right);
process(node);
}
// 层序遍历
void layer_order(TreeNode*node){
queue<TreeNode*> que;
que.push(node);
while(!que.empty()){
if(que.front()==nullptr){
continue;
}
process(que.front());
que.push(que.front()->left);
que.push(que.front()->right);
que.pop();
}
}
//重建二叉树-前中
/*
* pre 前序遍历的数组
* mid 中序遍历的数组
* root 前序遍历中的第一个数的坐标。也就是说,该子树的根节点。
* beg2 中序遍历的起始位置。
* end2 中序遍历的结束位置。
* 问题分析:二叉树遍历问题,递归与分治的思想。创建一个树,可以分解为创建左子树和右子树两个子问题。问题的规模缩小。具有最优子结构性质,每一个子问题解法一致。子问题最终可以合并为问题的解。各个子问题相互独立。
* 选择策略:使用链表数据结构存储结果。采用递归思想递归创建。
* 算法技术:递归技术。算法流程,设计输入参数,界定本层处理范围。设计返回值即提供给上层的值。确定递归结构,分别调用左子树和右子树。确定递归的终止条件。确定递归前和递归后需要处理的内容。
* 正确性证明。
*/
TreeNode* rebuild(vector<int> pre,vector<int> mid,int root,int beg2,int end2){
if(end2<beg2){
return nullptr;
}
int i=0;
TreeNode* node= new TreeNode();
node->val=pre[root];
for(i=beg2;i<=end2;i++){
if(mid[i]==pre[root]){
break;
}
}
int dis = i-beg2;//左树的长度
node->left=rebuild(pre,mid,root+1,beg2,beg2+dis-1);
node->right=rebuild(pre,mid,root+dis+1,beg2+dis+1,end2);
return node;
}
TreeNode* rebuild2();
//重建二叉树-中后
};
int main(){
//数组表示的树
vector<int> vec{9,8,7,6,-1,4,3};
TreeNode n;
TreeNode* node=&n;
BinaryTree tree;
// tree.build(node,vec,0);
// tree.display(node);
// cout<<endl;
// tree.pre_order(node);
// cout<<endl;
// tree.mid_order(node);
// cout<<endl;
// tree.lst_order(node);
// 数组表示的前序遍历和后续遍历
vector<int> pre{3,9,20,15,7};
vector<int> mid{9,3,15,20,7};
TreeNode* node2 = tree.rebuild(pre,mid,0,0,mid.size()-1);
tree.display(node2);
return 0;
}

View File

@@ -1,9 +1,14 @@
# 正则表达式
> 目录
> * regex正则表达式的定义
> * regex_match/search/replace正则表达式的三个操作
> * smatch、sregex_iterator正则表达式的结果对象以及与其配套的迭代器。
## 1 正则表达式组件
## 1.1 正则表达式基础用法
> 参考文献
> * [正则表达式总结](https://blog.csdn.net/haohao1945/article/details/51375609)
## 1 正则表达式基础
> 不考虑子表达式的内容
### 头文件
@@ -12,23 +17,145 @@
```
### 库组件
![](image/2021-03-07-19-53-20.png)
库组件 | 作用
|----|----|
regex | 正则表达式类
regex_match| 字符串与正则表达式进行匹配
regex_search | 搜索第一个与正则表达式匹配的子序列
regex_replace | 给定格式替换一个正则表达式
smatch | 保存string中搜索的结果s指string
sregex_iterator|迭代器遍历string搜索的结果s指string
<!-- ![](image/2021-03-07-19-53-20.png) -->
### 正则表达式regex
```C++
//定义正则表达式的对象。可以使用一个string、一个字符范围迭代器对、一个字符数组指针、一个字符和一个计数器、或括号括起来的字符列表。一个可选的flag参数主要用来指定匹配规则
string str = "hhh233";
string pattern="[a-z0-9]+";
regex r(pattern,[flag]);
//重新制定r的正则表达式
r.assign(pattern2,[flag])
//r中子表达式的数目
r.mark_count();
//r中的标志位
r.flags();
```
<!-- ![](image/2021-03-07-20-52-19.png) -->
### 正则表达式对象
![](image/2021-03-07-20-52-19.png)
## 2 操作
### 操作
## 2.1 正则匹配regex_match
函数|说明
|----|----|
regex_match(string seq,regex r)|查询是否匹配。完全匹配。seq也可以是字符串迭代器对string.begin(),string.end()
regex_match(string seq,smatch m,regex r)|查询是否匹配完全匹配。并返回匹配的结果。seq也可以是字符串迭代器对string.begin(),string.end()
![](image/2021-03-07-19-55-20.png)
* 头文件<regex>中的regex_match和regex_search均可以进行匹配返回一个布尔类型匹配成功为true匹配失败为false。前者要求完全匹配后者要求子串匹配即可
* 对字符串进行匹配(一般不使用,因为字符串匹配的正则表达式要考虑到整个字符串)
```C++
string str = "hhh233";
regex r("[a-z0-9]+");
// 用法一
bool flag = regex_match(str,r);
// 用法二
bool flag = regex_match(str,regex("\\d+"));
// 用法三
bool flag = regex_match(str.begin()+7,str.end(),regex("\\d+"));
//正则匹配
string regex_str2("(\\d{4}).*");
regex pattern2(regex_str2,regex::icase);
if(regex_match(str,result,pattern2)){
cout<<result[0]<<endl;
cout<<result[1]<<endl;
}
```
## 2.2 正则搜索regex_search
函数|说明
|----|----|
regex_search(string seq,regex r)|搜索是否匹配。子串匹配seq也可以是字符串迭代器对string.begin(),string.end()
regex_search(string seq,smatch m,regex r)|搜索是否匹配子串匹配并返回匹配的结果。seq也可以是字符串迭代器对string.begin(),string.end()
* 使用regex_search()对字符串进行寻找。**本身只返回第一次匹配到的结果**,可以手写循环,多次调用对字符串进行匹配,找到多个结果。
![](image/2021-03-07-20-34-45.png)
```C++
//正则查找
while (std::regex_search(iter,iterEnd,result,pattern1))
{
temp=result[0];
cout<<temp<<endl;
iter = result[0].second; //更新搜索起始位置
}
//循环查找过程
string test = "145341.35186410.200034uhvsv nfji7676876///1324531.1";
smatch mat;
regex rgx("(\\d+\\.){1}");
string::const_iterator start = test.begin();
string::const_iterator end = test.end();
while (regex_search(start, end, mat, rgx))
{
cout << mat[1].str() << endl;
start = mat[0].second;
}
```
## 2.3 正则替换regex_replace
函数|说明
|----|----|
regex_search(string seq,regex r)|搜索是否匹配。子串匹配seq也可以是字符串迭代器对string.begin(),string.end()
regex_search(string seq,smatch m,regex r)|搜索是否匹配子串匹配并返回匹配的结果。seq也可以是字符串迭代器对string.begin(),string.end()
* regex_replace:使用给定格式替换一个正则表达式
```C++
//正则替换
std::regex reg1("\\d{4}");
string t("1993");
str = regex_replace(str,reg1,t); //trim_left
cout<<str<<endl;
```
## 2.4 捕获结果smatch
* 捕获就是先匹配,然后将匹配结果存储下来。捕获同样是使用上面介绍的那两个函数,仍然区分为整串匹配和子串匹配。
1. 模式中一般要有分组(因为捕捉的正是分组匹配的结果)
2. 定义一个STL容器smatch用来保存捕捉的结果
3. 使用reg_search函数匹配用smatch的实例存储匹配的结果即完成捕捉。
4. 使用m.size()查看捕捉到的个数使用m.str(i)查看捕捉到的字符串smatch 类的 size() 指的是分组个数也就是正则中左括号的个数。【注意m.str(0)一定是整个正则匹配到的部分m.str(1)及以后才是分组捕获的结果】
5. m.prefix().str()获取整个匹配之前的字符串m.suffix().str()获取整个匹配之后的字符串
* 获取第i个匹配m.str(i)还有其他等价写法m[i].str()、*(m.begin() + i)
* 模式其实可以不分组…这样就只有m.str(0)捕捉到整个串没有m.str(1)其他的了。
* 正则分组:一个正则表达式可以被分为很多个正则分组,主要通过()和|对正则分组进行划分。其中str(i)表示的是当前smatch 中匹配的第一个结果的第i个正则分组。smatch 类的 size() 指的是分组个数,也就是正则中左括号的个数。
```
smatch ==>match_result<string>
```
函数|说明
|---|---|
m.ready()|是否接受过返回结果
m.empty()|是否没哟匹配数。
m.size()|查看捕捉到的分组的个数。smatch 类的 size() 指的是分组个数,也就是正则中左括号的个数。
m.prefix().str() | 获取整个匹配之前的字符串;
m.suffix().str() | 获取整个匹配之后的字符串
m.str(i),m[i].str(),*(m.begin() + i) | 获取第i个子匹配即由正则分组匹配到的第i个匹配。
```C++
#include<iostream>
@@ -48,21 +175,48 @@ int main(){
cout<<results.str()<<endl;
else
cout<<results.str()<<endl;
//另一个例子
string str;
while(true){
cin >> str;
regex e("([[:w:]]+)@([[:w:]]+)\.com");
smatch m;
bool found = regex_search(str, m, e);
if(found)
{
cout << "m.size() " << m.size() << endl;
for(int i=0; i<m.size(); ++i){
cout << "m.str("<<i<< "): "<<m.str(i)<< endl;
}
cout<<"m.prefix().str():"<<m.prefix().str()<< endl;
cout<<"m.suffix().str():"<<m.suffix().str()<< endl;
}
else cout << "Not Found" << endl;
return 0;
}
return 0;
}
```
## 1.2 正则表达式的迭代器string对象
### regex迭代器选择
![](image/2021-03-07-20-36-59.png)
### regex迭代器使用针对string
![](image/2021-03-07-20-53-15.png)
## 2.5 迭代器sregex_ieterator
* 使用那个smatch来保存结果。迭代器内的对象指向的是smatch。用来遍历smatch对象
```
sregex_iterator==> regex_iterator<string>
```
函数| 说明
|----|----|
sregex_iterator it(string.beg(),string.end(),regex r)| 遍历迭代器begin和end之间的string。调用regex_search返回并保存结果。
```C++
#include<iostream>
#include<regex>
@@ -91,51 +245,58 @@ int main(){
return 0;
}
```
### smatch的操作针对string
![](image/2021-03-07-21-07-30.png)
## 1.3 子表达式的正则匹配
![](image/2021-03-07-21-10-18.png)
## 1.4 regex_replace
![](image/2021-03-07-21-10-01.png)
## 2 正则表达式规则
## 4 正则表达式规则
主要包括四类
* 字符类
* 数量限定符
* 位置限定符
* 特殊符号
### 2.1 字符类
### 4.0 正则表达式实例
实例|说明
|----|----|
| “ab"      | 表示以ab开头的字符串例如”abc“ ”abc ed“
| ”ab+"    | 表示一个字符串由一个a和至少一个b组成
| "ab?"    | 表示一个字符串由一个a和一个或零个b组成
| "ab{2,3}"  | 表示一个字符串由一个a和2-3个b组成
| “access|boot"  | 表示一个字符串,为access或者boot
| "(a|b)*c"   | 表示一个字符串,  由一个或多个a(或者b) + c 混合而成
| [a-zA-Z]  | 表示一个字符,为一个字母
| ”[a-zA-Z0-9]$"   | 表示一个字符串,由一个字母或数字结束。
| **错误提示!!!!**[ab\\d]  | 中括号中不能有转义字符
”[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+ “          | 检验普通电话、传真号码:可以“+”或数字开头,可含有减号和空格
”http[s]{0,1}:\/\/.+$/ 或 /^http[s]{0,1}:\/\/.{1,n}“    | 检验URL
“([0-9A-F]{2})(-[0-9A-F]{2}){5}”                          | 检验mac地址
“[-+]?\d+(\.\d+)?”                                        |       值类型
“\\d{4}-\\d{1,2}-\\d{1,2}”                                |      日期格式2018-7-30
”(\\d+){511}@(\\w+)\\.(\\w){3}“                        | QQ邮箱格式 
### 4.1 字符类
![](image/2021-03-07-20-17-59.png)
### 2.2 数量限定符
### 4.2 数量限定符
![](image/2021-03-07-20-18-20.png)
### 2.3 位置限定符
### 4.3 位置限定符
![](image/2021-03-07-20-18-37.png)
### 2.4 特殊符号
### 4.4 特殊符号
![](image/2021-03-07-20-18-51.png)
### 2.5 普通字符集及其替换
### 4.5 普通字符集及其替换
![](image/2021-03-07-20-20-11.png)
### 2.6 贪婪模式与非贪婪模式
### 4.6 贪婪模式与非贪婪模式
1. 贪婪模式:正则表达式匹配时,会尽量多的匹配符合条件的内容。
2. 非贪婪模式正则表达式匹配时会尽量少的匹配符合条件的内容也就是说一旦发现匹配符合要求立马就匹配成功而不会继续匹配下去除非有g开启下一组匹配
### 2.7 特殊规则
### 4.7 特殊规则
* '[:alnum:]' 匹配任何字母和数字
Alphanumeric characters: '[:alpha:]' and '[:digit:]'.
@@ -174,7 +335,7 @@ X Y Z'.
* '[:xdigit:]' 匹配任何16进制数字
Hexadecimal digits: '0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f'.
### 2.8 正则规则速查表
### 4.8 正则规则速查表
| **字符** | **描述** |
|--------------|----------------|

View File

@@ -23,5 +23,149 @@ int main(){
for(;it != end_it;++it){
cout<<it->str()<<endl;
}
//第一种存储方式
//match_results<string::const_iterator> result;
//第二种存储方式
smatch result;
//文本数据
string str="1994 is my birth year 1994";
//正则表达式
string regex_str("\\d{4}");
regex pattern1(regex_str,regex::icase);
//迭代器声明
string::const_iterator iter = str.begin();
string::const_iterator iterEnd= str.end();
string temp;
//正则查找
while (std::regex_search(iter,iterEnd,result,pattern1))
{
temp=result[0];
cout<<temp<<endl;
iter = result[0].second; //更新搜索起始位置
}
//正则匹配
string regex_str2("(\\d{4}).*");
regex pattern2(regex_str2,regex::icase);
if(regex_match(str,result,pattern2)){
cout<<result[0]<<endl;
cout<<result[1]<<endl;
}
//正则替换
std::regex reg1("\\d{4}");
string t("1993");
str = regex_replace(str,reg1,t); //trim_left
cout<<str<<endl;
return 0;
}
int test_regex_match()
{
std::string pattern{ "\\d{3}-\\d{8}|\\d{4}-\\d{7}" }; // fixed telephone
std::regex re(pattern);
std::vector<std::string> str{ "010-12345678", "0319-9876543", "021-123456789"};
/* std::regex_match:
判断一个正则表达式(参数re)是否匹配整个字符序列str,它主要用于验证文本
注意这个正则表达式必须匹配被分析串的全部否则返回false;如果整个序列被成功匹配返回true
*/
for (auto tmp : str) {
bool ret = std::regex_match(tmp, re);
if (ret) fprintf(stderr, "%s, can match\n", tmp.c_str());
else fprintf(stderr, "%s, can not match\n", tmp.c_str());
}
return 0;
}
int test_regex_search()
{
std::string pattern{ "http|hppts://\\w*$" }; // url
std::regex re(pattern);
std::vector<std::string> str{ "http://blog.csdn.net/fengbingchun", "https://github.com/fengbingchun",
"abcd://124.456", "abcd https://github.com/fengbingchun 123" };
/* std::regex_search:
类似于regex_match,但它不要求整个字符序列完全匹配
可以用regex_search来查找输入中的一个子序列该子序列匹配正则表达式re
*/
for (auto tmp : str) {
bool ret = std::regex_search(tmp, re);
if (ret) fprintf(stderr, "%s, can search\n", tmp.c_str());
else fprintf(stderr, "%s, can not search\n", tmp.c_str());
}
return 0;
}
int test_regex_search2()
{
std::string pattern{ "[a-zA-z]+://[^\\s]*" }; // url
std::regex re(pattern);
std::string str{ "my csdn blog addr is: http://blog.csdn.net/fengbingchun , my github addr is: https://github.com/fengbingchun " };
std::smatch results;
while (std::regex_search(str, results, re)) {
for (auto x : results)
std::cout << x << " ";
std::cout << std::endl;
str = results.suffix().str();
}
return 0;
}
int test_regex_replace()
{
std::string pattern{ "\\d{18}|\\d{17}X" }; // id card
std::regex re(pattern);
std::vector<std::string> str{ "123456789012345678", "abcd123456789012345678efgh",
"abcdefbg", "12345678901234567X" };
std::string fmt{ "********" };
/* std::regex_replace:
在整个字符序列中查找正则表达式re的所有匹配
这个算法每次成功匹配后就根据参数fmt对匹配字符串进行替换
*/
for (auto tmp : str) {
std::string ret = std::regex_replace(tmp, re, fmt);
fprintf(stderr, "src: %s, dst: %s\n", tmp.c_str(), ret.c_str());
}
return 0;
}
int test_regex_replace2()
{
// reference: http://www.cplusplus.com/reference/regex/regex_replace/
std::string s("there is a subsequence in the string\n");
std::regex e("\\b(sub)([^ ]*)"); // matches words beginning by "sub"
// using string/c-string (3) version:
std::cout << std::regex_replace(s, e, "sub-$2");
// using range/c-string (6) version:
std::string result;
std::regex_replace(std::back_inserter(result), s.begin(), s.end(), e, "$2");
std::cout << result;
// with flags:
std::cout << std::regex_replace(s, e, "$1 and $2", std::regex_constants::format_no_copy);
std::cout << std::endl;
return 0;
}

View File

@@ -1,3 +1,4 @@
//数组的创建、遍历、插入、删除
#include<iostream>
using namespace std;

View File

@@ -1,3 +1,4 @@
// 单链表的创建、遍历、插入、删除
#include<stdio.h>
#include<stdlib.h>
struct node

View File

@@ -1,3 +1,4 @@
// 双链表的创建、遍历、插入、删除
#include<stdio.h>
#include<stdlib.h>
struct node

View File

@@ -1,3 +1,4 @@
// 循环链表的创建、遍历、插入和删除
#include<stdio.h>
#include<stdlib.h>
struct node

View File

@@ -1,3 +1,4 @@
//循环双链表的创建、遍历、插入和删除
#include<stdio.h>
#include<stdlib.h>
struct node

1
数据结构/3.cpp Normal file
View File

@@ -0,0 +1 @@
// 栈的创建、遍历、插入和删除

1
数据结构/4.cpp Normal file
View File

@@ -0,0 +1 @@
// 队列的创建、遍历、插入和删除

View File

@@ -56,16 +56,61 @@
### 前序遍历
```
* 第一个节点肯定是根节点。
```C++
//前序遍历
void pre_order(TreeNode*node){
if(node == nullptr){
return;
}
process(node);
pre_order(node->left);
pre_order(node->right);
return;
}
```
### 中序遍历
```
```C++
//中序遍历
void mid_order(TreeNode*node){
if(node == nullptr){
return;
}
mid_order(node->left);
process(node);
mid_order(node->right);
return;
}
```
### 后序遍历
```
* 最后一个节点肯定是根节点。
```C++
//后续遍历
void lst_order(TreeNode* node){
if(node == nullptr){
return;
}
lst_order(node->left);
lst_order(node->right);
process(node);
}
```
### 层序遍历
```
```C++
// 层序遍历
void layer_order(TreeNode*node){
queue<TreeNode*> que;
que.push(node);
while(!que.empty()){
if(que.front()==nullptr){
continue;
}
process(que.front());
que.push(que.front()->left);
que.push(que.front()->right);
que.pop();
}
}
```
## 4 二叉树实现
@@ -85,6 +130,12 @@
```
```
## 重建二叉树问题
* 给定了二叉树的任何一种遍历序列,都无法唯一确定相应的二叉树。
* 如果知道了二叉树的中序遍历序列和任意的另一种遍历序列,就可以唯一地确定二叉树。
* 中序遍历能够分出子树的根节点的左右。中序和后序遍历能够区根节点。
## 5 二叉树相关的问题

192
数据结构/6.1.cpp Normal file
View File

@@ -0,0 +1,192 @@
//二叉树的链表实现
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
struct TreeNode{
int val;
TreeNode* left;//左子树
TreeNode* right;//右子树
TreeNode* parent;//可以不用
};
class BinaryTree{
//TreeNode* root;//二叉树的根节点
//vector<int> tree;//二叉树的数组表示-1表示不存在的值
public:
// 创建二叉树
void build(TreeNode* &node,vector<int> &vec,int i){
if(i>vec.size() || vec[i]<0){
return ;
}
node =new TreeNode();
node->val = vec[i];
build(node->left,vec,2*i+1);
build(node->right,vec,2*i+2);
return;
}
//可视化二叉树
void display(TreeNode*node){
queue<TreeNode*> que;
que.push(node);
int i=1;
int j=0;
TreeNode* temp;
while(!que.empty()){
if(que.front()==nullptr){
que.pop();
cout<<"\t";
continue;
}
temp=que.front();
que.pop();
cout<<temp->val<<"\t";
que.push(temp->left);
que.push(temp->right);
j++;
if(j==i){
j=0;
i=2*i;
cout<<endl;
}
}
}
//处理节点值
void process(TreeNode * node){
cout<<node->val<<" ";
}
//前序遍历
void pre_order(TreeNode*node){
if(node == nullptr){
return;
}
process(node);
pre_order(node->left);
pre_order(node->right);
return;
}
//中序遍历
void mid_order(TreeNode*node){
if(node == nullptr){
return;
}
mid_order(node->left);
process(node);
mid_order(node->right);
return;
}
//后续遍历
void lst_order(TreeNode* node){
if(node == nullptr){
return;
}
lst_order(node->left);
lst_order(node->right);
process(node);
}
// 层序遍历
void layer_order(TreeNode*node){
queue<TreeNode*> que;
que.push(node);
while(!que.empty()){
if(que.front()==nullptr){
continue;
}
process(que.front());
que.push(que.front()->left);
que.push(que.front()->right);
que.pop();
}
}
// 区分层次的层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> vec;
queue<TreeNode*> que[2];
que[0].push(root);
int i=0;
while(!que[i%2].empty()){
// 每次交换队列创建一个数组
vec.push_back(vector<int>());
while(!que[i%2].empty()){
if(que[i%2].front()==nullptr){
que[i%2].pop();
continue;
}
TreeNode*temp=que[i%2].front();
que[i%2].pop();
vec[i].push_back(temp->val);
que[(i+1)%2].push(temp->left);
que[(i+1)%2].push(temp->right);
}
//可以在这里针对每层进行操作。例如反转。
i++;
}
// 最后肯定是空元素组成的队列,创建一个额外的空数组。
vec.pop_back();
return vec;
}
//重建二叉树-前中
/*
* pre 前序遍历的数组
* mid 中序遍历的数组
* root 前序遍历中的第一个数的坐标。也就是说,该子树的根节点。
* beg2 中序遍历的起始位置。
* end2 中序遍历的结束位置。
* 问题分析:二叉树遍历问题,递归与分治的思想。创建一个树,可以分解为创建左子树和右子树两个子问题。问题的规模缩小。具有最优子结构性质,每一个子问题解法一致。子问题最终可以合并为问题的解。各个子问题相互独立。
* 选择策略:使用链表数据结构存储结果。采用递归思想递归创建。
* 算法技术:递归技术。算法流程,设计输入参数,界定本层处理范围。设计返回值即提供给上层的值。确定递归结构,分别调用左子树和右子树。确定递归的终止条件。确定递归前和递归后需要处理的内容。
* 正确性证明。
*/
TreeNode* rebuild(vector<int> pre,vector<int> mid,int root,int beg2,int end2){
if(end2<beg2){
return nullptr;
}
int i=0;
TreeNode* node= new TreeNode();
node->val=pre[root];
for(i=beg2;i<=end2;i++){
if(mid[i]==pre[root]){
break;
}
}
int dis = i-beg2;//左树的长度
node->left=rebuild(pre,mid,root+1,beg2,beg2+dis-1);
node->right=rebuild(pre,mid,root+dis+1,beg2+dis+1,end2);
return node;
}
TreeNode* rebuild2();
//重建二叉树-中后
};
int main(){
//数组表示的树
vector<int> vec{9,8,7,6,-1,4,3};
TreeNode n;
TreeNode* node=&n;
BinaryTree tree;
// tree.build(node,vec,0);
// tree.display(node);
// cout<<endl;
// tree.pre_order(node);
// cout<<endl;
// tree.mid_order(node);
// cout<<endl;
// tree.lst_order(node);
// 数组表示的前序遍历和后续遍历
vector<int> pre{3,9,20,15,7};
vector<int> mid{9,3,15,20,7};
TreeNode* node2 = tree.rebuild(pre,mid,0,0,mid.size()-1);
tree.display(node2);
return 0;
}

View File

@@ -26,7 +26,10 @@
* 插入
* 删除
### 遍历
* 二叉搜索树的前序遍历。
* 二叉搜索书的中序遍历。中序的输出结果其实就是二叉搜索树排序后的结果。
* 二叉搜索树的后续遍历。
### 插入
* 使用下列元素创建二叉树的过程
```

View File

@@ -121,10 +121,12 @@ $$
### 递归的实现
* 设计递归的终止条件
* 设计递归的返回值
* 递归前的数据处理
* 递归后的数据处理
1. 设计递归的参数。首先确定每一次递归,上一层需要提供给下一层的内容。
2. 设计递归的返回值。设计递归需要返回的内容,即提供给上一层的内容。
3. 设计递归的开始。设计如何开始递归。怎样调用递归。有了上一层的参数和返回值的需求,相当于提供了一个函数的接口。那么就可以调用递归函数,开始递归了。
4. 设计递归的终止条件。一旦开始递归,就要设计递归的终止条件。
5. 递归前的数据处理。在递归前需要处理的数据,提供给递归函数。
6. 递归后的数据处理。在递归后需要处理的数据。提供给上层函数和最终结果。

0
编译原理/1 简介.md Normal file
View File