[Code Journal#1] 2022/2/20

  • Post author:
  • Post category:其他


1. 求最大公约数gcd(a,b) OJW1T2

int gcd(int a,int b)
{
    return b ? gcd(b ,a % b) : a;
}

2. Trie树:OJW1T4

一种数据结构,利用公共前缀压缩存储空间。

本质为一棵26叉树,树干上存储每一条字符对应的结点。

支持单词的插入、查询、求前缀等功能。

#include <cstdio>
#include <string>
#include <iostream>
using namespace std;
struct node{
	node* nxt[26];
	bool isend;
};
node* New()
{
	node* p = new node;
	for (int i = 0 ; i <= 25 ; i++)
		p->nxt[i] = NULL;
	p->isend = false;
	return p;
}
node *root = New();//建立根节点 
int n;
void insert(string s)
{
	node* cur = root;
	int len = s.size();
	for (int i = 0 ; i < len ; i++)
		{
			if(cur->nxt[s[i] - 'a'] == NULL) //若当前位置结点不存在s[i]的后继连边,建立新节点
				{
					node* p = New();	
					cur->nxt[s[i] - 'a'] = p;
				}
			cur = cur->nxt[s[i] - 'a'];//往后连接。 
		}
	cur->isend = true;//标记为结尾。 
}
bool search(string s)
{
	node* cur = root;
	int len = s.size();
	for (int i = 0 ; i < len ; i++)
		{
			if(cur->nxt[s[i] - 'a'] == NULL)
				return false;
			cur = cur->nxt[s[i] - 'a'];
		}
	return cur != NULL && cur->isend;
 } 
int main()
{
	root->isend = false;
	scanf("%d", &n);
	char t;
	string str;
	for (int i = 1 ; i <= n ; i++)
		{
			cin >> t;
			cin >> str;	
			if(t == 'I')
				{
					insert(str);
					continue;
				}
			if(t == 'S')
				{
					if(search(str))
						printf("YES\n");
					else
						printf("NO\n");
					continue;
				}
				
		}
	return 0;
}


尤其注意的是,当我们在结构体类型中声明指针类型的时候。一定要对其内部的指针进行初始化!这样其指针才处于正确的初始状态,本题中要求每个结点的指针预处理成空指针。细节!

3. C++提供的STL二分查找

#include <algorithm>
//头文件库为alg

int a[N];
//注意,二分查找的对象应当为有序表,所以需要对数组进行预处理:排序!
sort(a + 1,a + 1 + n);
cin >> val;//input the queryed val;

int pos = lower_bound(a + 1,a + 1 + n,val) - a;//lower_bound里面的三个参数,第一个为查找起始,
//第二个为查找终点,第三个为查找的数。在有序表中找到第一个大于等于val的数,并返回其地址。
//和数组开头元素的地址做差之后,就能得到对应的,第一个大于等于val的元素在序列中的下标。
a[pos]>=val

4.快速读入:

inline long long read() {
	long long x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}

5. 二叉搜索树:

OJW2T4

/*
维护一颗二叉搜索树
支持插入、删除、打印 

树的结点应当维护以下信息:
(1)本身的电锯“标号” ,数值域 
(2) 结点的插入次数k
(3)左、右儿子 
*/
#include <cstdio>
#include <iostream>
using namespace std;
struct node{
	int val;//记录数据域 
	int cnt;//记录插入次数
	node *l,*r,*fa; 
};//二叉搜索树结点定义
node *rt = NULL;
node* New(node* t,int data)//新建结点函数,返回结点地址 
{
	node* p = new node;
	p->cnt = 1;
	p->fa = t;//记录父亲 
	p->l = NULL;
	p->r = NULL;
	p->val = data;
	return p;
}
/*Insert Function */ 
void insert(node* root,int data)//将data插入到这棵树
{
	if(root == NULL) //若新插入的结点是第一个结点,也就是新建树,单独处理一下
		{
			node* p = New(NULL,data);
			rt = p;//维护全局根节点 
			return;
		} 
	if(root->val == data)//如果已经找到对应结点,直接加权
		{
			root->cnt++;
			return;	
		} 
	if(root->val > data)//若根节点比data大,递归访问左子树 
		{
			if(root->l == NULL)//若不存在左子结点,直接新建并且与父结点连接 
				{
					node* p = New(root,data);
					root->l = p;//父结点的左子结点为p 
					return;
				} 
			insert(root->l,data);
		}
	else
		{
			if(root->r == NULL)//若不存在左子结点,直接新建并且与父结点连接 
				{
					node* p = New(root,data);
					root->r = p;//父结点的左子结点为p 
					return;
				} 
			insert(root->r,data);		
		}
}
/*Find the direct succession*/
node* s(node* root)//找到直接后继 
{
	while(root->l)
		{
			root = root->l;
		}
	return root;
}
/*Delete Function*/
void erase(node* root)//删除根的结点 
{
	if(root->l == NULL && root->r == NULL)//没有左右结点 
		{
			if(root->fa)//不是根节点 
				{
					if(root->fa->l == root)//被删除结点是父结点的左儿子 
						root->fa->l = NULL;//删除 
					else//删除右儿子 
						root->fa->r = NULL;
					root->fa = NULL;
				}
			//此时可以放心大胆地删除! 
			else //若删除的结点是一个根节点
				rt = NULL;//还需要清空标准根地址 
			delete root;
			return;
		}
	if(root->l != NULL && root->r == NULL)//如果只存在左子结点 
		{
			if(root->fa != NULL)//fa如果不是根节点,调整root左子结点为root位置即可。 
				{
					if(root->fa->l == root)//如果root是父结点的左儿子 
					{
						root->fa->l = root->l;//把父节点的左儿子设置成root的左儿子 
						root->l->fa = root->fa;
					}
					else
					{
						root->fa->r = root->l;
						root->l->fa = root->fa;
					}
					delete root;
					return;
				}
			//若为根节点,则直接把左子结点设置为根节点即可。 
			rt = root->l;
			root->l->fa = NULL;
			delete root;
			return;
		}
	if(root->l == NULL && root->r != NULL)//如果只存在右子结点 
		{
			if(root->fa != NULL)//fa如果不是根节点,调整root左子结点为root位置即可。 
				{
					if(root->fa->l == root)
					{
						root->fa->l = root->r;
						root->r->fa = root->fa;
					}
					else
					{
						root->fa->r = root->r;
						root->r->fa = root->fa;
					}
					delete root;
					return;
				}
			//若为根节点,则直接把右子结点设置为根节点即可。 
			rt = root->r;
			root->r->fa = NULL;
			delete root;
			return;
		}
	//最后一种情况,同时存在左右节点,需要找到后继来。
	node* suc = s(root->r);//先找到后继,再进行数据交换
	int t1 = root->val, t2 = root->cnt;
	root->val = suc->val;
	root->cnt = suc->cnt;
	suc->val = t1;
	suc->cnt = t2;
	erase(suc);
	return; 
}
/*Minus Function*/
void sub(node* root,int data)
{
	if(root == NULL) //若删除结点是空结点,忽略操作 
		{
			return;
		} 
	if(root->val == data)//如果已经找到对应结点,直接删去一次 
		{
			root->cnt--;
			if(root->cnt == 0)
				erase(root);
			return;	
		} 
	if(root->val > data)//若根节点比data大,递归在左子树查找删除结点 
		{
			sub(root->l,data);
		}
	else
		{
			sub(root->r,data);	
		}
		return;
}

/*First Order dfs*/
void VLR(node* root)
{
	if(root == NULL)
		return;
	printf("%d ", root->val);
	if(root->l)
		VLR(root->l);
	if(root->r)
		VLR(root->r);
	return;
}
int M;
int main()
{
	int type, tmp;
	scanf("%d", &M);
	while(M--)
		{
			scanf("%d", &type);
			if(type == 0)
				{
					VLR(rt);
					printf("\n");
					continue;
				}
			if(type == 1)
				{
					scanf("%d", &tmp);
					insert(rt,tmp);
					continue;
				}
			if(type == 2)
				{
					scanf("%d", &tmp);
					sub(rt,tmp);
					continue;
				}
		}
	return 0;
}



版权声明:本文为hjrxfly原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。