记一点笔记
算法笔记 第9章 提高篇(3)——数据结构专题(2)
9.1 树与二叉树
9.1.1 树的定义与性质
- 略
9.1.2 二叉树的递归定义
- 略
9.1.3 二叉树的存储结构与基本操作
1. 二叉树的存储结构
struct node {
typename data;
node *lchild, *rchild;
};
//建树前根结点不存在,因此其地址一般设为NULL
node *root = NULL;
//生成一个新结点,v为结点权值
node *newNode(int v) {
node *Node = new node;
Node->data = v;
Node->lchild = NULL;
Node->rchild = NULL;
return Node;
}
2. 二叉树结点的查找、修改
void search(node *root, int x, int newdata) {
if(root == NULL) return;
if(root->data == x) {
root->data = newdata;
}
search(root->lchild, x, newdata);
search(root->rchild, x, newdata);
}
3. 二叉树结点的插入
//注意根结点指针root要使用引用,否则插入不会成功
void insert(node* &root, int x) {
if(root == NULL) {
root = newNode(x);
return;
}
if(由二叉树的性质,x应该插在左子树) {
insert(root->lchild, x);
} else {
insert(root->rchild, x);
}
}
4. 二叉树的创建
node *Create(int data[], int n) {
node *root = NULL;
for(int i = 0; i < n; i++) {
insert(root, data[i]);
}
return root;
}
9.2 二叉树的遍历
9.2.1 先序遍历
void preorder(node *root) {
if(root == NULL) return;
printf("%d\n", root->data);
preorder(root->lchild);
preorder(root->rchild);
}
9.2.2 中序遍历
void inorder(node *root) {
if(root == NULL) return;
inorder(root->lchild);
printf("%d\n", root->data);
inorder(root->rchild);
}
9.2.3 后序遍历
void postorder(node *root) {
if(root == NULL) return;
postorder(root->lchild);
postorder(root->rchild);
printf("%d\n", root->data);
}
9.2.4 层序遍历
struct node {
typename data;
node *lchild, *rchild;
int layer; //层次
};
//层序遍历并计算每个结点所处的层次
void layerorder(node *root) {
queue<node*> q; //注意队列里存地址
root->layer = 1;
q.push(root);
while(!q.empty()) {
node *now = q.front();
q.pop();
printf("%d\n", 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);
}
}
}
补充. 给定一棵二叉树的先序遍历序列和中序遍历序列,重建这棵二叉树
//当前先序序列区间为[preL, preR],中序序列区间为[inL, inR],返回根结点地址
node *create(int preL, int preR, int inL, int inR) {
if(preL > preR) {
return NULL;
}
node *root = new node;
node->data = pre[preL]; //新结点的数据域为根结点的值
int k;
for(k = inL; k <= inR; k++) {
if(in[k] == pre[preL]) { //在中序序列中找到当前根结点位置
break;
}
}
int numLeft = k - inL; //左子树的结点个数
//左子树的先序区间为[preL+1, preL+numLeft],中序区间为[inL, k-1]
root->lchild = create(preL+1, preL+numLeft, inL, k-1);
//右子树的先序区间为[preL+numLeft+1, preR],中序区间为[k+1, inR]
root->rchild = create(preL+numLeft+1, preR, k+1, inR);
return root;
}
9.2.5 二叉树的静态实现
struct node {
typename data;
int lchild, rchild; //左、右子树指针域,以-1或maxn表示空
} Node[maxn];
/* 其他操作略 */
9.3 树的遍历
- 略
9.4 二叉查找树
9.4.1 二叉查找树的定义
- 略
9.4.2 二叉查找树的基本操作
1. 查找操作
void search(node *root, int x) {
if(root == NULL) {
printf("serch 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);
}
}
2. 插入操作
void insert(node* &root, int x) {
if(root == NULL) {
root = newNode(x);
return;
}
if(x == root->data) {
return;
} else if(x < root->data) {
insert(root->lchild, x);
} else {
insert(root->rchild, x);
}
}
3. 二叉查找树的建立
- 略
4. 二叉查找树的删除
//寻找以root为根结点的树中的最大权值结点
node *findMax(node *root) {
while(root->rchild != NULL) {
root = root->rchild;
}
return root;
}
//寻找以root为根结点的树中的最小权值结点
node *findMax(node *root) {
while(root->lchild != NULL) {
root = root->lchild;
}
return root;
}
//删除以root为根结点树中权值为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前驱
root->data = pre->data; //用前驱覆盖root
deleteNode(root->lchild, pre->data); //在左子树中删除结点pre
} else { //左子树为空,右子树不为空时
node *next = findMin(root->rchild); //找root后继
root->data = next->data; //用后继覆盖root
deleteNode(root->rchild, next->data); //在右子树中删除结点next
}
} else if(root->data > x) {
deleteNode(root->lchild, x);
} else {
deleteNode(root->rchild, x);
}
}
9.4.3 二叉查找树的性质
- 对二叉查找树进行中序遍历,遍历的结果是有序的。
9.5 平衡二叉树(AVL树)
9.5.1 平衡二叉树的定义
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;
else 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;
}
9.5.2 平衡二叉树的基本操作
1. 查找操作
- 略
2. 插入操作
//左旋(L)
void L(node *root) {
node *temp = root->rchild;
root->rchild = temp->lchild;
temp->lchild = root;
updateHeight(root);
updateHeight(temp);
root = temp;
}
//右旋(R)
void R(node *root) {
node *temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
updateHeight(root);
updateHeight(temp);
root = temp;
}
//插入权值为v的结点
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(getBalanceFactor(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->lchild) == 1) { //RL型
R(root->lchild);
L(root);
}
}
}
}
3. AVL树的建立
- 略
9.6 并查集
9.6.1 并查集的定义
- 略
9.6.2 并查集的基本操作
1. 初始化
for(int i = 1; i <= N; i++ {
father[i] = i;
}
2. 查找
int findFather(int x) {
while(x != father[x]) {
x = father[x];
}
return x;
}
3. 合并
void Union(int a, int b) {
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB) {
father[faA] = faB;
}
}
9.6.3 路径压缩
int findFather(int x) {
int a = x;
while(x != father[x]) {
x = father[x];
}
while(a != father[a]) {
int z = a;
a = father[a];
father[z] = x;
}
return x;
}