mirror of
https://github.com/Estom/notes.git
synced 2026-04-05 11:57:37 +08:00
代码补充
This commit is contained in:
21
.vscode/c_cpp_properties.json
vendored
Normal file
21
.vscode/c_cpp_properties.json
vendored
Normal 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
161
C++/test.cpp
Normal 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;
|
||||
}
|
||||
@@ -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 @@
|
||||
```
|
||||
|
||||
### 库组件
|
||||

|
||||
|
||||
库组件 | 作用
|
||||
|----|----|
|
||||
regex | 正则表达式类
|
||||
regex_match| 字符串与正则表达式进行匹配
|
||||
regex_search | 搜索第一个与正则表达式匹配的子序列
|
||||
regex_replace | 给定格式替换一个正则表达式
|
||||
smatch | 保存string中搜索的结果(s指string)
|
||||
sregex_iterator|迭代器,遍历string搜索的结果(s指string)
|
||||
|
||||
<!--  -->
|
||||
|
||||
### 正则表达式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();
|
||||
```
|
||||
|
||||
<!--  -->
|
||||
|
||||
|
||||
|
||||
### 正则表达式对象
|
||||
|
||||

|
||||
## 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()
|
||||
|
||||
|
||||

|
||||
* 头文件<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()对字符串进行寻找。**本身只返回第一次匹配到的结果**,可以手写循环,多次调用对字符串进行匹配,找到多个结果。
|
||||
|
||||

|
||||
```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迭代器选择
|
||||
|
||||

|
||||
|
||||
### regex迭代器使用,针对string
|
||||
|
||||

|
||||
## 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
|
||||
|
||||

|
||||
|
||||
## 1.3 子表达式的正则匹配
|
||||
|
||||

|
||||
## 1.4 regex_replace
|
||||
|
||||

|
||||
## 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+){5,11}@(\\w+)\\.(\\w){3}“ | QQ邮箱格式
|
||||
### 4.1 字符类
|
||||
|
||||

|
||||
|
||||
### 2.2 数量限定符
|
||||
### 4.2 数量限定符
|
||||
|
||||

|
||||
|
||||
### 2.3 位置限定符
|
||||
### 4.3 位置限定符
|
||||
|
||||

|
||||
|
||||
### 2.4 特殊符号
|
||||
### 4.4 特殊符号
|
||||
|
||||

|
||||
|
||||
### 2.5 普通字符集及其替换
|
||||
### 4.5 普通字符集及其替换
|
||||
|
||||

|
||||
|
||||
### 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 正则规则速查表
|
||||
|
||||
| **字符** | **描述** |
|
||||
|--------------|----------------|
|
||||
|
||||
144
C++/标准库/6.cpp
144
C++/标准库/6.cpp
@@ -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;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
//数组的创建、遍历、插入、删除
|
||||
#include<iostream>
|
||||
using namespace std;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// 单链表的创建、遍历、插入、删除
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
struct node
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// 双链表的创建、遍历、插入、删除
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
struct node
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// 循环链表的创建、遍历、插入和删除
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
struct node
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//循环双链表的创建、遍历、插入和删除
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
struct node
|
||||
|
||||
1
数据结构/3.cpp
Normal file
1
数据结构/3.cpp
Normal file
@@ -0,0 +1 @@
|
||||
// 栈的创建、遍历、插入和删除
|
||||
1
数据结构/4.cpp
Normal file
1
数据结构/4.cpp
Normal file
@@ -0,0 +1 @@
|
||||
// 队列的创建、遍历、插入和删除
|
||||
@@ -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
192
数据结构/6.1.cpp
Normal 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;
|
||||
}
|
||||
@@ -26,7 +26,10 @@
|
||||
* 插入
|
||||
* 删除
|
||||
|
||||
|
||||
### 遍历
|
||||
* 二叉搜索树的前序遍历。
|
||||
* 二叉搜索书的中序遍历。中序的输出结果其实就是二叉搜索树排序后的结果。
|
||||
* 二叉搜索树的后续遍历。
|
||||
### 插入
|
||||
* 使用下列元素创建二叉树的过程
|
||||
```
|
||||
|
||||
@@ -121,10 +121,12 @@ $$
|
||||
|
||||
### 递归的实现
|
||||
|
||||
* 设计递归的终止条件
|
||||
* 设计递归的返回值
|
||||
* 递归前的数据处理
|
||||
* 递归后的数据处理
|
||||
1. 设计递归的参数。首先确定每一次递归,上一层需要提供给下一层的内容。
|
||||
2. 设计递归的返回值。设计递归需要返回的内容,即提供给上一层的内容。
|
||||
3. 设计递归的开始。设计如何开始递归。怎样调用递归。有了上一层的参数和返回值的需求,相当于提供了一个函数的接口。那么就可以调用递归函数,开始递归了。
|
||||
4. 设计递归的终止条件。一旦开始递归,就要设计递归的终止条件。
|
||||
5. 递归前的数据处理。在递归前需要处理的数据,提供给递归函数。
|
||||
6. 递归后的数据处理。在递归后需要处理的数据。提供给上层函数和最终结果。
|
||||
|
||||
|
||||
|
||||
|
||||
0
编译原理/1 简介.md
Normal file
0
编译原理/1 简介.md
Normal file
Reference in New Issue
Block a user