目录
〇,全文说明、宏定义代码
类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。
代码工程结构:
- 每一章的第一节《代码》可以独立编译运行(本地要加LOCAL宏)
- 每一章的第二节《测试代码》搭配第〇章的代码和本章第一节的代码可以编译运行并测试成功
- 所有模板文章的第〇章的代码和其他章第一节的《代码》全部汇总起来可以编译运行



宏定义代码:
#define LOCAL //力扣不要本行代码,其他OJ随意
///(1)二叉树///
#define MaxDepth BinaryTree::maxDepth//求二叉树的深度,根节点深度是1
#define MinDepth BinaryTree::minDepth//叶子节点的最小深度
#define PreorderTraversal BinaryTree::preorderTraversal//二叉树的前序遍历
#define PostorderTraversal BinaryTree::postorderTraversal//二叉树的后序遍历
#define InorderTraversal BinaryTree::inorderTraversal//二叉树的中序遍历
#define LevelOrderTraversal BinaryTree::levelOrderTraversal//二叉树的层序遍历
#define BuildTreePre BinaryTree::buildTreePre//根据前序和中序重建二叉树,假设没有重复数字
#define BuildTreePost BinaryTree::buildTreePost//根据中序和后序重建二叉树,假设没有重复数字
#define CountNodes BinaryTree::countNodes//求节点个数
#define CopyTree BinaryTree::copyTree//拷贝二叉树
#define IsSameTree BinaryTree::isSameTree//判断两棵二叉树是否全等
#define InvertTree BinaryTree::invertTree//左右翻转二叉树
///(2)树状数组、线段树///
// TreeArray 树状数组
// TreeArray2D 二维树状数组
// SegmentTree 线段树
///(3)多叉树、RMQ、LCA///
#define MultiTreePreorder MultiTree::preorder //多叉树前序遍历
#define MultiTreePostorder MultiTree::postorder //多叉树后序遍历
#define EdgesToMultiTree MultiTree::edgesToMultiTree//输入无向图,构造多叉生成树
// TreeWithId 略。//把二叉树或多叉树转成id形式的树,前序遍历,从0开始编号
// RMQ 略。
// LCA 略。
///(4)DancingLink、Covering///
// DancingLink 略。精确覆盖算法
#define GetEdgeCover Covering::getEdgeCover//给定一个2n个点的图,选出n条边,刚好覆盖这2n个点
///(5)匈牙利算法///
#define HungarianMaxMatch Hungarian().maxMatch //求二分图最大匹配,v是一边的点集,adjaList的每条边都恰好有一个点在v中
///(6.1)并查集///
// Union 略。并查集
// UnionDif 略。
// Vunion 略。
///(6.2)无向图///
#define GetAdjaListFromTree UndirectedGraph::getAdjaList //输入二叉树,转化成无向图的邻接表,没有权值,节点编号是先序遍历的编号,默认从0开始
#define EdgesToBinaryTree UndirectedGraph::edgesToBinaryTree //输入无环无向图,生成任意一棵二叉树,val存放原id,节点编号是从0开始依次编号
#define UndirectedEdgeToFatherList UndirectedGraph::undirectedEdgeToFatherList //无向拓扑排序,输入无向无环图{
{1,2}{1,3}{4,3}}和指定根1,输出父节点表{4:3, 3:1, 2:1}
#define HasUndirectedCircle UndirectedGraph::hasUndirectedCircle //判断无向图是否有环
#define IsCompleteGraph UndirectedGraph::isCompleteGraph //判断是不是k-正则图
#define IsTwoDivGraph UndirectedGraph::isTwoDivGraph //判断是不是二分图
///(6.3)最小生成树Kruskal///
#define KruskalMinCostTree Kruskal::kruskalMinCostTree
///(7)最小生成树Prim///
#define PrimminCostTree Prim::minCostConnectPoints
///(8.1)有向图///
#define ReverseGraph DirectedGraph::reverseGraph//构建有向图的反向图
#define GetLongestPath DirectedGraph::getLongestPath//求有向无环图中的最长路径长度,出参nextNode是每个点的后继,len是每个点出发的最长路径长度
#define HasDirectedCircle DirectedGraph::hasCircle//根据有向图的邻接表判断是否有环
///(8.2)单源最短路径///
#define DijskraShortestPath Dijskra::shortestPath//求最短路,适用于不存在负权值的边的图
#define BellmanFordShortestPath BellmanFord::shortestPath//求最短路,适用于不存在负权值的环的图
#define SPFAShortestPath SPFA::shortestPath//求最短路,适用于不存在负权值的环的图
///(8.3)不区分有向图和无向图的通用操作///
#define GetSubGraph GraphOpt::getSubGraph//根据点集取子图
///(8.4)连通分量、拓扑排序///
#define SemiConnectComponent SemiConnect::semiConnectComponent//半连通分量分割
#define ConnectComponent KosarajuStrongConnect::connectComponent//Kosaraju算法,强连通分量分割
#define GetPointGraph KosarajuStrongConnect::getPointGraph//强连通分量缩点
// TarjanUndirect 略。Tarjan算法,双连通分量分割
// TarjanStrongConnect 略。Tarjan算法,强连通分量分割
#define TopoSortNoCircle DirectedTopoSort::topoSortNoCircle //有向无环图拓扑排序,输入n=3,g.edges={
{0,1}{0,2}{1,2}}, 输出{0,1,2},有环则输出为空
#define TopoSort DirectedTopoSort::topoSort //有向图拓扑排序
///(9.1)网格图///
// GridGraph 略
///(9.2)回路或链路///
// Hierholzer 略。欧拉回路或链路
// Hamilton 略。哈密顿回路或链路
///(9.3)路径重建///
// ReBuild 略。路径重建
一,二叉树
1,代码
#ifdef LOCAL
#ifndef struct_TreeNode
#define struct_TreeNode
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
#endif
#endif
class BinaryTree
{
public:
//求二叉树的深度,根节点深度是1
static int maxDepth(TreeNode* root) {
if (!root)return 0;
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
//叶子节点的最小深度
static int minDepth(TreeNode* root) {
if (!root)return 0;
return min_depth(root);
}
//二叉树的前序遍历
static vector<int> preorderTraversal(TreeNode* root) {
vector<int>v1;
if (root == NULL)return v1;
v1.insert(v1.end(), root->val);
vector<int>v2 = preorderTraversal(root->left);
v1.insert(v1.end(), v2.begin(), v2.end());
v2 = preorderTraversal(root->right);
v1.insert(v1.end(), v2.begin(), v2.end());
return v1;
}
//二叉树的后序遍历
static vector<int> postorderTraversal(TreeNode* root) {
vector<int>v1;
if (root == NULL)return v1;
vector<int>v2 = postorderTraversal(root->left);
v1.insert(v1.end(), v2.begin(), v2.end());
v2 = postorderTraversal(root->right);
v1.insert(v1.end(), v2.begin(), v2.end());
v1.insert(v1.end(), root->val);
return v1;
}
//二叉树的中序遍历
static vector<int> inorderTraversal(TreeNode* root) {
vector<int>v1;
if (root == NULL)return v1;
v1 = inorderTraversal(root->left);
v1.insert(v1.end(), root->val);
vector<int>v2 = inorderTraversal(root->right);
v1.insert(v1.end(), v2.begin(), v2.end());
return v1;
}
//二叉树的层序遍历
static vector<vector<int>> levelOrderTraversal(TreeNode* root) {
vector<vector<int>>ans;
if (!root)return ans;
vector<vector<TreeNode*>>v;
vector<TreeNode*>tmp;
vector<int>tmpans;
tmp.push_back(root);
v.push_back(tmp);
bfs(v);
for (int i = 0; i < v.size(); i++) {
tmpans.resize(v[i].size());
for (int j = 0; j < v[i].size(); j++)tmpans[j] = v[i][j]->val;
ans.push_back(tmpans);
}
return ans;
}
//根据前序和中序重建二叉树,假设没有重复数字
static TreeNode* buildTreePre(vector<int>& preorder, vector<int>& inorder) {
return build_tree(preorder, 0, inorder, 0, inorder.size());
}
//根据中序和后序重建二叉树,假设没有重复数字
static TreeNode* buildTreePost(vector<int>& inorder, vector<int>& postorder) {
return build_tree2(postorder, 0, inorder, 0, inorder.size());
}
//求节点个数
static int countNodes(TreeNode* root) {
if (!root)return 0;
return countNodes(root->left) + countNodes(root->right) + 1;
}
//拷贝二叉树
static TreeNode* copyTree(TreeNode* root)
{
if (!root)return root;
return new TreeNode(root->val, copyTree(root->left), copyTree(root->right));
}
//判断两棵二叉树是否全等
static bool isSameTree(TreeNode* r1, TreeNode* r2)
{
if (r1 == NULL && r2 == NULL)return true;
if (r1 == NULL || r2 == NULL)return false;
if (r1->val != r2->val)return false;
return isSameTree(r1->left, r2->left) && isSameTree(r1->right, r2->right);
}
//左右翻转二叉树
static TreeNode* invertTree(TreeNode* root) {
if (!root)return root;
TreeNode* p = root->left, *q = root->right;
root->left = q, root->right = p;
invertTree(p);
invertTree(q);
return root;
}
private:
static int min_depth(TreeNode* root) {
if (!root)return 1234567890;
if (!root->left && !root->right)return 1;
return min(min_depth(root->left), min_depth(root->right)) + 1;
}
static void bfs(vector<vector<TreeNode*>>&v) {
vector<TreeNode*>v1 = *(v.end() - 1);
vector<TreeNode*>v2;
for (int i = 0; i < v1.size(); i++) {
if (v1[i]->left)v2.push_back(v1[i]->left);
if (v1[i]->right)v2.push_back(v1[i]->right);
}
if (v2.empty())return;
v.push_back(v2);
bfs(v);
}
static TreeNode* build_tree(vector<int>& preorder, int s1, vector<int>& inorder, int s2, int len) {
if (len <= 0)return NULL;
TreeNode* ans = new TreeNode;
ans->val = preorder[s1];
auto loc = find(inorder.begin() + s2, inorder.begin() + s2 + len, preorder[s1]);
ans->left = build_tree(preorder, s1 + 1, inorder, s2, loc - inorder.begin() - s2);
ans->right = build_tree(preorder, loc - inorder.begin() - s2 + s1 + 1, inorder, loc - inorder.begin() + 1, len - (loc - inorder.begin() - s2) - 1);
return ans;
}
static TreeNode* build_tree2(vector<int>& postorder, int s1, vector<int>& inorder, int s2, int len) {
if (len <= 0)return NULL;
TreeNode* ans = new TreeNode;
ans->val = postorder[s1 + len - 1];
auto loc = find(inorder.begin() + s2, inorder.begin() + s2 + len, postorder[s1 + len - 1]);
ans->left = build_tree2(postorder, s1, inorder, s2, loc - inorder.begin() - s2);
ans->right = build_tree2(postorder, loc - inorder.begin() - s2 + s1, inorder, loc - inorder.begin() + 1, len - (loc - inorder.begin() - s2) - 1);
return ans;
}
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testBinaryTree()
{
TreeNode t1(1), t2(2), t3(3), t4(4);
t1.left = &t2, t1.right = &t3, t2.left = &t4;
auto p = &t1;
EXPECT_EQ(MaxDepth(p), 3);
EXPECT_EQ(MinDepth(p), 2);
vector<int>pre{ 1, 2, 4, 3 }, post{ 4, 2, 3, 1 }, inorder{ 4, 2, 1, 3 };
EXPECT_EQ(PreorderTraversal(p), pre);
EXPECT_EQ(PostorderTraversal(p), post);
EXPECT_EQ(InorderTraversal(p), inorder);
auto p2 = BuildTreePre(pre, inorder);
EXPECT_EQ(IsSameTree(p, p2), true);
p2 = BuildTreePost(inorder, post);
EXPECT_EQ(IsSameTree(p, p2), true);
EXPECT_EQ(CountNodes(p), 4);
p2 = CopyTree(p);
EXPECT_EQ(IsSameTree(p, p2), true);
InvertTree(p2);
EXPECT_EQ(IsSameTree(p, p2), false);
InvertTree(p2);
EXPECT_EQ(IsSameTree(p, p2), true);
return true;
}
int main()
{
if (testBinaryTree())cout << "test succ!";
return 0;
}
二,树状数组、线段树
1,代码
template<int maxLen = 100000>
class TreeArray
{
public:
TreeArray(int len)//len是元素实际数量,元素id范围是[1,n]
{
this->n = len;
memset(c, 0, sizeof(int)*(len + 1));
}
void add(int i, int x)
{
while (i <= n)
{
c[i] += x;
i += (i&(-i));
}
}
int getSum(int i)
{
int s = 0;
while (i)
{
s += c[i];
i -= (i&(-i));
}
return s;
}
private:
int n;
int c[maxLen+5];
};
template<int maxLen = 1000>
class TreeArray2D
{
public:
TreeArray2D(int len)//len是元素实际数量,元素id范围是[1,n]*[1,n]
{
this->n = len;
for (int i = 0; i <= n; i++)memset(c[i], 0, sizeof(int)*(n + 1));
}
void add(int x, int y, int a = 1)
{
for (int i = x; i <= n; i += (i&(-i)))
for (int j = y; j <= n; j += (j&(-j)))c[i][j] += a;
}
int getSum(int x, int y)
{
int s = 0;
for (int i = x; i > 0; i -= (i&(-i)))
for (int j = y; j > 0; j -= (j&(-j)))
s += c[i][j];
return s;
}
private:
int n;
int c[maxLen +5][maxLen +5];
};
//type=0,1,2,3,4分别表示sum型、min型、max型、minId型、maxId型线段树
//maxLen是元素最大数量
template<int type, int maxLen = 100000, typename T = int>
class SegmentTreeBase
{
public:
T* getData()//先调getData更新数据再调build
{
return num;
}
void build(int len)//len是元素实际数量,元素id范围是[1,n]
{
this->n = len;
build(1, 1, n);
}
void update(int uplace, T value)//1<=uplace<=n
{
num[uplace] = value;
update(1, 1, n, uplace);
}
T query(int x, int y)//1<=x<=y<=n
{
return query(1, 1, n, x, y);
}
protected:
template<typename T2>
inline T2 op(T2 a, T2 b)
{
if (type == 3)return num[a] < num[b] ? a : b;
if (type == 4)return num[a] > num[b] ? a : b;
if (type == 0)return a + b;
return type == 1 ? min(a, b) : max(a, b);
}
void build(int key, int low, int high)
{
if (low == high)
{
ans[key] = type > 2 ? low : num[low];
return;
}
int mid = (low + high) / 2;
build(key * 2, low, mid);
build(key * 2 + 1, mid + 1, high);
ans[key] = op(ans[key * 2], ans[key * 2 + 1]);
}
void update(int key, int low, int high, int uplace)
{
if (low == high)
{
ans[key] = type > 2 ? low : num[low];
return;
}
int mid = (low + high) / 2;
if (uplace <= mid)update(key * 2, low, mid, uplace);
else update(key * 2 + 1, mid + 1, high, uplace);
ans[key] = op(ans[key * 2], ans[key * 2 + 1]);
}
T query(int key, int low, int high, int x, int y)
{
if (low == x && high == y)return ans[key];
int mid = (low + high) / 2;
if (mid < x)return query(key * 2 + 1, mid + 1, high, x, y);
if (mid >= y)return query(key * 2, low, mid, x, y);
T a = query(key * 2, low, mid, x, mid);
T b = query(key * 2 + 1, mid + 1, high, mid + 1, y);
return op(a, b);
}
protected:
int n;
T num[maxLen + 1];
T ans[maxLen * 4 + 10];
};
//sum型线段树拓展,支持查询前缀和
template<int maxLen = 100000, typename T = int>
class SegmentTreeTypeSum :public SegmentTreeBase<0, maxLen, T>
{
using BASE = SegmentTreeBase<0, maxLen, T>;
public:
int queryPreSum(T x)
{
return queryPreSum(1, 1, BASE::n, x);
}
private:
int queryPreSum(int key, int low, int high, T x)
{
if (low == high)return low;
int mid = (low + high) / 2;
if (x <= BASE::ans[key * 2])return queryPreSum(key * 2, low, mid, x);
return queryPreSum(key * 2 + 1, mid + 1, high, x - BASE::ans[key * 2]);
}
};
//5种线段树拓展,支持区间更新,区间查询
template<int type, int maxLen = 100000, typename T = int, T invalid = -1>
class SegmentTree :public SegmentTreeBase<type, maxLen, T>
{
using BASE = SegmentTreeBase<type, maxLen, T>;
public:
void build(int len)//len是元素实际数量,元素id范围是[1,n]
{
BASE::n = len;
build(1, 1, BASE::n);
}
void update(int uplace, T value)//1<=uplace<=n,覆盖父类函数
{
update(uplace, uplace, value);
}
void update(int x, int y, T value)//1<=x<=y<=n
{
update(1, 1, BASE::n, x, y, value);
}
T query(int x, int y)//1<=x<=y<=n
{
return query(1, 1, BASE::n, x, y);
}
private:
static inline T opMulti(T a, int num)
{
if (!type)return a * num;
return a;
}
void build(int key, int low, int high)
{
if (low == high)
{
BASE::ans[key] = type > 2 ? low : BASE::num[low];
lazy[key] = invalid;
return;
}
int mid = (low + high) / 2;
build(key * 2, low, mid);
build(key * 2 + 1, mid + 1, high);
BASE::ans[key] = BASE::op(BASE::ans[key * 2], BASE::ans[key * 2 + 1]);
lazy[key] = invalid;
}
void update(int key, int low, int high, int x, int y, T value)
{
if (low == x && high == y)
{
BASE::ans[key] = type > 2 ? x : opMulti(value, high - low + 1);
lazy[key] = value;
if (x == y)BASE::num[x] = value;
return;
}
if (lazy[key] != invalid)down(key, low, high);
int mid = (low + high) / 2;
if (mid < x)update(key * 2 + 1, mid + 1, high, x, y, value);
else if (mid >= y)update(key * 2, low, mid, x, y, value);
else
{
update(key * 2, low, mid, x, mid, value);
update(key * 2 + 1, mid + 1, high, mid + 1, y, value);
}
BASE::ans[key] = BASE::op(BASE::ans[key * 2], BASE::ans[key * 2 + 1]);
}
void down(int key, int low, int high)
{
int mid = (low + high) / 2;
BASE::ans[key * 2] = type > 2 ? low : opMulti(lazy[key], mid - low + 1);
BASE::ans[key * 2 + 1] = type > 2 ? high : opMulti(lazy[key], high - mid);
lazy[key * 2] = lazy[key];
lazy[key * 2 + 1] = lazy[key];
lazy[key] = invalid;
}
T query(int key,

该博客提供多种数据结构与算法的Java代码及测试代码,涵盖二叉树、树状数组、线段树等数据结构,以及匈牙利算法、最小生成树算法等。代码有接口注释,各部分代码有明确的编译运行规则,可独立或汇总编译运行。
最低0.47元/天 解锁文章
2783

被折叠的 条评论
为什么被折叠?



