본문 바로가기
Quality control (Univ. Study)/Data structure

자료구조론 과제(1)

by 생각하는 이상훈 2023. 2. 17.
728x90

 


Array Stack 과제

ArrayStack.h

#ifndef ARRAYSTACK_H
#define ARRAYSTACK_H

#include <iostream>


using namespace std;

class StackEmpty {
public:
    StackEmpty(const string& err) { }
};

class StackFull {
public:
    StackFull(const string& err) { }
};


template <typename E>
class ArrayStack {
    enum { DEF_CAPACITY = 100 };		// default stack capacity
public:
    ArrayStack(int cap = DEF_CAPACITY);		// constructor from capacity
    int size() const;				// number of items in the stack
    bool empty() const;				// is the stack empty?
    const E& top() const throw(StackEmpty);	// get the top element
    void push(const E& e) throw(StackFull);	// push element onto stack
    void pop() throw(StackEmpty);		// pop the stack
    // ...housekeeping functions omitted
private:                                	// member data
    E* S;					// array of stack elements
    int capacity;				// stack capacity
    int t;					// index of the top of the stack
};


template <typename E> ArrayStack<E>::ArrayStack(int cap)
    : S(new E[cap]), capacity(cap), t(-1) { }	// constructor from capacity

template <typename E> int ArrayStack<E>::size() const
{
    return (t + 1);
}				// number of items in the stack

template <typename E> bool ArrayStack<E>::empty() const
{
    return (t < 0);
}				// is the stack empty?

template <typename E>				// return top of stack
const E& ArrayStack<E>::top() const throw(StackEmpty) {
    if (empty()) throw StackEmpty("Top of empty stack");
    return S[t];
}


template <typename E>				// push element onto the stack
void ArrayStack<E>::push(const E& e) throw(StackFull) {
    if (size() == capacity) throw StackFull("Push to full stack");
    S[++t] = e;
}

template <typename E>				// pop the stack
void ArrayStack<E>::pop() throw(StackEmpty) {
    if (empty()) throw StackEmpty("Pop from empty stack");
    --t;
}


#endif

 

ArrayStack.cpp

#include <iostream>
#include "ArrayStack.h"

using namespace std;


int main(void)
{
	ArrayStack<int> mystack;

	cout << mystack.size() << endl;

	mystack.push(1);
	mystack.push(2);

	cout << mystack.top() << endl;
	mystack.pop();

	cout << mystack.top() << endl;
	cout << mystack.size() << endl;

	return 0;
}

괄호매칭

우선 1 소스코드는 괄호 매칭을 진행해보는 소스코드이다. 소스코드에서의 특징은 open bracket 계속 stack 넣어두고 close bracket stack top 매칭을 하여 같은 형식의 set 경우 top pop해주어 set 있는 bracket stack에서 제거 해주는 것이다. 만약 모든 bracket 제대로 matching되어 있어서 set 맞게 식에 존재한다면 stack 남아있는 open bracket 없을 것이다. 따라서 stack empty하면 bracket matching 제대로 되되어있는 것으로 판단할 있고 stack empty하지 않다면 bracket 제대로 matching되어있지 않다는 것으로 판단할 있다.

 

bracketmatching.cpp

#include <iostream>
#include "ArrayStack.h"
using namespace std;

//괄호 매칭함수
int bracketmatching(ArrayStack<char>& stack, string expression) {
	//범위기반 반복문
	for (const char& pair : expression) {
		//괄호 종류에 따라 분류
		switch (pair) {
		//open bracket의 경우
		case '(': case '{': case '[':
			stack.push(pair);	//stack에 문자를 입력
			break;	//반복문 종료

		//close bracket의 경우
		case ')': case '}': case ']':
			if (stack.empty()) {	//stack이 비어있으면
				cout << "false" << endl;	//false출력
				return 0;	//함수 종료
			}

			//stack이 비어있지 않다면
			char open_bracket = stack.top();	//open_bracket에 stack의 top을 입력
			stack.pop();		//해당 값은 pop
			if (open_bracket == '(' and pair != ')' or
				open_bracket == '{' and pair != '}' or
				open_bracket == '[' and pair != ']') {	//입력받은 close bracket과 stack에 있던 open bracket을 비교
				// (), {}, [] 세트가 아닌경우
				cout << "false" << endl;	//false출력
				return 0;	//함수 종료
			}
			break;	//반복문 종료
		}
	}
	//반복문 종료후
	if (!stack.empty()) {		//stack에 값이 남아있다면
		cout << "false" << endl;	//false출력
		return 0;
	}
	else {				//stack이 비어있다면
		cout << "true" << endl;		//true출력
		return 0;
	}
}

int main() {
	ArrayStack<char> bracket_stack;
	bracketmatching(bracket_stack, "(1+2)((3*4)){([( )])}");
	bracketmatching(bracket_stack, "((( )((1+2)){([(3+4 )])}");
	bracketmatching(bracket_stack, ")(( )){([(a+b )])}");
	bracketmatching(bracket_stack, "({[c/d])}");
	cout << endl << "이상훈 12211813" << endl;
	return 0;
}

Stock Span 알고리즘

2 소스코드는 stock span 코드로 배열의 크기를 integer 변수 n 담아두기 위해 vector STL 사용하였다. Array 크기를 구하는 sizeof()함수를 사용하지 못한 이유는 array 함수의 인자로 받아올 경우 array pointer 인식이 되기 때문에 sizeof(array) 하면 언제나pointer변수의 default size 8 출력된다. 다른 부분은 강의노트의 pseudo 코드를 기반으로 작성하였기에 특별한 내용은 없고 주석에서 모두 설명이 되어있다. 다만 마지막에 날짜의 span값을 반복문을 이용하여 배열의 원소를 출력하여야했다.

 

stock_span.cpp

#include <iostream>
#include <vector>		//vector STL
#include "ArrayStack.h"
using namespace std;

//span을 computing하는 linear-time algorithm 함수
int computeSpans(vector<int> p) {
	ArrayStack<int> d;		//빈 stack d 선언
	int n = p.size();		//integer n에 vector의 길이 대입
	int h = 0;				//계산용 인자 h를 0으로 초기화
	int S[100];				//각 날짜의 span 값을 입력해둘 중분한 크기의 integer array S선언

	//for문을 이용하여 벡터의 사이즈n만큼 반복
	for (int i = 0; i < n; i++) {		
		int done = 0;					//done 명령어를 0으로 초기화

	//stack이 비어있거나 done명령어가 1로 바뀌지 않은 경우
		while (!(d.empty() == true or done == 1)) { 
	//stack의 top보다 조사하는 값이 더 크거나 같으면 stack에서 pop진행
			if (p[d.top()] <= p[i])		
				d.pop();
	//stack의 top보다 조사하는 값이 작으면 done을 1로 바꿔줌
			else
				done = 1;
		}
	//stack이 비어있으면 h를 -1로 설정
		if (d.empty() == true)
			h = -1;
	//이외의 경우 h를 stack d의 top으로 설정
		else
			h = d.top();

		S[i] = i - h;		//array S에 i-h를 통해 구한 span값 입력
		d.push(i);			//i값을 stack d에 push
	}

	//array S출력
	for (int i = 0; i < n; i++) {
		cout<< "Span" << i << " = " << S[i] << endl;
	};
	return 0;
}

//다양한 stock market 상황을 생성해두고 stockspan함수를 실행하는 main문
int main() {
	//다양한 stock market 상황
	vector<int> stock_value1 = { 6, 4, 1, 2, 1, 3, 5 };	//강의노트에 주어진 상황
	vector<int> stock_value2 = { 3, 2, 3, 5, 7, 8, 8, 7, 5, 3 };	//random1
	vector<int> stock_value3 = { 11, 10, 8, 6, 3, 4, 5, 4, 6, 8, 10, 12, 14 };	//random2

	cout << "Stock Span1" << endl;
	computeSpans(stock_value1);
	cout << endl << endl << endl << "Stock Span2" << endl;
	computeSpans(stock_value2);
	cout << endl << endl << endl << "Stock Span3" << endl;
	computeSpans(stock_value3);
	cout << endl << "이상훈 12211813" << endl;
	return 0;
}

Postfix_transform

3 소스코드는 중위표기식을 후위 표기식으로 변환하는 postfix_transform함수에 관한 코드이다. 소스코드의 가장 특징은 문자들은 바로 array 입력하고 연산자들은 각각의 우선순위에 따라 stack 담거나 stack top pop해주고 stack 담아지는 경우로 나눠진다는 것이다. 이는 수업시간에 배운 내용과 강의노트의 내용을 기반으로 작성하였고 소스코드 내의 주석에서 line by line으로 상세하게 설명되어있다. 소스코드의 또다른 특징은 예외처리 입니다. Postfix_transform 함수 초반에 for문을 이용하여 음수가 존재하는 식인 경우 예외처리를 통해 error메세지가 출력되도록 하였다. 마지막 특징으로 연산자들의 유형이 존재했다. 1,2,3,4,5 식들은 +-*/ 같은 우리가 평소에 이용하는 연산자들로 구성되어있는 식들이고 6,7 식들은 && || ! 같은 논리 연산자들로 이루어져 있는 식들이었다. 그러나 유형 모두 연산자간의 우선순위만 제대로 설정을 해준다면 무리없이 코드를 완성할 있었다.

 

postfix_main.cpp

#include <iostream>
#include "ArrayStack.h"
using namespace std;

//후위표기식 변환 함수
string postfix_transform(ArrayStack<char>& oper_stack, string infix) {
	string ans;	//결과를 담아둘 ans 문자열 선언
	ArrayStack<char> checker_stack;
	//음수가 입력된 경우 error 처리
	for (const char& check : infix) {	//범위기반 반복문 사용
		if (check == '-') {				//음수일 가능성이 존재하는 -기호 조사
			if (checker_stack.empty()) {	//-가 문자열의 첫번째 문자인 경우 error 출력
				return "ERROR: can't control negative";
			}
			else if (checker_stack.top() == '-' or checker_stack.top() == '+' or
				checker_stack.top() == '*' or checker_stack.top() == '/') {
		//-가 연산자 바로 뒤에 출력되는 경우 즉 stack의 top이 연산자인 경우 error 출력
				return "ERROR: can't control negative";
			}
		}

		//-가 아닌 경우 stack에 계속 입력
		else {
			checker_stack.push(check);
		}
	}
	
	//범위기반 반복문 활용
	for (const char& oper : infix) {
	//char type의 oper를 상황에 따라 분류
		switch (oper) {	
		case '(':		//여는 괄호의 경우
			oper_stack.push('(');	//일단 stack에 넣음
			break;

		case ')':		//닫는 괄호
			while (!oper_stack.empty() and oper_stack.top() != '(') {
				//여는 괄호가 나올때까지 stack을 pop
				ans.push_back(oper_stack.top());	//문자열끝에 stack의 top을 입력
				oper_stack.pop();					//입력한 top은 pop해서 제거
			}
			oper_stack.pop();	//여는괄호는 stack에 넣지 않고 pop으로 제거
			break;
		
		//-------------------*,/,+,-류 연산(1,2,3,4,5번)에서 필요한 연산자)------------------
		case '*': case '/':		//우선순위가 높은 *과 /의 경우
			while (!oper_stack.empty() and (oper_stack.top() == '*' or oper_stack.top() == '/')) {
			//*, /을 만난 경우
				ans.push_back(oper_stack.top());	//ans문자열에 stack의 top을 입력
				oper_stack.pop();					//입력해준 top은 pop
			}
			oper_stack.push(oper);	//자신보다 낮는 우선순위의 연산자를 만나면 stack에 입력
			break;

		case '+': case '-':		//우선순위가 낮은 +와 -의 경우
			while (!oper_stack.empty() and oper_stack.top() != '(') {
			//top이 여는 괄호가 아닐경우
				ans.push_back(oper_stack.top());	//top을 문자열에 입력
				oper_stack.pop();		//그후 pop
			}
			oper_stack.push(oper);		//stack의 top에 여는 괄호가 있으면 연산자를 입력
			break;

			//----------------&&,//,!,<,>류 연산(6,7번)에서 필요한 연산자)-----------------
		case '!':
			while (!oper_stack.empty() and oper_stack.top() == '!') {
				//같은 !를 만난 경우
				ans.push_back(oper_stack.top());	//ans문자열에 stack의 top을 입력
				oper_stack.pop();					//입력해준 top은 pop
			}
			oper_stack.push(oper);	//자신보다 낮는 우선순위의 연산자를 만나면 stack에 입력
			break;

		case '&':		//우선순위가 높은 &&의 경우
			while (!oper_stack.empty() and oper_stack.top() == '!') {
				//자신보다 높은 우선순위의 연산자를 만난 경우
				ans.push_back(oper_stack.top());	//ans문자열에 stack의 top을 입력
				oper_stack.pop();					//입력해준 top은 pop
			}
			oper_stack.push(oper);	//자신보다 낮는 우선순위의 연산자 또는 자신을 만나면 stack에 입력
			break;

		case '|':		//우선순위가 낮은 ||의 경우
			while (!oper_stack.empty() and 
				(oper_stack.top() == '!' or oper_stack.top() == '&')) {
				//자신보다 높은 우선순위의 연산자를 만난 경우
				ans.push_back(oper_stack.top());	//ans문자열에 stack의 top을 입력
				oper_stack.pop();					//입력해준 top은 pop
			}
			oper_stack.push(oper);	//자신보다 낮는 우선순위의 연산자 또는 자신을 만나면 stack에 입력
			break;

		case '<': case '>':		//우선순위가 가장낮은 <와 >의 경우
			while (!oper_stack.empty() and oper_stack.top() != '(') {
				//top이 여는 괄호가 아닐경우
				ans.push_back(oper_stack.top());	//top을 문자열에 입력
				oper_stack.pop();		//그후 pop
			}
			oper_stack.push(oper);		//stack의 top에 여는 괄호가 있으면 연산자를 입력
			break;




		default:	//연산자가 아닌 경우
			ans.push_back(oper);	//문자들은 문자열에 바로 입력
		}
	}

	while (!oper_stack.empty()) {		//stack에 값이 존재하는 경우
		ans.push_back(oper_stack.top());	//문자열에 top을 입력하고
		oper_stack.pop();					//pop해줌
	}

	return ans;		//재구성한 식을 return해줌
}


int main() {
	ArrayStack<char> oper_stack;
	cout << postfix_transform(oper_stack, "A*B*C") << endl;
	cout << postfix_transform(oper_stack, "((A+(B*C))-(D/E))") << endl;
	cout << postfix_transform(oper_stack, "-A+B-C+D") << endl;
	cout << postfix_transform(oper_stack, "A*-B+C") << endl;
	cout << postfix_transform(oper_stack, "(A+B)*D+E/(F+A*D)+C") << endl;
	cout << postfix_transform(oper_stack, "A&&B||C||!(E>F)") << endl;
	cout << postfix_transform(oper_stack, "!(A&&!((B<C)||(C>D)))||(C<E)") << endl;
	cout << endl << "이상훈 12211813" << endl;
	return 0;
}

 

728x90

'Quality control (Univ. Study) > Data structure' 카테고리의 다른 글

ArrayStack(3)  (0) 2022.11.20
ArrayStack(2)  (0) 2022.11.19
ArrayStack(1)  (0) 2022.11.18
자료구조론(5)  (1) 2022.10.06
자료구조론(4)  (1) 2022.10.03