30/09/2018, 16:41

Thuật toán tính biểu thức ko cần dùng Stack

Mình đã thành công khi ko cần thuật toán ký pháp BaLan để làm được bài này. Hjx mừng quá xá lun. Chắc người tiên phong làm bài dạng này mà ko cần dùng STACK

Thuật toán:
B1:Tối ưu biểu thức bằng cách bỏ đi khoảng trắng dư thừa
B2: Xác định 2 vị trí start là dấu ngoặc đơn mở cuối cùng và vị trí end là dấu ngoặc đơn đóng đầu tiên trong chuỗi tính từ trái qua.
B3: Thực hiện tính trong đoạn giữa từ start đến end.
B4: Xóa các ký tự trong đoạn từ start đến end.
B5: Chèn kết quả tính được từ B3 vào vị trí start sau khi xóa.
B6. Lặp lại bước 2 cho đến khi chuỗi không còn ngoặc đơn nào

#include <iostream>
#include <string>
using namespace std;

int Vtngoacmocuoi(char* s)
{
	int len = strlen(s);
	for(int i = len - 1; i >= 0; i--)
	{
		if(s[i] == '(')
			return i;
	}
}

int Vtngoacdongdau(char *s)
{
	int len = strlen(s);
	for(int i = Vtngoacmocuoi(s); i < len; i++)
	{
		if(s[i] == ')')
			return i;
	}
}
void XoaKyTu(char *s, int vt)
{
	int len = strlen(s);
	int i;
	for(i = vt; i < len- 1 ; i++)
	{
		s[i] = s[i+1];
	}
	s[len - 1] = NULL;
}

void XoaKhoangTrangThua(char *s, int vtbatdau, int vtketthuc)
{
	for(int i = vtbatdau; i < vtketthuc - 1; i++)
	{
		if(s[i] == ' ' && s[i+1] == ' ')
		{
			XoaKyTu(s,i);
			i--;
		}
	}
	if(s[vtbatdau] == ' ')
		XoaKyTu(s, vtbatdau);
	if(s[vtketthuc-1] == ' ')
		XoaKyTu(s, vtketthuc-1 -1);
}
int tinhdoan(char *s,int vtbatdau, int vtketthuc)
{
	XoaKhoangTrangThua(s, vtbatdau,vtketthuc);
	int num1 = 0,num2 = 0, i = vtbatdau + 1;
	bool checkam1 = false, checkam2 = false;
	if(s[i] == '-')
	{
		checkam1 = true;
		i++;
	}
	while(s[i] >= '0' && s[i] <= '9')
	{
		num1 = num1 * 10 + (s[i] - 48);
		i++;
	}
	if(checkam1 == true)
	num1 *= -1;
	if(s[i+1] == '+')
	{
		int j = i + 3;
		if(s[j] == '-')
		{
			checkam2 = true; 
			j++;
		}
		while(s[j] >= '0' && s[j] <= '9') 
		{
			num2 = num2 * 10 + (s[j] - 48);
			j++;
		}
		if(checkam2 == true)
			num2 *= -1;
		return (num1 + num2);
	}
	if(s[i+1] == '-')
	{
		int j = i + 3;
		if(s[j] == '-')
		{
			checkam2 = true; 
			j++;
		}
		while(s[j] >= '0' && s[j] <= '9') 
		{
			num2 = num2 * 10 + (s[j] - 48);
			j++;
		}
		if(checkam2 == true)
			num2 *= -1;
		return (num1 - num2);
	}
		if(s[i+1] == '*')
	{
		int j = i + 3;
		if(s[j] == '-')
		{
			checkam2 = true; 
			j++;
		}
		while(s[j] >= '0' && s[j] <= '9') 
		{
			num2 = num2 * 10 + (s[j] - 48);
			j++;
		}
		if(checkam2 == true)
			num2 *= -1;
		return (num1 * num2);
	}
		if(s[i+1] == '/')
	{
		int j = i + 3;
		if(s[j] == '-')
		{
			checkam2 = true; 
			j++;
		}
		while(s[j] >= '0' && s[j] <= '9') 
		{
			num2 = num2 * 10 + (s[j] - 48);
			j++;
		}
		if(checkam2 == true)
			num2 *= -1;
		return (num1 / num2);
	}
}
void ChenKyTu(char *s, char kytuchen, int vtchen)
{
	int len = strlen(s);
	for(int i = len; i > vtchen; i--)
	{
		s[i] = s[i-1];
	}
	s[vtchen] = kytuchen;
	s[len + 1] = NULL;
}
bool KiemtracoNgoac(char *s)
{
	for(int i = 0; i < strlen(s); i++)
	{
		if(s[i] == '(' || s[i] == ')')
			return true;
	}
	return false;
}
bool KiemTraKhoangTrang(char *s)
{
	for(int i = 0; i < strlen(s); i++)
	{
		if(s[i] == ' ')
			return true;
	}
	return false;
}
int TinhBieuThuc(char *&s)
{
	int vtbatdau = Vtngoacmocuoi(s);
	int vtketthuc = Vtngoacdongdau(s);
		if(KiemtracoNgoac(s)==false && KiemTraKhoangTrang(s) == true)
	{
		ChenKyTu(s,'(',0);
		ChenKyTu(s,')',strlen(s));
		vtbatdau = Vtngoacmocuoi(s);
		vtketthuc = Vtngoacdongdau(s);
	}
	int c = tinhdoan(s, vtbatdau, vtketthuc);
	char *a = new char[50];
	itoa(c,a,10);
	int lena = strlen(a);

	if(KiemtracoNgoac(s)==false )
		return  atoi(s);
	for(int j = 0; j < vtketthuc - vtbatdau + 1; j++)
	{
		XoaKyTu(s,vtbatdau);
	}
	
	for(int i = 0; i < lena; i++)
	{
		ChenKyTu(s,a[i],vtbatdau);
		vtbatdau++;
	}
	TinhBieuThuc(s);
}
void main()
{
	char *bieuthuc = new char[50];
	cout<<"Nhap bieu thuc:
";
	fflush(stdin);
	gets(bieuthuc);
	cout<<endl<<"Ket qua bieu thuc la "<<TinhBieuThuc(bieuthuc);
	system("pause");
}
lê tuấn anh viết 18:54 ngày 30/09/2018

like cho bạn, nhưng có rất nhiều vấn đề trong code này. Đây là mình thử test:

Có vẻ như cách xử lý xâu và cách thực hiện trong code ko ổn !!

Tuấn Nguyễn viết 18:57 ngày 30/09/2018

Bạn nhập biểu thức ngăn cách khoảng trắng và thêm dấu mở ngoặc, đóng ngoặc cho phù hợp là được. Vì nó ko tự xác định * / trước bạn tự chủ động thêm nhé !

lê tuấn anh viết 18:49 ngày 30/09/2018

cách c giải bài này phải nhóm tất cả vào trong ngoặc, nếu vậy thì cần gì dài dòng nhỉ ? Chỉ cần xác định dấu hiện có dấu ‘(’ và ‘)’ rồi từ xâu chuyển thành phép toán mà ko cần quan tâm mức độ ưu tiên các phép toán. Như vậy c chỉ làm được nếu c đã nhóm đc thôi, khi có yêu cầu giải bài toán mà nói là: Hãy nhóm hết lại cho tôi, tôi sẽ tính toán cho. Có vẻ ko hay lắm !

Tuấn Nguyễn viết 18:53 ngày 30/09/2018

Tôi đố bạn dùng cách gì để giải được phép toán kiểu zậy. Máy tính nó ko thông minh được vậy đâu bạn à.Tôi không biết bạn có làm dạng ký pháp bao giờ chưa mà phát biểu zậy?

Bạn nghĩ có thể giải được phép 1 + 15 - 30 * 5 / 3 + 3 kiểu vậy hả?

Tuấn Nguyễn viết 18:47 ngày 30/09/2018

Bạn ko hiểu rằng nhóm như thế nào à? Ko phải nhóm tất cả mà chỉ nhóm khi có 3 toán hạng trong 1 biểu thức.
Kiểu như thế này

lê tuấn anh viết 18:54 ngày 30/09/2018

Bạn nghĩ có thể giải được phép 1 + 15 - 30 * 5 / 3 + 3 kiểu vậy hả?

Có gì hot, thuật toán chuyển trung tố , hậu tố xác định mức độ ưu tiên của các toán tử.
Bạn có tin t làm đc ko ?
chuyển từ trung tố sang hậu tố, rồi từ hậu tố tính kq.
Có thể dùng Stack và danh sách liên kết để tính.
Có thể bonus cho khi các toán hạng là số thập phân.
// ko biết bạn đã tìm hiểu các nguồn hướng dẫn thuật toán của kí pháp balan chưa mà phát biểu như vậy ?

lê tuấn anh viết 18:52 ngày 30/09/2018

Bonus cho cái link mà ngẫm:

http://scriptasylum.com/tutorials/infix_postfix/infix_postfix.html
Loc Le Thai viết 18:43 ngày 30/09/2018

mình từng làm cái máy tính mà không sử dụng Stack.Mình làm được hâu hết các phép tính + - x / () ^ sqrt có điều ^ khi kết hợp với () thì mình không có cách nào làm được.Các bạn có cách nào thì xin chỉ giáo.

lê tuấn anh viết 18:45 ngày 30/09/2018

^ là một toán tử có mức ưu tiên cao hơn nhân, chia. Vậy nếu bạn tính đc nhân và chia có () sao lại ko tính đc cái này.

Nguyễn Bá Cường viết 18:50 ngày 30/09/2018

Tớ thấy ý tưởng của bạn cũng hay nhưng mà có nhiều vấn đề cần xử lý và có thể là không triệt để như các bạn comment trước. Ngoài ra, còn một vấn đề về độ phức tạp thuật toán, nếu làm theo Balan để chuyển từ trung tố sang hậu tố thì chỉ là O(n) nhưng với thuật toán của bạn phải mất tới O(n^2) vậy là tốc độ chậm đi rất nhiều rồi , hi vọng bạn có thể cải tiến và biết đâu ra đuợc một thuật toán hay hơn

Bài liên quan
0