-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathInfixToPostfix.cs
More file actions
247 lines (207 loc) · 7.95 KB
/
InfixToPostfix.cs
File metadata and controls
247 lines (207 loc) · 7.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
using System;
using System.Diagnostics.CodeAnalysis;
namespace Algorithms.Stack
{
/// <summary>
/// The Code focuses on Converting an Infix Expression to a Postfix Expression and Evaluates the value for the expression.
/// @author Aalok Choudhari. <a href="https://github.com/kaloa2025">kaloa2025</a>
/// </summary>
public static class InfixToPostfix
{
/// <summary>
/// <param name="initialInfixExpression"> Infix Expression String to Convert.</param>
/// <returns>Postfix Expression.</returns>
/// <exception cref="ArgumentException">
/// Thrown when the input expression contains invalid characters or is null/empty.
/// Only following characters are allowed : Parentheses['(',')'], Operands[a-z,A-Z,0-9], Operators['+','-','*','/','^'].
/// </exception>
/// </summary>
public static string InfixToPostfixConversion(string initialInfixExpression)
{
ValidateInfix(initialInfixExpression);
Stack<char> stack = new Stack<char>();
StringBuilder postfixExpression = new StringBuilder();
foreach (char c in initialInfixExpression)
{
if (char.IsWhiteSpace(c))
{
continue;
}
if (!IsValidCharacter(c))
{
throw new ArgumentException($"Invalid character {c}.");
}
ProcessInfixCharacter(c, stack, postfixExpression);
}
EmptyRemainingStack(stack, postfixExpression);
return postfixExpression.ToString();
}
/// <summary>
/// <param name="postfixExpression"> Postfix Expression String to Evaluate.</param>
/// <returns>Postfix Expression's Calculated value.</returns>
/// <exception cref="ArgumentException">
/// Thrown when the input expression contains invalid characters or is null/empty.
/// </exception>
/// <exception cref="InvalidOperationException">
/// Validates expression to have sufficient operands for performing operation.
/// </exception>
/// </summary>
public static int PostfixExpressionEvaluation(string postfixExpression)
{
ValidatePostfix(postfixExpression);
Stack<int> stack = new Stack<int>();
foreach (char ch in postfixExpression)
{
if(char.IsWhiteSpace(ch))
{
continue;
}
if(char.IsDigit(ch))
{
stack.Push(ch - '0');
continue;
}
if (IsOperator(ch))
{
EvaluateOperator(stack, ch);
continue;
}
throw new InvalidOperationException($"Invalid character in expression: {ch}");
}
if (stack.Count != 1)
{
throw new InvalidOperationException("Invalid postfix expression: Leftover operands.");
}
return stack.Pop();
}
private static void ProcessInfixCharacter(char c, Stack<char> stack, StringBuilder postfixExpression)
{
if (IsOperand(c))
{
postfixExpression.Append(c);
return;
}
if (c == '(')
{
stack.Push(c);
return;
}
if (c == ')')
{
ProcessClosingParenthesis(stack, postfixExpression);
return;
}
ProcessOperator(c, stack, postfixExpression);
}
private static void ProcessClosingParenthesis(Stack<char> stack, StringBuilder postfixExpression)
{
while (stack.Count > 0 && stack.Peek() != '(')
{
postfixExpression.Append(stack.Pop());
}
if (stack.Count == 0)
{
throw new InvalidOperationException("Mismatched parentheses in expression.");
}
stack.Pop();
}
private static void ProcessOperator(char c, Stack<char> stack, StringBuilder postfixExpression)
{
while (stack.Count > 0 && stack.Peek() != '(' && Precedence(stack.Peek()) >= Precedence(c))
{
postfixExpression.Append(stack.Pop());
}
stack.Push(c);
}
private static void EmptyRemainingStack(Stack<char> stack, StringBuilder postfix)
{
while (stack.Count > 0)
{
if (stack.Peek() is '(' or ')')
{
throw new InvalidOperationException("Mismatched parentheses.");
}
postfix.Append(stack.Pop());
}
}
private static void EvaluateOperator(Stack<int> stack, char op)
{
if (stack.Count < 2)
{
throw new InvalidOperationException("Insufficient operands");
}
int b = stack.Pop();
int a = stack.Pop();
if (op == '/' && b == 0)
{
throw new DivideByZeroException("Cannot divide by zero");
}
int result = op switch
{
'+' => a + b,
'-' => a - b,
'*' => a * b,
'/' => a / b,
'^' => (int)Math.Pow(a, b),
_ => throw new InvalidOperationException($"Unknown operator {op}"),
};
stack.Push(result);
}
private static void ValidateInfix(string expr)
{
if (string.IsNullOrEmpty(expr) || string.IsNullOrWhiteSpace(expr))
{
throw new ArgumentException("Infix cannot be null or empty.");
}
}
private static void ValidatePostfix(string expr)
{
if (string.IsNullOrEmpty(expr) || string.IsNullOrWhiteSpace(expr))
{
throw new ArgumentException("Postfix cannot be null or empty.");
}
}
/// <summary>
/// Decided Operator Precedence.
/// <param name="operatorChar"> Operator character whose precedence is asked.</param>
/// <returns>Precedence rank of parameter operator character.</returns>
/// </summary>
[ExcludeFromCodeCoverage]
private static int Precedence(char operatorChar)
{
if (operatorChar == '^')
{
return 3;
}
if (operatorChar == '*' || operatorChar == '/')
{
return 2;
}
if (operatorChar == '+' || operatorChar == '-')
{
return 1;
}
return 0;
}
/// <summary>
/// Checks for character if its an Operand.
/// <param name="ch"> Character asked to verify whether its an operand.</param>
/// <returns>True if its a digit or a Letter.</returns>
/// </summary>
private static bool IsOperand(char ch) => char.IsLetterOrDigit(ch);
private static readonly HashSet<char> Operators = new() { '+', '-', '*', '/', '^' };
/// <summary>
/// Checks Operator.
/// <param name="ch"> Character asked to verify whether its an operator.</param>
/// <returns>True if its allowded operator character.</returns>
/// </summary>
private static bool IsOperator(char ch) => Operators.Contains(ch);
/// <summary>
/// Checks Valid Character.
/// <param name="c"> Character asked to verify whether its an valid Character for expression.</param>
/// <returns>True if its allowded character.</returns>
/// </summary>
private static bool IsValidCharacter(char c) => IsOperand(c) || IsOperator(c) || IsParenthesis(c);
private static bool IsParenthesis(char c) => c == '(' || c == ')';
}
}