@@ -77,30 +77,86 @@ export function onlyFunctions(
77
77
// ---
78
78
79
79
export function findLinearPaths ( graph : Map < TypedNode , Set < TypedNode > > ) {
80
- const linearPaths = [ ] ;
81
-
82
- const visitedNodes = new Set ( ) ;
80
+ const linearPaths = [ ] as TypedNode [ ] [ ] ;
81
+ const visitedNodes = new Set < TypedNode > ( ) ;
82
+ const nodeInDegrees = new Map < TypedNode , number > ( ) ;
83
83
84
+ // 计算每个节点的入度
84
85
for ( const [ node , edges ] of graph . entries ( ) ) {
85
- if ( edges . size === 1 && ! visitedNodes . has ( node ) ) {
86
- const path = [ node ] ;
87
- let nextNode = Array . from ( edges ) [ 0 ] ;
86
+ for ( const edge of edges ) {
87
+ const inDegree = nodeInDegrees . get ( edge ) || 0 ;
88
+ nodeInDegrees . set ( edge , inDegree + 1 ) ;
89
+ }
90
+ }
91
+
92
+ function dfs ( node : TypedNode , path : TypedNode [ ] ) {
93
+ if ( visitedNodes . has ( node ) ) {
94
+ return ;
95
+ }
96
+
97
+ path . push ( node ) ;
98
+ visitedNodes . add ( node ) ;
88
99
89
- visitedNodes . add ( node ) ;
100
+ const edges = graph . get ( node ) || new Set ( ) ;
101
+
102
+ if ( edges . size === 0 || edges . size > 1 ) {
103
+ if ( path . length > 1 ) {
104
+ addOrUpdatePath ( [ ...path ] ) ;
105
+ }
106
+ }
107
+ else {
108
+ const nextNode = Array . from ( edges ) [ 0 ] ;
109
+ const nextNodeInDegree = nodeInDegrees . get ( nextNode ) || 0 ;
110
+
111
+ // 确保下一个节点只有一个入度
112
+ if ( nextNodeInDegree === 1 ) {
113
+ dfs ( nextNode , path ) ;
114
+ }
115
+ }
116
+
117
+ path . pop ( ) ;
118
+ visitedNodes . delete ( node ) ;
119
+ }
90
120
91
- while ( graph . get ( nextNode ) ?. size === 1 ) {
92
- if ( visitedNodes . has ( nextNode ) ) {
121
+ function addOrUpdatePath ( newPath : TypedNode [ ] ) {
122
+ let shouldAddNewPath = true ;
123
+
124
+ for ( let i = linearPaths . length - 1 ; i >= 0 ; i -- ) {
125
+ const existingPath = linearPaths [ i ] ;
126
+ if ( isSubpath ( existingPath , newPath ) ) {
127
+ linearPaths . splice ( i , 1 ) ; // remove the shorter path
128
+ }
129
+ else if ( isSubpath ( newPath , existingPath ) ) {
130
+ shouldAddNewPath = false ;
131
+ break ;
132
+ }
133
+ }
134
+
135
+ if ( shouldAddNewPath && newPath . length > 2 ) {
136
+ linearPaths . push ( newPath ) ;
137
+ }
138
+ }
139
+
140
+ function isSubpath ( shortPath : TypedNode [ ] , longPath : TypedNode [ ] ) {
141
+ if ( shortPath . length >= longPath . length ) { return false ; }
142
+
143
+ for ( let i = 0 ; i <= longPath . length - shortPath . length ; i ++ ) {
144
+ let isSub = true ;
145
+ for ( let j = 0 ; j < shortPath . length ; j ++ ) {
146
+ if ( shortPath [ j ] !== longPath [ i + j ] ) {
147
+ isSub = false ;
93
148
break ;
94
149
}
95
- path . push ( nextNode ) ;
96
- visitedNodes . add ( nextNode ) ;
97
- nextNode = Array . from ( graph . get ( nextNode ) ! ) [ 0 ] ;
98
150
}
99
-
100
- if ( path . length > 1 ) {
101
- linearPaths . push ( path ) ;
151
+ if ( isSub ) {
152
+ return true ;
102
153
}
103
154
}
155
+ return false ;
156
+ }
157
+
158
+ for ( const node of graph . keys ( ) ) {
159
+ dfs ( node , [ ] ) ;
104
160
}
105
161
106
162
return linearPaths ;
0 commit comments