This commit is contained in:
Estom
2021-09-15 15:50:25 +08:00
parent 1e18bd1115
commit 12464c187b
7 changed files with 361 additions and 27 deletions

View File

@@ -1,8 +1,14 @@
//二叉树的链表实现
/*
* 二叉树数组与链表表示的转换
* 前序遍历(递归和非递归)、中序遍历(递归和非递归)、后序遍历(递归和非递归)
* 层序遍历(单队列单循环法。双队列双循环法)
*/
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<stack>
using namespace std;
struct TreeNode{
@@ -20,7 +26,7 @@ class BinaryTree{
public:
// 创建二叉树
void build(TreeNode* &node,vector<int> &vec,int i){
if(i>vec.size() || vec[i]<0){
if(i>=vec.size() || vec[i]<0){
return ;
}
node =new TreeNode();
@@ -72,6 +78,29 @@ public:
pre_order(node->right);
return;
}
// 前序遍历非递归
void pre_order_stack(TreeNode* node){
// 左节点持续压栈,压栈访问。
// 有节点退出时访问。
stack<TreeNode*> st;
TreeNode* now = node;
TreeNode* temp;
while(!st.empty()|| now){
while(now != nullptr){
st.push(now);
process(now);
now = now->left;
}
// 这个判断防止栈为空,即一个节点也没有的情况。
if(!st.empty()){
temp = st.top();
st.pop();
now=temp->right;
}
}
return ;
}
//中序遍历
void mid_order(TreeNode*node){
if(node == nullptr){
@@ -82,7 +111,28 @@ public:
mid_order(node->right);
return;
}
//后续遍历
// 中序遍历非递归
void mid_order_stack(TreeNode* node){
// 左节点持续压栈,压栈访问。
// 有节点退出时访问。
stack<TreeNode*> st;
TreeNode* now = node;
TreeNode* temp;
while(!st.empty()|| now){
while(now != nullptr){
st.push(now);
now = now->left;
}
if(!st.empty()){
temp = st.top();
st.pop();
process(temp);
now=temp->right;
}
}
return ;
}
//后序遍历
void lst_order(TreeNode* node){
if(node == nullptr){
return;
@@ -91,6 +141,32 @@ public:
lst_order(node->right);
process(node);
}
// 后序遍历的双栈法
// 对于一个节点而言,要实现访问顺序为左儿子-右儿子-根节点,可以利用后进先出的栈,在节点不为空的前提下,依次将根节点,右儿子,左儿子压栈。故我们需要按照根节点-右儿子-左儿子的顺序遍历树,而我们已经知道先序遍历的顺序是根节点-左儿子-右儿子,故只需将先序遍历的左右调换并把访问方式打印改为压入另一个栈即可。最后一起打印栈中的元素。
void lst_order_stack(TreeNode* node){
stack<TreeNode*> st1;
stack<TreeNode*> st2;
TreeNode* now = node;
TreeNode* temp;
while(!st1.empty() || now){
while(now){
st1.push(now);
st2.push(now);
now=now->right;
}
if(!st1.empty()){
temp = st1.top();
st1.pop();
now = temp->left;
}
}
while(!st2.empty()){
temp = st2.top();
st2.pop();
process(temp);
}
}
// 层序遍历
void layer_order(TreeNode*node){
queue<TreeNode*> que;
@@ -135,7 +211,8 @@ public:
vec.pop_back();
return vec;
}
// 区分层次的层序遍历2 改进版,单队列,单循环
// 区分层次的层序遍历2 改进版,单队列,单循环
vector<vector<int>> levelOrder2(TreeNode* root) {
vector<vector<int>> res;
vector<int> vec;
@@ -203,25 +280,38 @@ public:
};
int main(){
//数组表示的树
vector<int> vec{9,8,7,6,-1,4,3};
vector<int> vec{1,2,3,4,5,6,7};
TreeNode n;
TreeNode* node=&n;
BinaryTree tree;
tree.build(node,vec,0);
// tree.display(node);
// 测试
cout<<"preorder:"<<endl;
tree.pre_order(node);
cout<<endl;
tree.pre_order_stack(node);
cout<<endl;
cout<<"midorder:"<<endl;
tree.mid_order(node);
cout<<endl;
tree.mid_order_stack(node);
cout<<endl;
cout<<"lst_order:"<<endl;
tree.lst_order(node);
cout<<endl;
tree.lst_order_stack(node);
cout<<endl;
// cout<<endl;
// tree.pre_order(node);
// cout<<endl;
// tree.mid_order(node);
// cout<<endl;
// tree.lst_order(node);
vector<vector<int>> res = tree.levelOrder2(node);
for(auto a:res){
for(auto b:a){
cout<<b<<" ";
}
cout<<endl;
}
// vector<vector<int>> res = tree.levelOrder2(node);
// for(auto a:res){
// for(auto b:a){
// cout<<b<<" ";
// }
// cout<<endl;
// }
// 数组表示的前序遍历和后续遍历
// vector<int> pre{3,9,20,15,7};
// vector<int> mid{9,3,15,20,7};

244
数据结构/6.2.cpp Normal file
View File

@@ -0,0 +1,244 @@
// 二叉搜索树的创建和查找
/*
* 二叉搜索树的插入、删除、查找
*/
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<stack>
using namespace std;
struct TreeNode{
int val;
TreeNode* left;//左子树
TreeNode* right;//右子树
TreeNode* parent;//可以不用
TreeNode(int v){
val=v;
left = nullptr;
right = nullptr;
}
};
class BinarySearchTree{
public:
TreeNode* build(vector<int> &vec){
TreeNode* head = new TreeNode(vec[0]);
for(int i=1;i<vec.size();i++){
insert(head,vec[i]);
}
return head;
}
// 循环插入叶子及诶点
void insert(TreeNode* root,int val){
TreeNode* temp = root;
while(true){
// cout<<temp->val<<endl;
if(val>temp->val){
if(temp->right!=nullptr){
temp = temp->right;
}
else{
temp->right = new TreeNode(val);
break;
}
}
else if(val<temp->val){
if(temp->left!=nullptr){
temp = temp->left;
}
else{
temp->left = new TreeNode(val);
break;
}
}
}
}
// 递归插入叶子节点
TreeNode* insert2(TreeNode* root,int val){
if(root==nullptr){
return new TreeNode(val);
}
if(val<root->val){
root->left = insert2(root->left,val);
}
else{
root->right = insert2(root->right,val);
}
return root;
}
void insert(TreeNode* root,TreeNode* node){
TreeNode* temp = root;
while(true){
// cout<<temp->val<<endl;
if(node->val>temp->val){
if(temp->right!=nullptr){
temp = temp->right;
}
else{
temp->right = node;
break;
}
}
else if(node->val<temp->val){
if(temp->left!=nullptr){
temp = temp->left;
}
else{
temp->left = node;
break;
}
}
}
return ;
}
void mid_order(TreeNode* root){
if(root == nullptr){
return ;
}
mid_order(root->left);
process(root);
mid_order(root->right);
return;
}
bool find(TreeNode* root,int val){
TreeNode* temp = root;
while(temp){
if(temp->val==val){
return true;
}
if(val > temp->val){
temp = temp->right;
}
else{
temp = temp->left;
}
}
return false;
}
// 将左树上升。
void delete_node(TreeNode* root,int val){
TreeNode* new_root = new TreeNode(-1);
new_root->right = root;
TreeNode* temp = new_root;
TreeNode* parent=new_root;
// 查找节点,如果存在则删除,不存在直接退出。
bool left_or_right=false;
while(temp){
if(temp->val==val){
break;
}
if(val > temp->val){
parent = temp;
left_or_right=true;
temp = temp->right;
}
else{
parent = temp;
left_or_right=false;
temp = temp->left;
}
}
if(temp==nullptr)return;
cout<<"left_or_right:"<<left_or_right<<endl;
// 删除parent的左或者右节点
if(left_or_right==false){
if(temp->left!=nullptr && temp->right!=nullptr){
parent->left = temp->left;
TreeNode* t=temp->right;
while(t->left){
t=t->left;
}
t->left = parent->left->right;
parent->left->right = temp->right;
}
else if(temp->left==nullptr){
parent->left=temp->right;
}
else if(temp->right==nullptr){
parent->left = temp->left;
}
}
else{
if(temp->left!=nullptr && temp->right!=nullptr){
parent->right = temp->left;
TreeNode* t=temp->right;
while(t->left){
t=t->left;
}
t->left = parent->right->right;
parent->right->right = temp->right;
}
else if(temp->left==nullptr){
parent->right=temp->right;
}
else if(temp->right==nullptr){
parent->right = temp->left;
}
}
delete temp;
return;
}
// 正常删除,找到右子树的最小节点,作为根节点。删除最小节点。
// 非递归的方法实现,通过循环查找,循环删除
void delete_node2(TreeNode* root,int val){
TreeNode* new_root = new TreeNode(-1);
new_root->right = root;
TreeNode* temp = new_root;
TreeNode* parent=new_root;
while(temp){
if(temp->val==val){
break;
}
if(val > temp->val){
parent = temp;
temp = temp->right;
}
else{
parent = temp;
temp = temp->left;
}
}
if(temp->left!=nullptr && temp->right!=nullptr){
// 找到右子树的最小值。日后再来实现吧
TreeNode* min_node=temp->right;
TreeNode* min_node_parent = temp;
while(temp->left!=nullptr){
temp=temp->left;
}
}
}
void process(TreeNode* root){
cout<<root->val<<" ";
}
};
int main(){
vector<int> vec{43, 10, 79, 90, 12, 54, 11, 9, 50};
BinarySearchTree bt = BinarySearchTree();
TreeNode* head = bt.build(vec);
cout<<"build&mid_order"<<endl;
bt.mid_order(head);
cout<<endl;
cout<<"insert"<<endl;
bt.insert(head,78);
bt.mid_order(head);
cout<<endl;
cout<<"find"<<endl;
bool b =bt.find(head,78);
cout<< b<<endl;
cout<<"delete:"<<endl;
bt.delete_node(head,10);
bt.mid_order(head);
cout<<endl;
}

View File

@@ -25,7 +25,7 @@
* 堆结构的一个常见应用是建立优先队列Priority Queue
![](image/2021-03-13-15-25-15.png)
* 普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配内存。堆仅仅使用一个数来存储数组,且不使用指针。
* 普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配内存。堆仅仅使用一个数来存储数组,且不使用指针。
## 2 操作
@@ -77,7 +77,7 @@
> 类似于冒泡的思想,但是是一中更快的冒泡。保证最后能够建立最好的堆。
* 从根节点向叶节点开始,从前往后开始。进行多次上浮操作。
*叶节点向根节点开始,从后往前开始。进行多次下沉操作。
* 从后往前第一个非叶节点开始。进行多次下沉操作。
### 插入(堆尾的数据)

View File

@@ -9,11 +9,11 @@ public:
// cout<<111<<endl;
}
vector<int> max_queue;
// 创建堆
// 创建堆。从第一个非叶节点开始向下调整
MaxQueue(vector<int> vec) {
max_queue=vec;
for(int i=vec.size()-1;i>=0;i--){
shift_down((i-1)/2);
for(int i=vec.size()/2-1;i>=0;i--){
shift_down(i);
}
}
// 堆顶值.即队首的元素
@@ -98,9 +98,9 @@ public:
};
int main(){
// vector<int> vec{0,1,2,3,4,5};
// MaxQueue mq=MaxQueue(vec);
// mq.display();
vector<int> vec{0,1,2,3,4,5};
MaxQueue mq=MaxQueue(vec);
mq.display();
// cout<<mq.max_value()<<endl;
// mq.pop_front();
// mq.display();

View File

@@ -138,8 +138,8 @@
算法思想|问题特征|
|-----|-----|
|分治法 | 规模缩小容易解决;最优子结构性质;子问题的解合并为该问题的解;子问题是相互独立的。|
|动态规划|最优子结构性质;无后效性;有重叠子问题,子问题之间是不独立的|
|分治法 | 规模缩小容易解决;最优子结构性质;子问题是相互独立的;子问题的解合并为该问题的解。|
|动态规划|规模缩小容易解决;最优子结构性质;有重叠子问题,子问题之间是不独立的;无后效性;|
|贪心算法|最优子结构性质;贪心选择性质。|
|回溯法|多米诺性质(叶子节点的解一定满足其父节点)。|
|分支限界|多米诺性质;求解最优解或一个可行解。|

View File

@@ -1,4 +1,4 @@
# 查找算法
# 查找算法
> 阅读目录
1. 顺序查找
2. 二分查找