二叉树的增删改查和四种遍历
//二叉树的增删改查,和四种遍历
//二叉树的存储结构
//二叉链表
struct node{
typename data;//数据域
node* lchild;//指向左子树根结点的指针
node* rchild;
};
//新建结点
node* newNode(int v){
node* Node = new node;//申请一个node型变量的地址空间
Node->data = v;
Node->lchild = Node->rchild = NULL;//初始状态没有左右孩子
return Node;
}
//二叉树结点的查找,修改
void search(node* root, int x, int newdata){
if(root == NULL) return;//空树或者边界
if(root->data == x) root->data = newdata;//找到数据域为x的结点,修改为newdata
search(root->lchild, x, newdata);
search(root->rchild, x, newdata);
}
//二叉树的插入
//根结点root要使用引用,因为要对root本身的地址进行修改,而不是里面的data或者孩子
void insert(node* &root, int x){
if(root == NULL){
root = newNode(x);
return;
}
if(根据二叉树的性质,x应该插在左子树){
insert(root->lchild, x);//左孩子递归
}else{
insert(root->rchild, x);
}
}
//二叉树的创建
node* create(int data[], int n){
node* root = NULL;
for(int i = 0; i < n; i++){
insert(root, data[i]);//将数据插入到二叉树中;data[0]~data[n-1]
}
return root;
}
root == NULL;//表示结点root不存在
*root == NULL;//表示结点可能存在,但没有内容
//二叉树的遍历
//先序遍历
void pre(node* root){
if(root == NULL) return;//边界
printf("%d\n", root->data);//根左右的遍历
pre(root->lchild);
pre(root->rchild);
}
//中序遍历
void in(node* root){
if(root == NULL) return;
in(root->lchild);
printf("%d\n", root->data);
in(root->rchild);
}
//后序遍历
void post(node* root){
if(root == null) return;
post(root->lchild);
post(root->rchild);
printf("%d\n", root->data);
}
//层序遍历(相当于bfs)
struct node{
int data;
int layer;//层次
node* lchild;
node* rchild;
};
#include<queue>
#include<iostream>
using namespace std;
void bfs(node* root){
queue<node*> q;
q.push(root);
while(!q.empty()){
node* now = q.front();
q.pop();
printf("%d", now->data);//访问队首元素
if(now->lchild != NULL){
now->lchild->layer = now->layer+1;
q.push(now->lchild);
}
if(now->rchild != NULL){
now->rchild->layer = now->layer + 1;
q.push(now->rchild);
}
}
}
二叉树的转换
//前序中序 转 后序
void post(int preroot, int l, int r){//root为pre遍历根的下标,start是in的最左下标,end为in最右的下标
if(l > r) return;//边界
int i = l;
while(i < r&& pre[preroot] != in[i]) i++;//在in中找到root的下标i
post(root + 1 , l, i - 1);//i-1-l是左子树边的个数,右子树的根结点为root+i-l+1+1
post(root + 1 + i - l, i + 1, r); //右子树根结点为root加左子树的边+2
printf("%d", pre[preroot]);
}
//后序中序 转 前序
void pre(int postroot, int l, int r){
if(l > r) return;
int i = l;
while(i < r&& post[postroot] != in[i]) i++;
printf("%d", post[postroot]);
pre(postroot - 1 - r + i, l, i - 1) //左子树的根结点为root减右子树的边-2
pre(postroot - 1, i + 1, r);//r-i-1只是右子树边的个数
}
//后中 转 层序
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
vector<int> post, in;
map<int, int> level;
void pre(int root, int l, int r, int index){
if(l > r) return;
int i = l;
while(i < r&&post[root] != in[i]) i++;
level[index] = post[root];
pre(root - 1 - r + i, l, i-1, 2 * index + 1);//index+1为完全二叉树里层序遍历的左子树下标
pre(root - 1, i + 1, r, 2 * index + 2);//index+2为完全二叉树里层序遍历右子树下标
}
int main(){
int n;
scanf("%d", &n);
post.resize(n);
in.resize(n);
for(int i = 0; i < n; i++) scanf("%d", &post[i]);
for(int i = 0; i < n; i++) scanf("%d", &in[i]);
pre(n-1, 0, n-1, 0);
auto it = level.begin();
printf("%d", it->second);
while(++it != level.end()) printf(" %d", it->second);
return 0;
}
树的遍历
//树的遍历
#include<vector>
#include<iostream>
#include<queue>
using namespace std;
//树的静态写法
struct node{
int layer;
int data;
vector<int> child;//因为不知道孩子有多少个
}Node[maxn];
//新建结点
int index = 0;
int newNode(int v){
Node[index].data = v;
Node[index].child.clear();//清空子结点
return index++;//返回结点下标,并令index自增
}
//树的先根遍历
void pre(int root){
printf("%d", Node[root].data);
for(int i = 0; i < Node[root].child.size(); i++){
pre(Node[root].child[i]);//递归访问结点root的所有子结点
}
}
//树的层序遍历
void bfs(int root){
queue<int> q;
q.push(root);
Node[root].layer = 0;
while(!q.empty()){
int front = q.front();
printf("%d", Node[front].data);
q.pop();
for(int i = 0; i < Node[root].child.size(); i++){
int child = Node[front].child[i];
Node[child].layer = Node[front].layer + 1
q.push(child);
}
}
}
树的dfs
//dfs
//给出的树的结构和权值,找从根结点到叶子结点的路径上的权值相加之和等于给定目标数的路径, 并且从大到小输出路径
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int target;
struct node{
int w;
vector<int> child;
};
vector<node> v;//没有分配大小,此处size()为0
vector<int> path;//因为vector初始化时,path[0~maxn]都为0
void dfs(int index, int nodenum, int sum){//结点编号,第几个结点,结点目前总权值
if(sum > target) return;//长度超标
if(sum == target){
if(v[index].child.size() != 0) return;//非叶子结点
for(int i = 0; i < nodenum; i++){
printf("%d%c", v[path[i]].w, i != nodenum - 1 ? ' ' : '\n');//path[i]是孩子结点的序号,输出路径序号的权值
}
return;
}
for(int i = 0; i < v[index].child.size(); i++){
int child = v[index].child[i];//结点index的第i个子结点编号
path[nodenum] = child;//将结点child加到 path末尾
//或者path.push_back(child); 也可以把child加到path末尾
dfs(child, nodenum + 1, sum + v[child].w);
}
}
int cmp(int a, int b){
return v[a].w > v[b].w;
}
int main(){
int n, m, id, k;//结点数,叶子节点数,结点编号,每个结点的孩子个数
scanf("%d%d%d", &n, &m, &target);
v.resize(n), path.resize(n);//因为vector初始化时,path[0~maxn]都为0
for(int i = 0; i < n; i++){
scanf("%d", &v[i].w);
}
for(int i = 0; i < m; i++){//m是无叶子结点个数
scanf("%d%d", &id, &k);
v[id].child.resize(k);
for(int j = 0; j < k; j++){
scanf("%d", &v[id].child[j]);
}
sort(v[id].child.begin(), v[id].child.end(), cmp);
}
dfs(0, 1, v[0].w);
return 0;
}
bst的增删改查
//BST二叉查找树的增删改查
//search函数查找二叉查找树中数据为x的结点
void search(node* root, int x){
if(root == NULL){//空树,查找失败
printf("search failed\n");
return;
}
if(x == root->data){//查找成功
printf("%d\n", root->data); //边界
}else if(x < root->data){
search(root->lchild, x);
}else{
search(root->rchild, x);
}
}
//插入操作,因为要对结点进行修改,注意对root用&引用
void insert(node* &root, int x){
if(foot == NULL){
root = newNode(x);
return;
}
if(x == root->data){//查找成功,直接返回
return;
}else if(x < root->data){
insert(root->lchild, x);
}else{
insert(root->rchild, x);
}
}
//二叉查找树的建立
node* creat(int data[], int n){
node* root = NULL;
for(int i = 0; i < n; i++){
insert(root, data[i]);//将data[0~n-1]插入二叉查找树
}
return root;
}
//二叉查找树的删除
//删除root为根的data为x的结点
void deletenode(node* &root, int x){
if(root == NULL) return;
if(root->data == x){
if(root->lchild == NULL&&root->rchild == NULL){
root = NULL;
}else if(root->lchild != NULL){
node* pre = findmax(root->lchild);//找到左子树的最大结点
root->data = pre->data;
deletenode(root->lchild, pre->data);//把pre删了
}else(root->rchild != NULL){
node* post = findmin(root->rchild);
root->data = post->data;
deletenode(root->rchild, post->data);
}
}else if(root->data > x){
detetenode(root->lchild, x);
}else{
deletenade(root->rchild, x);
}
}
镜像bst
//给出n个正整数作为一颗二叉排序树的结点插入排序,
//若是先序序列或者镜像树的先序序列,则输出YES,并且输出对应树的后序序列; 否则输出NO
#include<iostream>
#include<vector>
using namespace std;
struct node{
int data;
node* left;
node* right;
};
void insert(node* &root, int data){
if(root == NULL){
root = new node;
root->data = data;
root->left = root->right = NULL;
return;
}
if(data < root->data) insert(root->left, data);
else insert(root->right, data);
}
void pre(node* root, vector<int> &v){//先序遍历,将结果存在v中
if(root == NULL) return;
v.push_back(root->data);
pre(root->left, v);
pre(root->right, v);
}
void premirror(node* root, vector<int> &v){
if(root == NULL) return;
v.push_back(root->data);
premirror(root->right, v);
premirror(root->left, v);
}
void post(node* root, vector<int> &v){
if(root == NULL) return;
post(root->left, v);
post(root->right, v);
v.push_back(root->data);
}
void postmirror(node* root, vector<int> &v){
if(root == NULL) return;
post(root->right, v);
post(root->left, v);
v.push_back(root->data);
}
vector<int> origin, preo, prem, posto, postm;
int main(){
int n, data;
node* root = NULL;//定义头节点
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d", &data);
origin.push_back(data);
insert(root, data);//将data插入二叉树
}
pre(root, preo);
premirror(root, prem);
post(root, posto);
postmirror(root, postm);
if(origin == preo){
printf("YES\n");
for(int i = 0; i < posto.size(); i++){
printf("%d", posto[i]);
if(i < posto.size() - 1) printf(" ");
}
}else if(origin == prem){
printf("YES\n");
for(int i = 0; i < postm.size(); i++){
printf("%d", postm[i]);
if(i < postm.size() - 1) printf(" ");
}
}else{
printf("NO\n");
}
return 0;
}
avl树的增删改查
//AVL平衡二叉树
//平衡二叉树仍然是一棵二叉查找树
//平衡二叉树的定义
struct node{
int v, height;
node *lchild, *rchild;//左右孩子结点地址
};
//生成一个新结点,v为结点权值
node* newnode(int v){
node* Node = new node;
Node->v = v;
Node->height = 1;
Node->lchild = Node->rchild = NULL;
return Node;//返回新建结点的地址
}
//获取以root为根结点的子树的当前height
int getheight(node* root){
if(root = NULL) return 0;//空结点高度为0
return root->height;
}
//获取结点root的平衡因子
int getbalancefactor(node* root){
return getheight(root->lchild) - getheight(root->rchild);
}
//更新结点root的height
void updateheight(node* root){
root->height = max(getheight(root->lchild), getheight(root->rchild)) + 1;
}
//AVL的基本操作
//查找AVL树中数据域为x的结点
void search(node* root, int x){
if(root == NULL){
printf("search failed\n");
return;
}
if(x == root->v){
printf("%d\n", root->v);
}else if(x < root->v){
search(root->lchild, x);
}else if(x > root->v){
search(root->rchild, x);
}
}
//插入操作
//LL型,LR型,RR型,RL型
//左旋
void l(node* &root){
node* temp = root->rchild;
root->rchild = temp->lchild;
temp->lchild = root;
updateheight(root);//先更新下面的,再更新上面的
updateheight(temp);
root = temp;
}
//右旋
void r(node* &root){
node* temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
updateheight(root);
updateheight(temp);
root = temp;
}
void insert(node* &root, int v){
if(root == NULL){//到达空结点
root = newnode(v);
return;
}
if(v < root->v){
insert(root->lchild, v);
updateheight(root);
if(getbalancefactor(root) == 2){
if(getbalanncefactor(root->lchild) == 1){//ll型
r(root);
}else if(getbalancefactor(root->lchild)== -1){//lr型
l(root->lchild);
r(root);
}
}
}else{
insert(root->rchild, v);
updateheight(root);
if(getbalancefactor(root) == -2){
if(getbalancefactor(root->rchild) == -1){//rr型
l(root);
}else if(getbalancefactor(root->rchild) == 1){//rl型
r(root->rchild);
l(root);
}
}
}
}
//AVL树的建立
node* create(int data[], int n){
node* root = NULL;
for(int i = 0; i < n; i++){
insert(root, data[i]);
}
return root;
}
并查集的查,并,路径压缩
//并查集
//并查集的基本操作
//初始化
int father[MAX_K + 1], height[MAX_K + 1], size[MAX_K + 1];
void creat(int N){
for(int i = 1; i <= N; i++){
father[i] = i;
height[i] = 0;
size[i] = 0;
}
}
//查找(找到x所在集合的根结点)
int findfather(int x){
while(x != father[x]){//直到找到father[x] == x(根结点);
x = father[x];//一直找父亲
}
return x;
}
//合并
void Union(int a, int b){
int faA = findfather(a);
int faB = findfather(b);
father[faA] = faB;//直接合并
/*if(height[faA] < height[faB]){ //(总是把小树合并到大树上)
father[faA] = faB;
size[faB] += size[faA];
}else if(height[faB] < height[faA]){
father[faB] = faA;
size[faA] += size[faB];
}else{
father[faB] = faA;
size[faA] += size[faB];
height[faA]++;
}*/
}
//路径压缩
int findfather(int v){
if(v == father[v]) return v;//找到根结点
else{
int f = findfather(father[v]);//递归寻找father[v]的根结点
father[v] = f;
return f;//返回结点f
}
}
并查集小例题
#include<iostream>
using namespace std;
const int N = 110;
int father[N];
bool flag[N];
int findfa(int x){
if(x == father[x]) return x;
else{
int f = findfa(father[x]);
father[x] = f;
return f;
}
}
void Union(int a, int b){
int faa = findfa(a);
int fab = findfa(b);
if(faa != fab){
father[faa] = fab;
}
}
void create(int n){
for(int i = 1; i <= n; i++){
father[i] = i;
flag[i] = false;
}
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
create(n);
for(int i = 0; i < m; i++){
int a, b;
scanf("%d%d", &a, &b);
Union(a, b);
}
int ans = 0;
for(int i = 1; i <= n; i++){
if(i == father[i]){
ans++;
}
}
printf("%d", ans);
return 0;
}
堆的下坠,上浮,建立,增删,堆排序
//堆
//定义堆
const int maxn = 100;
//heap为堆,n为元素个数
int heap[maxn], n = 10;
//对heap数组在[low,high]范围进行向下调整
//low为预调整结点的数组下标,high一般为堆的最后一个元素的下标
void downadjust(int low, int high){//O(logn)
int i = low, j = i*2;
while(j <= high){//存在孩子结点
//如果右孩子的值比左孩子大
if(j+1 <= high&& heap[j+1] > heap[i]){
j = j + 1;//让j存右孩子下标
}
//如果孩子中最大的权值比预调整结点i大
if(heap[j] > heap[i]){
swap(heap[j], heap[i]);
i = j;//把预调整结点,换成最大值孩子下标
j = i*2;
}else{
break;//孩子结点比预调整结点i小
}
}
}
//建堆
void createheap(){//O(n)
for(int i = n/2; i >= 1; i--){//从非叶子结点,依次往顶循环
downadjust(i, n);
}
}
//删除堆顶元素
void deletetop(){//O(logn)
heap[1] = heap[n--];//用最后一个元素覆盖堆顶元素,且让n-1
downadjust(1, n);//向下调整堆顶
}
//往堆里添加元素,向上调整
//往上调整,low为1,high为预调整结点的数组下标
void upadjust(int low, int high){//O(logn)
int i = high, j = i/2;//i为预调整结点,j为父亲
while(j >= low){
//父亲权值小于预调整结点i的权值
if(heap[j] < heap[i]){
swap(heap[j] > heap[i]);//交换父亲和预调整结点
i = j;//把预调整结点往上调,换成父亲下标
j = i/2;
}else{
break;//父亲权值比预调整i的权值大,调整结束
}
}
}
//添加元素x
void insert(int x){
heap[++n] = x;//n+1,数组末位赋值x
upadjust(1, n);//向上调整新加入的结点n
}
//堆排序,把堆从小到大排
void heapsort(){//O(nlogn)
createheap();
for(int i = n; i > 1; i--){
swap(heap[i], heap[1]);
downadjust(1, i-1);//每次都向下调整到i的前一个位置
}
}
lca(最近公共祖宗)
//LCA最小公共祖宗
#include<iostream>
#include<vector>
#include<map>
using namespace std;
map<int, bool> mp;//用来表示输入的数字是否true
int main(){
int m, n, u, v, a;
scanf("%d%d", &m, &n);
vector<int> pre(n);//用来存遍历
for(int i = 0; i < n; i++){
scanf("%d", &pre[i]);
mp[pre[i]] = true;
}
for(int i = 0; i < m; i++){
scanf("%d%d", &u, &v);
for(int j = 0; j < n; j++){
a = pre[j];
if((a < v&&a > u)||(a > v&&a < u)||(a == u||a == v)) break;//pre遍历和BST的性质,决定了a在u和v之间,则a为u,v的最近祖宗
}
if(mp[u] == false&&mp[v] == false)
printf("ERROR: %d and %d are not found.\n", u, v);
else if(mp[u] == false||mp[v] == false)
printf("ERROR: %d is not found.\n", mp[u] == false ? u : v);
else if(a == u||a == v)
printf("%d is an ancestor of %d.\n", a, a == u ? v : u);
else
printf("LCA of %d and %d is %d.\n", u, v, a);
}
return 0;
}