1.【桌面软件开发分享】Desktop-portable-topological-sorting-application(桌面便携式拓扑排序软件)
2.案例解读|高盛 Goldman Sachs 如何做数据库变更
3.C语言 任意表达式求值。拓扑拓扑(栈的排序排序应用
4."tsort"缩写为何意,即“拓扑排序”?
【桌面软件开发分享】Desktop-portable-topological-sorting-application(桌面便携式拓扑排序软件)
这篇博客详细介绍了拓扑排序图绘制工具——TopologicalSort_app的开发与实现,以确保项目的拓扑拓扑实施和开发合理、可行。排序排序项目采用Python语言,源码源码脚本精灵 源码结合PySide2、拓扑拓扑networkx、排序排序matplotlib、源码源码subprocess等库,拓扑拓扑实现了一个桌面便携式拓扑排序软件。排序排序此软件具备技术可行性和操作可行性,源码源码能够高效、拓扑拓扑准确地绘制拓扑排序图。排序排序技术实现方案包括使用PySide2构建图形用户界面,源码源码网络x和matplotlib绘制图形,Python的文件处理功能实现文件导入导出,以及使用C++程序进行拓扑排序的计算。开发人员需具备Python编程、图论知识,以及调用C++程序的能力。操作界面设计简单明了,用户容易上手,提供了导入、导出、绘制图像等功能,符合用户使用习惯。C++程序的调用对用户透明,操作界面友好,确保了操作可行性。项目设计包括修订历史记录、软硬件环境、需求分析、js 组织架源码详细设计、运行结果截图和测试内容,以及系统特色与可扩展点。系统特色包括图形用户界面、拓扑排序图绘制、文件导入导出、C++程序调用、动态UI加载、用户操作反馈和异常处理。可扩展点包括核心源代码的模块化设计和GitHub仓库地址。用户可以遵循用户使用手册进行安装与操作,完成基本功能如导入文件、生成拓扑排序、导出结果。此软件为桌面便携式,适用于拓扑排序图的绘制与分析。
案例解读|高盛 Goldman Sachs 如何做数据库变更
本文重点
近年,高盛采用了标准的 SDLC 来构建和部署应用程序。这包括管理新系统和现有系统的数据库 schema ,这比管理应用程序代码更加困难。在本文中,我们将描述我们最近开源的数据库部署工具 Obevo 是如何帮助高盛的企业级应用程序的数据库纳入 SDLC 管控的。
企业的数据库部署的问题
将数据库定义引入到标准的 SDLC 流程中是具有挑战性的,尤其是考虑到数据库的状态以及执行增量迁移的需求。因此,许多应用程序没有自动化或流畅的数据库部署过程。我们的目标是将数据库 schema 管理纳入与应用程序相同的 SDLC 中:通过将所有定义提交到版本控制系统 (VCS) 并通过标准的构建/发布机制部署。
这项工作由我们实际数据库系统使用案例的多样性而变得复杂:
无论使用何种案例,由于大量分布各地的开发人员都在进行变更,SDLC 本身都有复杂之处。
虽然现有的开源工具可以处理简单的案例,它们无法处理我们一些现有系统的php源码 云盘规模和复杂度。但是我们不能放任这些现有系统没有适当的 SDLC:它们是正在开发和发布的关键系统。
因此,我们开发了 Obevo,一个能处理所有此类使用案例的工具。Obevo 的关键差异化因素在于能够 按文件维护数据库对象(类似于更常见的 按文件存储类定义),同时仍管理增量部署。
在本文中,我们将讨论数据库部署问题,然后演示基于对象的项目结构如何帮助我们优雅地管理各种对象和环境类型的上百上千个 schema 对象。
数据库对象类型(有状态 vs 无状态)
首先,我们来回顾一下不同数据库对象类型的部署语义,因为这会影响工具的设计。
有状态对象(例如:表) 需要增量修改其定义,而不是完全的定义替换。以下是添加两列到 MyTable 中的示例:
理想情况下,我们可以通过一个 SQL 语句来把数据库带到终态,该 SQL 定义了一个具有四列的表。不过 SQL 其实无法提供可行的解决方案:
相反,关系型数据库管理系统 (RDBMS) 允许用户使用 ALTER 语句来修改现有表。
某些列更新可能需要进行数据迁移,例如从一个表中移动列数据到另一个表中。
因此,每个对象都是应用多个脚本片段的结果;初始脚本片段创建对象,后续脚本片段修改对象。
无状态对象(例如:视图,存储过程) 可以通过指定其完整对象定义来创建和修改。
我们也将静态数据文件(代码或参考数据表)视为无状态对象。虽然它涉及到表数据,但是这些数据在你的脚本中已经完全定义,并且可以通过批量 delete + insert 或选择性 insert + update + delete 操作部署到表中。
数据库部署工具原则
Martin Fowler 的 Evolutionary Database Design 对基于源头控制的数据库部署工具遵循的主要原则进行了精彩阐述,下面是delphi程序源码下载其中一些具体相关的要点。
基于 UI 的管理可能适用于非技术用户,但我们建议开发团队将其数据库脚本片段存储在源代码控制中(和对待其它应用程序一样),并以自动化方式调用部署。
在我们看来,在企业环境中,例如在当前数据库表状态和代码完整视图之间自动计算迁移是有风险的。
数据库部署工具要求
我们根据以下需求评估数据库部署工具的处理能力:
A) 将增量更改部署到现有数据库中 这是数据库部署工具的主要功能;大多数生产环境都是通过此方式执行的。在一些非生产环境中,尤其是在发布到生产之前的 QA 环境中进行测试时,也会使用此方法。
B) 将完整 schema 部署到空白数据库中 开发人员可能希望将其部署到一个空白沙盒数据库以进行以下操作:
这可以通过以下几种方式来完成:
C) 易于维护和阅读 在我们进行数据库部署改进之前,我们看到一些团队为每个数据库对象维护一个文件,其中包含对象的定义,尽管这些文件并未用于部署。
这似乎没有意义,但我们获得了一些见解:
通用数据库部署工具设计主要部署算法
根据上述原则,大多数基于源代码控制的数据库部署工具(包括 Obevo)的工作方式如下:
有状态和无状态对象部署语义
对象类型对变更集计算语义会产生影响。
为了演示有状态用例,我们将 deploy 部署包 v1 以获取右侧表。
假设有人修改了 M3 并重命名了列,然后我们进行重新部署。我们期望会发生什么?
工具检测到不匹配:
因此,一般规则是:有状态对象脚本一旦部署就不能修改。
某些选择性功能可以让我们在需要时绕过这个问题,例如:
数据库部署工具的实现选择
考虑到它们的底层算法相似,部署工具因几个实现要点而异。
1)如何将脚本片段组织成文件
有如下几种方式将脚本片段进行分组:
2)如何排序部署要部署的脚本片段
需要考虑:
接下来,我们将详细介绍 Obevo 是如何解决这两个问题的。
Obevo 设计:基于对象的脚本组织
我们主要的数据库部署问题是如何管理 schema 中大量对象的开发、维护和部署。同时,还有开发人员在编写应用程序时处理他们的svn怎么下载源码数据库对象。
因此,我们希望提供一种对开发人员来说易于理解的体验,这导致了我们根据对象名称组织脚本。在本节中,我们将深入探讨这些详细信息。(该结构增加了一些排序方面的挑战,下一节详细介绍)
项目结构基础
我们根据适用于那些对象的脚本片段来组织,以下是一个示例。
文件结构根据对象是否具有状态而不同。
分析:无状态对象处理
基于对象的结构对于无状态对象方便很多,因为完整的无状态对象定义可以在文件中维护,并且可以就地修改。
作为比较,在增量有状态的方式中,技术上可以处理无状态对象部署,例如作为持久化多个版本的增量脚本。然而,这会导致数据库脚本存在冗余,因为对象在多个版本中发生变化。
分析:可读性
从维护的角度来看,这个项目结构有一些优势:
为了进行比较,可以拿一个项目结构的例子来说明,其中一个文件与迁移或发布相关联,因为许多工具都支持这种方式。这可能会导致一些问题:
从代码审查/发布审查角度来看:面向对象的结构意味着特定版本中所有更改都会分散在文件中。乍一看,似乎很难审核要部署到下一个版本的脚本片段。但是,我们仍然可以通过比较 VCS 历史记录和标签来审核发布的代码 - 就像处理应用程序代码一样。
分析:对于开发者的好处
使用 Obevo 项目结构,开发人员也好处多多。
由于对象的脚本片段放置在单个文件中,我们可以轻松地在测试中部署单个对象,这对于像在内存数据库中进行数据访问 API 的单元测试等情况非常有用。
开发人员也可以利用 ORM 工具从应用程序生成 DDL,并与迁移脚本进行协调。简洁起见,这里我们不深入讨论,但你可以在文档中了解更多。
Obevo 设计: 通过依赖性分析进行排序
虽然选择基于对象的项目组织方式提供了上一节中提到的许多好处,但它也使排序变得更加复杂。
对象可以互相依赖,随着我们把 schema 扩展到数百或数千个对象,手动指定顺序变得越来越困难。
让我们描述一下我们是如何克服这些挑战的。
排序算法
不是所有的脚本片段都互相依赖,因此我们在对象依赖声明的明显约束下是有一些灵活性的。
因此,我们使用一个简单的图算法来设计解决方案。
比如以下示例语句:
注意以下几点:
这适合使用有向图表示,其中图节点是脚本片段,边是顺序依赖关系。
我们现在可以使用拓扑排序算法得出一个可接受的顺序,以保持这些顺序约束并成功部署我们的数据库。
拓扑排序可以产生许多可接受的顺序,但是我们会调整算法使用方式以给出单一一致的顺序,以便在各个环境中具有一致性。
现在最后一个细节:如何在脚本片段中声明依赖关系?
依赖声明和发现
我们发现最简单的方法是在脚本中声明依赖项。请参见下面 TABLE_B.fkA 脚本片段中的dependencies 属性。
然而,对于大型数据库来说这并不友好(想象一下注释数百或数千个对象),因此我们需要一种自动检测依赖关系的方式,同时仍允许开发者覆盖。
我们使用两种策略来推断依赖关系:
有状态迁移的内部对象依赖关系:
我们允许有状态的对象定义多个脚本。很自然地,我们认为在同一个文件中编写的迁移按照它们编写的顺序进行部署,因此我们推断出这样的依赖关系(下图)。
通过文本搜索实现跨对象依赖关系
为检测跨对象的依赖关系,我们需要搜索脚本内容以查找相关对象。
从技术上讲,理想的方法是解析 SQL 以查找这些对象。然而,这非常困难,因为我们必须理解所有支持的 DBMS 类型的 SQL 语法。
相反,Obevo 采用简单的方法:在你的项目中选择通过字符串搜索发现的对象名称,并假定它们是依赖项。
实现说明:
以下是我们先前示例的算法结果:
如果出现误报匹配(例如由于注释)或假阴,开发人员可以根据需要指定排除或包含覆盖。
乍一看,可能很难想象这适用于实际用例,但我们已经成功地使用了这种技术来部署许多复杂的 schema ,其中一些跨越数千个对象,如表、存储过程、视图等。
想看实例的话请查看我们的 kata 课程,该课程是个通过一个大型数据库 schema 反向工程的示例。
跨多个表处理数据迁移
我们快速过一下这种用法(即将数据从旧列移动到新列,然后删除旧列),因为最开始将基于对象的文件结构概念应用于此听起来更复杂。
Obevo 可以处理这个问题 - 简而言之,我们提供了「迁移」对象的概念来帮助解决此问题,它:
如需更多信息,请查看 文档。
现有数据库 schema 的逆向工程
希望我们成功展示了你可以使用 Obevo 部署复杂的数据库 schema 。但是,为了让现有系统真正加入到 Obevo 中,我们必须使开发人员能够轻松地对现有数据库进行逆向工程。
解决这个问题并不容易,因为不幸的是,在不同的 DBMS 类型之间没有一个完美的统一 API
因此,我们选择与供应商提供的反向工程工具集成(见下表)。一些工具只需将完整架构输出到单个文件中即可,但我们提供了一个实用程序,可以将这些文件转换为 Obevo 基于对象结构,并利用简单字符串解析和正则表达式技术。相比 Java API,我们认为这种技术更可靠于现有系统中,特别是核心供应商工具最懂得他们自己架构。
数据库管理系统
结论
虽然有许多开源工具可用于数据库部署,但我们认为更复杂的使用情况需要更强大的工具支持。
通过 Obevo,我们旨在支持所有类型的系统;无论是通过测试功能和易于基于对象维护来增强现代系统的生产力,还是通过促进长期存在但以前没有 SDLC 管控的系统加入管控重获新生。
这里还有更多未涉及到的特性和数据库部署活动(例如回滚、分阶段部署、内存 DB 测试、多 schema 管理)。欢迎访问我们的 Github,文档和 Kata 课程,了解更多关于 Obevo 以及如何将该工具应用到你的系统中。
Bytebase 团队的读后感
通过解读高盛如何变更数据库的案例,我们可以一窥企业级数据库变更的复杂度。这篇文章的精华在于当中对于数据库变更工具设计方案选择的亮点归纳:
Obevo 相比于业界其他的工具,在这两点上都选择了非主流,但是可以更加自动化的方案:
对于高盛来说这是可行的,因为在一个单一组织内,可以通过各种约束,保证操作的一致性,然后基于这样的统一,提高自动化。但是如果要作为一个对外输出的方案,就未必能应付不同组织不同的操作习惯。 Bytebase 团队接触到 Obevo 也是一个潜在客户在调研各种方案时聊起的。相比于 Obevo 而言,Bytebase 提供的是数据库变更,查询,安全,治理一体化方案,而且还提供了可视化界面。
你可以访问 官网,免费注册云账号,立即体验 Bytebase。
C语言 任意表达式求值。(栈的应用
/*** 只适合整数的表达式求值 ***/
/***其中部分可作修改,表达式也可是输入的***/
#include "iostream.h"
const int n0=;
int s1[n0+1]; //操作数栈
char s2[n0+1]; //运算符栈
int t1,t2;
int num[4]; //提取表达式中的整数
void calcu() //一次计算
{
int x1,x2,x;
char p;
//弹出一个运算符
p=s2[t2--];
//弹出两个操作数
x2=s1[t1--];
x1=s1[t1--];
//进行一次运算
switch(p) {
case '+':x=x1+x2;break;
case '-':x=x1-x2;break;
case '*':x=x1*x2;break;
case '/':x=x1/x2;
}
//结果压入操作数栈
s1[++t1]=x;
}
int calculator(char *f)
{
int v,i=0;
char *p=f;
t1=t2=0; //设置空栈
while (*p!='\0')
switch(*p) {
case '+': case '-':
while (t2&&(s2[t2]!='('))
//执行先遇到的加、减、乘、除运算
calcu();
//当前运算符进栈
s2[++t2]=*p;
//读下一个字符
p++;
break;
case '*': case '/':
if (t2&&(s2[t2]=='*')||(s2[t2]=='/'))
//执行先遇到的乘、除运算
calcu();
//当前运算符进栈
s2[++t2]=*p;
//读下一个字符
p++;
break;
case '(':
//左括号进栈
s2[++t2]=*p;
//读下一个字符
p++;
break;
case ')':
while (s2[t2]!='(')
//执行括号内的加、减、乘、除运算
calcu();
//弹出左括号
t2--;
//读下一个字符
p++;
break;
default:
//把字符串转换成整数值
v=0;
do {
v=*v+*p-'0';
p++;
} while((*p>='0')&&(*p<='9'));
//操作数进栈
s1[++t1]=v;
num[i++]=v;
};
//执行先遇到的加、减、乘、除运算
while (t2) calcu();
//返回结果
return s1[t1];
}
void main()
{
char a[]="5*(+6)-";
cout<<calculator(a)<<endl;
cout<<"其中的数字为:\n";
for (int i=0;i<4;i++)
{
cout<<num[i]<<' ';
}
cout<<endl;
}
原来做过的东西,是C++的,VC++6.0环境下调试运行成功。
"tsort"缩写为何意,即“拓扑排序”?
在计算机科学领域,"tsort"这个英文缩写词通常代表"Topological SORT",中文直译为“拓扑排序”。这个术语主要用于描述一种算法,它对有向无环图(DAG)中的节点进行排序,确保每个节点的依赖关系得到满足。tsort在Unix命令中颇为流行,有着次的查询量,主要应用于计算机编程、源代码分析、工艺路线优化以及算法分析等领域。
在具体应用中,tsort算法被用于如下的场景:在图的遍历中,它帮助确定节点的访问顺序;在构建最小生成树时,确保边的添加顺序正确;在关键路径分析中,帮助识别项目中的关键步骤。例如,tsort命令允许用户对文件执行拓扑排序,这对于需要复杂排序策略的情况非常有用。
尽管tsort源自英文,但其概念和使用已广泛渗透到网络资源和学习材料中。请注意,这些信息仅供参考,版权归属原作者,读者在使用时应自行甄别,以确保正确理解和应用。