插入
题目
请编写一个程序,对二叉搜索树T执行以下命令:
insert k:插入键值key
print:分别用树的中序遍历和前序遍历算法输出键值
思路
insert以根为起点寻找结点z该插入的位置。设当前结点x,如果z的键值小于x则将当前结点的左子结点作为下一个x,反之则以右为下一个,不断向叶结点搜索。
程序将前一个节点保存在y里,用作z的候选父结点。当x抵达nil时搜索结束,此时y就是z的父结点。
如果搜索结束时y仍然为NIL,就代表插入前的二叉树为空,z即成为根结点。如果不为空,则z为y的左子结点或右子结点。
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
using namespace std;
struct Node{
int key;
Node *parent,*right,*left;
};
Node *root,*NIL;
void insert(int k){
Node *y=NIL;
Node *x=root;
Node *z;
z=(Node*)malloc(sizeof(Node));
z->key=k;
z->left=NIL;
z->right=NIL;
while(x!=NIL){
y=x;
if(z->key<x->key){
x=x->left;
}
if(z->key>x->key){
x=x->right;
}
}
z->parent=y;
if(y==NIL){
root=z;
}else{
if(z->key<y->key){
y->left=z;
}else{
y->right=z;
}
}
}
void inorder(Node *u){
if(u==NIL) return;
inorder(u->left);
printf(" %d",u->key);
inorder(u->right);
}
void preorder(Node *u){
if(u==NIL) return;
printf(" %d",u->key);
preorder(u->left);
preorder(u->right);
}
int main(){
int n,i,x;
string com;
scanf("%d",&n);
for(i=0;i<n;i++){
cin>>com;
if(com == "insert"){
scanf("%d",&x);
insert(x);
}else if(com == "print"){
inorder(root);
printf("\n");
preorder(root);
printf("\n");
}
}
return 0;
}
搜索
题目
请编写一个程序,在Binary Search Tree的基础上添加find命令。
思路
以根为起点调用find,从根向叶搜索结点。如果给定键值小于当前结点x的键值,那么搜索目标移至左子结点继续搜搜,反之移动到右子结点。
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
using namespace std;
struct Node{
int key;
Node *parent,*right,*left;
};
Node *root,*NIL;
Node *find(Node *u,int k){
while(u!=NIL && k!=u->key){
if(k<u->key) u=u->left;
else u=u->right;
}
return u;
}
void insert(int k){
Node *y=NIL;
Node *x=root;
Node *z;
z=(Node*)malloc(sizeof(Node));
z->key=k;
z->left=NIL;
z->right=NIL;
while(x!=NIL){
y=x;
if(z->key<x->key){
x=x->left;
}
if(z->key>x->key){
x=x->right;
}
}
z->parent=y;
if(y==NIL){
root=z;
}else{
if(z->key<y->key){
y->left=z;
}else{
y->right=z;
}
}
}
void inorder(Node *u){
if(u==NIL) return;
inorder(u->left);
printf(" %d",u->key);
inorder(u->right);
}
void preorder(Node *u){
if(u==NIL) return;
printf(" %d",u->key);
preorder(u->left);
preorder(u->right);
}
int main(){
int n,i,x;
string com;
scanf("%d",&n);
for(i=0;i<n;i++){
cin>>com;
if(com[0] == 'f'){
scanf("%d",&x);
Node *t=find(root,x);
if(t!=NIL) printf("yes\n");
else printf("no\n");
}else if(com == "insert"){
scanf("%d",&x);
insert(x);
}else if(com == "print"){
inorder(root);
printf("\n");
preorder(root);
printf("\n");
}
}
return 0;
}
删除
题目
在上面的基础上,添加delete命令。
思路
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
using namespace std;
struct Node{
int key;
Node *parent,*right,*left;
};
Node *root,*NIL;
Node* treeMinimum(Node *x){
while(x->left != NIL) x=x->left;
return x;
}
Node *find(Node *u,int k){
while(u!=NIL && k!=u->key){
if(k<u->key) u=u->left;
else u=u->right;
}
return u;
}
/*
当x存在右子结点时,右子树中键值最小的结点即为x的后一个结点,因此返回getMinimun(x->right)。不存在右
子结点,要向上查询父结点,第一个“以左子结点身份出现的父结点”就是x的后一个结点。
*/
Node* treeSuccessor(Node *x){
if(x->right != NIL) return treeMinimum(x->right);
Node* y=x->parent;
while(y != NIL && x==y->right){
x=y;
y=y->parent;
}
return y;
}
void treeDelete(Node *z){
Node *y;//要删除的结点
Node *x;//y的子结点
/*case1 & case2 */
//确定要删除的结点
//z没有子结点或者有一个子结点,y就是z。
if(z->left == NIL || z->right == NIL) y=z;
else y=treeSuccessor(z);
/*case3:*/
//确定y的子结点x
if(y->left!=NIL){
x=y->left;
}else{
x=y->right;
}
//改变y父/子结点的指针,然后删除y。
//首先让x的父结点指针指向y的父结点。
if(x!=NIL){
x->parent=y->parent;
}
//随后改变该父结点原先指向y的指针,使x成为父结点的子结点。
//这里在更改指针前,先要检查结点y是根节点,还是其父结点的左/右子结点
if(y->parent==NIL){
root=x;
}else{
if(y==y->parent->left){
y->parent->left=x;
}else{
y->parent->right=x;
}
}
//最后,如果处理的是case3,则需要将y的键值赋值给z。
if(y!=z){
z->key=y->key;
}
//删除y结点
free(y);
}
void insert(int k){
Node *y=NIL;
Node *x=root;
Node *z;
z=(Node*)malloc(sizeof(Node));
z->key=k;
z->left=NIL;
z->right=NIL;
while(x!=NIL){
y=x;
if(z->key<x->key){
x=x->left;
}
if(z->key>x->key){
x=x->right;
}
}
z->parent=y;
if(y==NIL){
root=z;
}else{
if(z->key<y->key){
y->left=z;
}else{
y->right=z;
}
}
}
void inorder(Node *u){
if(u==NIL) return;
inorder(u->left);
printf(" %d",u->key);
inorder(u->right);
}
void preorder(Node *u){
if(u==NIL) return;
printf(" %d",u->key);
preorder(u->left);
preorder(u->right);
}
int main(){
int n,i,x;
string com;
scanf("%d",&n);
for(i=0;i<n;i++){
cin>>com;
if(com[0] == 'f'){
scanf("%d",&x);
Node *t=find(root,x);
if(t!=NIL) printf("yes\n");
else printf("no\n");
}else if(com == "insert"){
scanf("%d",&x);
insert(x);
}else if(com == "print"){
inorder(root);
printf("\n");
preorder(root);
printf("\n");
}else if(com=="delete"){
scanf("%d",&x);
treeDelete(find(root,x));
}
}
return 0;
}
通过标准库管理集合
管理元素集合的STL容器大致分为两类。一类是有顺序的集合,称为序列式容器;另一类是经过排序的集合,称为关联式容器。
序列式容器会将新添加的元素置于特定位置,该位置由插入事件和地点决定,与元素本身的值无关。如:vector、list
关联式容器会依据特定的排序标准来决定要添加的元素的位置。如set、map、multiset、multimap容器。
set
使用实例
#include <iostream>
#include <set>
using namespace std;
void print(set<int> S){
cout<<S.size()<<":";
for(set<int>:: iterator it=S.begin();it!=S.end();it++){
cout<<" "<<(*it);
}
cout<<endl;
}
int main(){
set<int> S;
S.insert(8);
S.insert(1);
S.insert(7);
S.insert(4);
S.insert(8);
S.insert(4);
print(S);//1 4 7 8
S.erase(7);
print(S);
S.insert(2);
print(S);
if(S.find(10)==S.end()) cout<<"not found"<<endl;
return 0;
}
成员函数示例
函数名 | 功能 |
---|---|
size( ) | 返回set中的元素数 |
clear( ) | 清空set |
begin( ) | 返回指向set开头的迭代器 |
end( ) | 返回指向set末尾的迭代器 |
insert(key) | 插入元素key |
erase(key) | 删除含有key的元素 |
find(key) | 搜索与key一致的元素,并返回指向该元素的迭代器,没有与key一致的元素就返回末尾end() |
map
map集合以键与值的组合为元素,每个元素拥有1个键和1个值,集合以键作为排序目标,集合中各元素的键唯一,不存在重复,可以看作是一种能使用任意类型下标的关联式容器。
使用示例
#include <iostream>
#include <map>
#include <string>
using namespace std;
void print(map<string, int> T){
map<string, int>::iterator it;
cout<<T.size()<<endl;
for(it=T.begin();it!=T.end();it++){
pair<string, int> item=*it;
cout<<item.first<<"-->"<<item.second<<endl;
}
}
int main(){
map<string, int> T;
T["red"]=32;
T["blue"]=688;
T["yellow"]=122;
T["blue"]+=132;
print(T);
T.insert(make_pair("zebra",101010));
T.insert(make_pair("white",0));
T.erase("yellow");
print(T);
pair<string, int> target=*T.find("red");
cout<<target.first<<"-->"<<target.second<<endl;
return 0;
}
成员函数示例
函数名 | 功能 |
---|---|
size( ) | 返回map中的元素数 |
clear( ) | 清空map |
begin( ) | 返回指向map开头的迭代器 |
end( ) | 返回指向map末尾的迭代器 |
insert((key,val)) | 插入元素(key,val) |
erase(key) | 删除含有key的元素 |
find(key) | 搜索与key一致的元素,并返回指向该元素的迭代器,没有与key一致的元素就返回末尾end() |