lsyf / lsyf.github.io Goto Github PK
View Code? Open in Web Editor NEWblog
blog
应用调了sl4j-api,即日志门面接口。
日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用。
由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,上图红框中的组件即是对应的各种桥接器!
log4
: log4j1的全部内容log4j-api
: log4j2定义的APIlog4j-core
: log4j2上述API的实现logback-core
: logback的核心包logback-classic
: logback实现了slf4j的APIcommons-logging
: commons-logging的原生全部内容log4j-jcl
: commons-logging到log4j2的桥梁jcl-over-slf4j
: commons-logging到slf4j的桥梁slf4j-jdk14
:slf4j到jdk-logging的桥梁slf4j-log4j12
:slf4j到log4j1的桥梁log4j-slf4j-impl
:slf4j到log4j2的桥梁logback-classic
:slf4j到logback的桥梁slf4j-jcl
:slf4j到commons-logging的桥梁jul-to-slf4j
:jdk-logging到slf4j的桥梁log4j-over-slf4j
:log4j1到slf4j的桥梁jcl-over-slf4j
:commons-logging到slf4j的桥梁org/slf4j/impl/StaticLoggerBinder.class
(每个实现包中都会有)StaticLoggerBinder.class
进行绑定(个人猜测classpath顺序,可以通过自定义org.slf4j.impl.StaticLoggerBinde指定)StaticLoggerBinder.class
获取LoggerFactory
package list
import (
"container/list"
"fmt"
"strings"
)
type Stack struct {
list *list.List
}
func NewStack() *Stack {
list := list.New()
return &Stack{list}
}
func (stack *Stack) Push(value interface{}) {
stack.list.PushBack(value)
}
func (stack *Stack) Pop() interface{} {
e := stack.list.Back()
if e != nil {
stack.list.Remove(e)
return e.Value
}
return nil
}
func (stack *Stack) Peak() interface{} {
e := stack.list.Back()
if e != nil {
return e.Value
}
return nil
}
func (stack *Stack) Len() int {
return stack.list.Len()
}
func (stack *Stack) String() (str string) {
data := make([]string, 0, stack.Len())
for e := stack.list.Front(); e != nil; e = e.Next() {
data = append(data, fmt.Sprintf("%v", e.Value))
}
str = strings.Join(data, ",")
str = "[" + str + "]"
return
}
package list
import (
"fmt"
"strings"
)
type Node struct {
next, pre *Node
Value interface{}
}
type LinkedList struct {
root, tail *Node
len int
}
func NewLinkedList() *LinkedList {
l := new(LinkedList)
return l
}
func (l *LinkedList) Add(v interface{}) {
if l.root == nil {
l.root = &Node{Value: v}
l.tail = l.root
l.len++
return
}
n := &Node{Value: v}
n.pre = l.tail
l.tail.next = n
l.tail = n
l.len++
}
func (l *LinkedList) Get(i int) interface{} {
if i < 0 || i >= l.len {
return nil
}
switch {
case i == 0:
return l.root.Value
case i == l.len-1:
return l.tail.Value
case i < l.len/2: //下标小于长度1/2从头结点遍历
n := l.root
for x := 0; x < i-1; x++ {
n = n.next
}
return n.Value
default: //下标大于长度1/2从尾结点遍历
n := l.tail
for x := 0; x < l.len-1-i; x++ {
n = n.pre
}
return n.Value
}
}
func (l *LinkedList) Remove(i int) interface{} {
if i < 0 || i >= l.len {
return nil
}
switch {
case l.len == 1: //长度为1代表只有头结点可删除
n := l.root
l.root = nil
l.tail = nil
l.len--
return n.Value
case i == 0:
n := l.root
l.root = l.root.next
l.root.pre = nil
l.len--
return n.Value
case i == l.len-1:
n := l.tail
l.tail = l.tail.pre
l.tail.next = nil
l.len--
return n.Value
case i < l.len/2: //下标小于长度1/2从头结点遍历
n := l.root
for x := 0; x < i-1; x++ {
n = n.next
}
n.pre.next = n.next
n.next.pre = n.pre
l.len--
return n.Value
default: //下标大于长度1/2从尾结点遍历
n := l.tail
for x := 0; x < l.len-1-i; x++ {
n = n.pre
}
n.pre.next = n.next
n.next.pre = n.pre
l.len--
return n.Value
}
}
func (l *LinkedList) Clear() {
l.root = nil
l.tail = nil
l.len = 0
}
func (l *LinkedList) Contains(v interface{}) bool {
n := l.root
for n != nil {
if n.Value == v {
return true
}
n = n.next
}
return false
}
func (l *LinkedList) String() (str string) {
data := make([]string, 0, l.len)
n := l.root
for n != nil {
data = append(data, fmt.Sprintf("%v", n.Value))
n = n.next
}
str = strings.Join(data, ",")
str = "[" + str + "]"
return
}
依赖调节原则: 1. 路径最近者优先; 2. 第一声明者优先
A–>B–>C。当前项目为A,A依赖于B,B依赖于C。知道B在A项目中的scope,那么怎么知道C在A中的scope呢?答案是:
当C是test或者provided时,C直接被丢弃,A不依赖C;
否则A依赖C,C的scope继承于B的scope。
pom
在该<dependencyManagement>
部分中的类型依赖项上受支持。从其他项目导入托管依赖项,例如spring-cloud-dependencies加载顺序:
<build><filters>
中的配置<properties>
${basedir}/target目录
${artifactId}-${version}
${name}
值应用到 resources 中。Maven的默认filter文件夹是 ${basedir}/src/main/filters/
${basedir}/src/main/resources
*
作为通配符;includes
和 excludes
,则 excludes
生效;test
时使用,默认的 test resource
文件夹路径是 ${basedir}/src/test/resources
,test resource
不被部署。<goal>run</goal>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 项目的全球唯一标识符,通常使用全限定的包名区分该项目和其他项目。并且构建时生成的路径也是由此生成, 如com.seyvoue.demo生成的相对路径为:/com/seyvoue/demo-->
<groupId>com.seyvoue.demo</groupId>
<!-- 构件的标识符,它和 groupId 一起唯一标识一个构件。换句话说,你不能有两个不同的项目拥有同样的 artifactId 和 groupId;在某个特定的 groupId 下,artifactId也必须是唯一的。-->
<artifactId>demo-maven</artifactId>
<!-- 项目当前版本,格式为:主版本.次版本.增量版本-限定版本号-->
<version>1.0.0-SNAPSHOT</version>
<!-- 项目产生的构件类型,例如 jar、war、pom 等。插件可以创建他们自己的构件类型,所以前面列的不是全部构件类型-->
<packaging>jar</packaging>
<!-- 项目的名称,Maven产生的文档用-->
<name>project-demo</name>
<!-- 项目主页的URL,Maven产生的文档用-->
<url>http://demo.seyvoue.com</url>
<!-- 项目的详细描述, Maven 产生的文档用。当这个元素能够用HTML格式描述时(例如,CDATA中的文本会被解析器忽略,就可以包含HTML标签), 不鼓励使用纯文本描述。如果你需要修改产生的web站点的索引页面,你应该修改你自己的索引页文件,而不是调整这里的文档。-->
<description>A demo of maven project to study maven.</description>
<parent>
<!--被继承的父项目的构件标识符-->
<artifactId/>
<!--被继承的父项目的全球唯一标识符-->
<groupId/>
<!--被继承的父项目的版本-->
<version/>
<!-- 父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。默认值是../pom.xml。Maven首先在构建当前项目的地方寻找父项目的pom,其次在文件系统的这个位置(relativePath位置),然后在本地仓库,最后在远程仓库寻找父项目的pom。-->
<relativePath/>
</parent>
<!-- 继承自该项目的所有子项目的默认依赖信息。这部分的依赖信息不会被立即解析,而是当子项目声明一个依赖(必须描述group ID和 artifact ID信息),如果group ID和artifact ID以外的一些信息没有描述,则通过group ID和artifact ID 匹配到这里的依赖,并使用这里的依赖信息。-->
<dependencyManagement>
<dependencies>
<!--参见dependencies/dependency元素-->
<dependency>
...
</dependency>
</dependencies>
</dependencyManagement>
<!--该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。-->
<dependencies>
<dependency>
<!--依赖的group ID-->
<groupId>org.apache.maven</groupId>
<!--依赖的artifact ID-->
<artifactId>maven-artifact</artifactId>
<!--依赖的版本号。 在Maven 2里, 也可以配置成版本号的范围。-->
<version>3.8.1</version>
<!-- 依赖类型,默认类型是jar。它通常表示依赖的文件的扩展名,但也有例外。一个类型可以被映射成另外一个扩展名或分类器。类型经常和使用的打包方式对应, 这也有例外。一些类型的例子:jar,war,ejb-client和test-jar。如果设置extensions为 true,就可以在 plugin里定义新的类型。所以前面的类型的例子不完整。-->
<type>jar</type>
<!-- 依赖的分类器。分类器可以区分属于同一个POM,但不同构建方式的构件。分类器名被附加到文件名的版本号后面。例如,如果你想要构建两个单独的构件成 JAR,一个使用Java 4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件。-->
<classifier></classifier>
<!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。
- compile :默认范围,用于编译
- provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath
- runtime: 在执行时需要使用
- test: 用于test任务时使用
- system: 需要外在提供相应的元素。通过systemPath来取得
- systemPath: 仅用于范围为system。提供相应的路径
- optional: 当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用-->
<scope>test</scope>
<!--仅供system范围使用。注意,不鼓励使用这个元素,并且在新的版本中该元素可能被覆盖掉。该元素为依赖规定了文件系统上的路径。需要绝对路径而不是相对路径。推荐使用属性匹配绝对路径,例{java. home}。-->
<systemPath></systemPath>
<!--当计算传递依赖时, 从依赖构件列表里,列出被排除的依赖构件集。即告诉maven你只依赖指定的项目,不依赖项目的依赖。此元素主要用于解决版本冲突问题-->
<exclusions>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
<!--可选依赖,如果你在项目B中把C依赖声明为可选,你就需要在依赖于B的项目(例如项目A)中显式的引用对C的依赖。可选依赖阻断依赖的传递性。-->
<optional>true</optional>
</dependency>
...
</dependencies>
<!--模块(有时称作子项目) 被构建成项目的一部分。列出的每个模块元素是指向该模块的目录的相对路径-->
<modules>
<module>account-email</module>
<module>account-persist</module>
...
</modules>
<scm>
<!--SCM的URL,该URL描述了版本库和如何连接到版本库。欲知详情,请看SCMs提供的URL格式和列表。该连接只读。-->
<connection>
scm:svn:http://svn.baidu.com/banseon/maven/banseon/banseon-maven2-trunk(dao-trunk)
</connection>
<!--给开发者使用的,类似connection元素。即该连接不仅仅只读-->
<developerConnection>
scm:svn:http://svn.baidu.com/banseon/maven/banseon/dao-trunk
</developerConnection>
<!--当前代码的标签,在开发阶段默认为HEAD-->
<tag/>
<!--指向项目的可浏览SCM库(例如ViewVC或者Fisheye)的URL。-->
<url>http://svn.baidu.com/banseon</url>
</scm>
<!--项目分发信息,在执行mvn deploy后表示要发布的位置。有了这些信息就可以把网站部署到远程服务器或者把构件部署到远程仓库。-->
<distributionManagement>
<!--部署项目产生的构件到远程仓库需要的信息-->
<repository>
<!--是分配给快照一个唯一的版本号(由时间戳和构建流水号)?还是每次都使用相同的版本号?参见repositories/repository元素-->
<uniqueVersion/>
<id>banseon-maven2</id>
<name>banseon maven2</name>
<url>file://${basedir}/target/deploy</url>
<layout/>
</repository>
<!--构件的快照部署到哪里?如果没有配置该元素,默认部署到repository元素配置的仓库,参见distributionManagement/repository元素-->
<snapshotRepository>
<uniqueVersion/>
<id>banseon-maven2</id>
<name>Banseon-maven2 Snapshot Repository</name>
<url>scp://svn.baidu.com/banseon:/usr/local/maven-snapshot</url>
<layout/>
</snapshotRepository>
<!--部署项目的网站需要的信息-->
<site>
<!--部署位置的唯一标识符,用来匹配站点和settings.xml文件里的配置-->
<id>banseon-site</id>
<!--部署位置的名称-->
<name>business api website</name>
<!--部署位置的URL,按protocol://hostname/path形式-->
<url>
scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web
</url>
</site>
<!--项目下载页面的URL。如果没有该元素,用户应该参考主页。使用该元素的原因是:帮助定位那些不在仓库里的构件(由于license限制)。-->
<downloadUrl/>
<!--如果构件有了新的group ID和artifact ID(构件移到了新的位置),这里列出构件的重定位信息。-->
<relocation>
<!--构件新的group ID-->
<groupId/>
<!--构件新的artifact ID-->
<artifactId/>
<!--构件新的版本号-->
<version/>
<!--显示给用户的,关于移动的额外信息,例如原因。-->
<message/>
</relocation>
<!-- 给出该构件在远程仓库的状态。不得在本地项目中设置该元素,因为这是工具自动更新的。有效的值有:none(默认),converted(仓库管理员从 Maven 1 POM转换过来),partner(直接从伙伴Maven 2仓库同步过来),deployed(从Maven 2实例部 署),verified(被核实时正确的和最终的)。-->
<status/>
</distributionManagement>
<build>
<!--当项目没有规定目标(Maven2 叫做阶段)时的默认值-->
<defaultGoal>install</defaultGoal>
<!--build目标文件的存放目录,默认在 ${basedir}/target 目录-->
<directory>${basedir}/target</directory>
<finalName>${artifactId}-${version}</finalName>
<filters>
<filter>filters/filter1.properties</filter>
</filters>
<!--这个元素描述了项目相关的所有资源路径列表,例如和项目相关的属性文件,这些资源被包含在最终的打包文件里。-->
<resources>
<!--这个元素描述了项目相关或测试相关的所有资源路径-->
<resource>
<!-- 描述了资源的目标路径。该路径相对target/classes目录(例如${project.build.outputDirectory})。举个例 子,如果你想资源在特定的包里( org.apache.maven.message,你就必须该元素设置为org/apache/maven /messages。然而,如果你只是想把资源放到源码目录结构里,就不需要该配置。-->
<targetPath/>
<!--是否使用参数值代替参数名。参数值取自properties元素或者文件里配置的属性,文件在filters元素里列出。-->
<filtering/>
<!--描述存放资源的目录,该路径相对POM路径-->
<directory/>
<!--包含的模式列表,例如**/*.xml.-->
<includes/>
<!--排除的模式列表,例如**/*.xml-->
<excludes/>
</resource>
</resources>
<!--这个元素描述了单元测试相关的所有资源路径,例如和单元测试相关的属性文件。-->
<testResources>
<!--这个元素描述了测试相关的所有资源路径,参见build/resources/resource元素的说明-->
<testResource>
<targetPath/>
<filtering/>
<directory/>
<includes/>
<excludes/>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<tagBase>${git.conn}</tagBase>
<branchBase>${git.conn}</branchBase>
<username>${git.username}</username>
<password>${git.password}</password>
</configuration>
</plugin>
...
</plugins>
<!--子项目可以引用的默认插件信息。该插件配置项直到被引用时才会被解析或绑定到生命周期。给定插件的任何本地配置都会覆盖这里的配置-->
<pluginManagement>
<plugins>
...
</plugins>
</pluginManagement>
</build>
</project>
package tree
import (
"container/list"
"strconv"
"strings"
)
type node struct {
left, right *node
Value int
}
type BiTree struct {
root *node
len int
}
func NewBiTree() *BiTree {
return &BiTree{}
}
func (t *BiTree) Add(v int) {
n := t.root
if n == nil {
t.root = &node{Value: v}
t.len++
return
}
for {
switch {
case v < n.Value:
if n.left == nil {
new := &node{Value: v}
n.left = new
t.len++
return
}
n = n.left
default:
if n.right == nil {
new := &node{Value: v}
n.right = new
t.len++
return
}
n = n.right
}
}
}
func (t *BiTree) Delete(v int) *node {
p, n := find(t.root, v)
switch {
case n == nil:
return nil
case n.left == nil || n.right == nil:
a := If(n.left == nil, n.right, n.left)
replace(p, n, a)
return n
default:
maxP, max := findMax(n.left)
replace(maxP, max, nil)
if n != t.root {
replace(p, n, max)
} else {
t.root = max
}
if n.left != max {
max.left = n.left
}
max.right = n.right
return n
}
}
func replace(p, a, b *node) {
switch {
case p == nil:
return
case p.left == a:
p.left = b
default:
p.right = b
}
}
func If(condition bool, v1, v2 *node) *node {
if condition {
return v1
}
return v2
}
func findMax(root *node) (p, n *node) {
n = root
for {
switch {
case n == nil:
return nil, nil
case n.right == nil:
return p, n
default:
p = n
n = n.right
}
}
}
func find(root *node, v int) (p, n *node) {
n = root
for {
switch {
case n == nil:
return nil, nil
case v == n.Value:
return p, n
case v < n.Value:
p = n
n = n.left
continue
default:
p = n
n = n.right
continue
}
}
}
func (t *BiTree) Search(v int) *node {
_, n := find(t.root, v)
return n
}
func (t *BiTree) Print(a int) string {
if t.root == nil {
return ""
}
data := make([]string, 0, t.len)
s := &stack{list.New()}
switch a {
case 10:
n := t.root
m := make(map[*node]bool)
s.push(t.root)
for !s.empty() {
n = s.pop()
if n == nil {
continue
}
if m[n] { //由于每个节点都会入栈两次,第一次标记,第二次打印值
data = append(data, strconv.Itoa(n.Value))
} else {
s.push(n.right)
s.push(n.left)
s.push(n)
m[n] = true
}
}
case 20:
n := t.root
m := make(map[*node]bool)
s.push(t.root)
for !s.empty() {
n = s.pop()
if n == nil {
continue
}
if m[n] {
data = append(data, strconv.Itoa(n.Value))
} else {
s.push(n.right)
s.push(n)
s.push(n.left)
m[n] = true
}
}
case 30:
n := t.root
m := make(map[*node]bool)
s.push(t.root)
for !s.empty() {
n = s.pop()
if n == nil {
continue
}
if m[n] {
data = append(data, strconv.Itoa(n.Value))
} else {
s.push(n)
s.push(n.right)
s.push(n.left)
m[n] = true
}
}
case 11:
//先序遍历方案1:
//对每个节点压入栈,打印值,同样处理左孩子;
//到达左下角后,栈弹出节点处理右孩子
n := t.root
for !s.empty() || n != nil { //如果栈为空并且节点为空,代表没有节点能够处理
if n != nil { //节点不为空的话处理左孩子
data = append(data, strconv.Itoa(n.Value))
s.push(n)
n = n.left
} else { //节点为空的话 弹出栈顶节点,处理其右孩子
n = s.pop().right
}
}
case 12:
//先序遍历方案2:
//按照栈先入后出结构,对每个节点打印值,先压入右孩子,再压入左孩子
//栈弹出各个节点依次处理
n := t.root
s.push(t.root)
for !s.empty() {
n = s.pop()
data = append(data, strconv.Itoa(n.Value))
if n.right != nil {
s.push(n.right)
}
if n.left != nil {
s.push(n.left)
}
}
case 21:
//中序遍历方案1:
//对每个节点压入栈,同样处理左孩子;
//到达左下角后,栈弹出节点,打印值,处理右孩子
n := t.root
for !s.empty() || n != nil {
if n != nil {
s.push(n)
n = n.left
} else {
n = s.pop()
data = append(data, strconv.Itoa(n.Value))
n = n.right
}
}
case 31:
//后序遍历方案1:
// 左右根 翻转是 根右左
//按照栈先入后出结构,对每个节点打印值,先压入左孩子,再压入右孩子
//栈弹出各个节点依次处理
//最后翻转
n := t.root
s.push(t.root)
for !s.empty() {
n = s.pop()
data = append(data, strconv.Itoa(n.Value))
if n.left != nil {
s.push(n.left)
}
if n.right != nil {
s.push(n.right)
}
}
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
data[i], data[j] = data[j], data[i]
}
case 4:
n := t.root
s.push(t.root)
q := &queue{list.New()}
q.put(t.root)
for !q.empty() {
n = q.poll()
if n == nil {
continue
}
data = append(data, strconv.Itoa(n.Value))
q.put(n.left)
q.put(n.right)
}
}
return strings.Join(data, ",")
}
type stack struct {
list *list.List
}
func (s *stack) push(v *node) {
s.list.PushBack(v)
}
func (s *stack) empty() bool {
return s.list.Len() == 0
}
func (s *stack) pop() *node {
e := s.list.Back()
if e != nil {
s.list.Remove(e)
return e.Value.(*node)
}
return nil
}
type queue struct {
list *list.List
}
func (s *queue) put(v *node) {
s.list.PushBack(v)
}
func (s *queue) empty() bool {
return s.list.Len() == 0
}
func (s *queue) poll() *node {
e := s.list.Front()
if e != nil {
s.list.Remove(e)
return e.Value.(*node)
}
return nil
}
()
改变运算符优先级结构
利用栈结构和后缀表达式来计算数学表达式
行为
通过后缀表达式计算:遇到数字压栈,遇到运算符弹出栈顶两个数字计算
生成后缀表达式:栈存运算符
遇到数字输出,
遇到运算符,栈顶的优先级更低则入栈,更高或相等则输出
遇到运算符,栈顶为(
直接入栈
运算符为)
则全部弹出,直到遇到(
最后弹出所有栈内运算符
边界条件
package main
import (
"container/list"
"fmt"
"strconv"
"unicode"
)
func main() {
fmt.Println(cacl("1+22*3"))
}
func cacl(expr string) int {
stack := &stack{list.New()}
expr = in2post(expr)
for i := 0; i < len(expr); i++ {
s := string(expr[i])
// 数字:直接压栈
if unicode.IsDigit(rune(expr[i])) {
j := i
num := ""
for ; j < len(expr) && unicode.IsDigit(rune(expr[j])); j++ { //获取整个数字
num += string(expr[j])
}
stack.push(num)
i = j //数字后都会跟有逗号,则跳过j-1
} else {
// 操作符:取出两个数字计算值,再将结果压栈
num1, _ := strconv.Atoi(stack.pop())
num2, _ := strconv.Atoi(stack.pop())
switch s {
case "+":
stack.push(strconv.Itoa(num1 + num2))
case "-":
stack.push(strconv.Itoa(num1 - num2))
case "*":
stack.push(strconv.Itoa(num1 * num2))
case "/":
stack.push(strconv.Itoa(num1 / num2))
}
}
}
result, _ := strconv.Atoi(stack.top())
return result
}
func in2post(expr string) (str string) {
stack := stack{list.New()}
for i := 0; i < len(expr); i++ {
s := string(expr[i])
switch s {
case " ":
case "(": //直接入栈
stack.push(s)
case ")": //弹出所有运算符,直至(
for !stack.empty() {
s = stack.pop()
if s == "(" {
break
}
str += s
}
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9": //数字直接输出
j := i
num := ""
for ; j < len(expr) && unicode.IsDigit(rune(expr[j])); j++ { //获取整个数字
num += string(expr[j])
}
str = str + num + ","
i = j - 1
default: //运算符:遇到更高级别运算符则弹出
for !stack.empty() {
top := stack.top()
if top == "(" || isLower(top, s) {
break
}
str += top
stack.pop()
}
// 低优先级的运算符入栈
stack.push(s)
}
}
// 栈不空则全部输出
for !stack.empty() {
str += stack.pop()
}
return str
}
func isLower(top string, newTop string) bool {
// 注意 a + b + c 的后缀表达式是 ab + c +,不是 abc + +
switch top {
case "+", "-":
if newTop == "*" || newTop == "/" {
return true
}
case "(":
return true
}
return false
}
type stack struct {
list *list.List
}
func (s *stack) push(v string) {
s.list.PushBack(v)
}
func (s *stack) empty() bool {
return s.list.Len() == 0
}
func (s *stack) top() string {
return s.list.Back().Value.(string)
}
func (s *stack) pop() string {
e := s.list.Back()
if e != nil {
s.list.Remove(e)
return e.Value.(string)
}
return ""
}
package list
import (
"container/list"
"fmt"
"strings"
)
type Queue struct {
list *list.List
}
func NewQueue() *Queue {
list := list.New()
return &Queue{list}
}
func (q *Queue) Put(v interface{}) {
q.list.PushBack(v)
}
func (q *Queue) Poll() interface{} {
e := q.list.Front()
if e != nil {
q.list.Remove(e)
return e.Value
}
return nil
}
func (q *Queue) Len() int {
return q.list.Len()
}
func (q *Queue) String() (str string) {
data := make([]string, 0, q.Len())
for e := q.list.Front(); e != nil; e = e.Next() {
data = append(data, fmt.Sprintf("%v", e.Value))
}
str = strings.Join(data, ",")
str = "[" + str + "]"
return
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.