Stack Queue 자료구조 너무 간단하다.
Stack
- LIFO(Last In First Out) 구조, 마지막에 저장된 것을 제일 먼저 꺼냅니다.
Stack 메서드
- push
Stack에 객체를 저장합니다.
- pop
Stack의 맨 위에 저장된 객체를 꺼냅니다.
- peek
Stack의 맨 위에 저장된 객체를 반환합니다. Stack에서 꺼내지는 않습니다. 비었을 때 null을 반환합니다.
- empty
Stack이 비어있는지 알려줍니다. 있으면 true, 없으면 false를 반환합니다.
- search
Stack에서 주어진 객체를 찾아서 그 위치를 반환합니다. (배열과는 달리 1부터 시작합니다.)
<aside> 💡 쉽게 말하면 Array의 종류 중 하나일뿐이고, 단순히 누가 먼저 출력이 되냐 차이!!!!
</aside>
근데 스택은 요즘은 거의 안쓴다고 합니다!….
그 이유는 바로 백터에 있다고 합니다. 백터로 스택자료구조를 구현을 했으니 당연히
백터에서 사용할 수 있는 모든 기능을 스택 또한 사용할 수 있게 되는데요.
그렇다면…스택은 꼭대기가 아닌 맨아래에 있는 원소를 참조할 수도 있고, 중간에 있는 값도 참조할수 있습니다…..과연 이게 Stack 자료구조라고 할 수 있을까요?…
또 Vector에서는 모든 메소드드가 싱크로나이즈 키워드가 붙어 있어서 특정 상황에서 성능을 꽤 저하시킬수도 있다고합니다. 그래서 비슷한 자료구조인 LinkedList를 사용한다고 하네요…
그 말은 즉슨 Stack 역시 Vactor의 모든 장단점을 물려받은 아이기 때문에 위와 같은 치명적인 단점들이 많이 존재한다는 소리죠.
그래서 일방적으로 deque 자료구조를 많이 쓴다고 합니다…..이 점을 참고해서
다음에는 Deque 자료구조를 한번 알아보도록 하겠습니다.
(아직 쓰는 사람이 남아 있기에 Deprecated가 안된 스택과 벡터…..ㅋ)
Queue
- FIFO(First In First Out) 구조, 제일 먼저 저장한 것을 제일 먼저 꺼냅니다.
Queue 메서드
- add
Queue에 객체를 저장합니다.
성공하면 true, 실패하면 false를 반환합니다.
- element
삭제없이 저장된 요소를 읽어옵니다. peek와 다른 점은 queue가 비었을 때 Exception을 발생시킵니다. (peek()는 null을 반환합니다.)
- offer
Queue에 객체를 저장합니다. 성공하면 true, 실패하면 false를 반환합니다.
- peek
삭제없이 읽어옵니다. Queue가 비었을 때 null을 반환합니다.
- poll
Queue에서 꺼내옵니다. 비어있으면 null을 반환합니다.
- remove
Queue에서 꺼내옵니다. 비어있으면 예외를 발생시킵니다.
스택은 Stack 클래스로 구현하여 제공하고 있지만, 큐는 Queue 인터페이스로만 정의해 놓았을 뿐 별도의 클래스를 제공하고 있지 않습니다. 대신 Queue 인터페이스를 구현한 클래스들이 있어서 이 들 중의 하나를 선택해서 사용하면 됩니다.
번외 ) 수업시간에 배열로 만들어본 stack 메소드
package sw.search;
import java.util.EmptyStackException;
import java.util.Scanner;
// 스텍 메모리
// 스택은 임시로 데이터를 저장하는 기능을 가지고
// 나중에 입력된 데이터가 제일 먼저 출력한다. LIFO
// 출력이 된 데이터는 출력후 제거.
public class IntStack {
//배열의 용량.
private int capacity;
//데이터를 담을 배열
private int[] stk;
//스택의 포인터 (맴버변수는 초기화를 안해줘도 기본 Default값이 있다)
private int ptr; // <=> 인덱스 번호.
public IntStack(int capacity) {
this.stk = new int[capacity];
this.capacity = capacity;
ptr=0;
}
public int push(int data) throws OverfzlowIntStackException{ //예외 처리
//데이터가 공간크기보다 더 들어온다면 => 오버플로우.
if(this.capacity==this.ptr) {
throw new OverfzlowIntStackException(); // 예외발생
}
//ptr위치에 data를 담고 ptr은 1증가시킨다.
return stk[ptr++]=data;
}
public int pop() throws EmptyIntStackException{
if(ptr==0) {
throw new EmptyIntStackException();
}
return stk[--ptr];
}
public int peek() throws EmptyStackException{
if(ptr==0) {
throw new EmptyStackException();
}
return stk[ptr-1];
}
public void dump() throws EmptyStackException{
if(ptr==0) {
throw new EmptyStackException();
}
for(int i=0; i<ptr; i++) {
System.out.print(stk[i]+" ");
}
}
public void search() {
Scanner sc = new Scanner(System.in);
System.out.print("찾고자 하는 값을 입력하세요 : ");
int value=sc.nextInt();
for(int i=ptr-1; i>=0; i--) {
if(stk[i]==value) {
System.out.println("찾으신 값이 Index:"+i+" 에 있습니다 !");
System.out.println();
break;
}
System.out.println("찾으시는 값은 없습니다...");
System.out.println();
}
}
public void empty() {
ptr=0;
System.out.println("전체 삭제 되었습니다.");
}
public void info() {
System.out.println();
System.out.println("전체 저장 공간: "+(stk.length));
System.out.println("남은 저장 공간: "+(stk.length-ptr));
System.out.println("사용한 데이터 갯수: "+ ptr);
System.out.print("저장되 있는 데이터 정보: ");
try {
dump();
}catch(EmptyStackException e) {
System.out.println("스택이 비어있습니다.");
}
exit();
System.out.println();
}
public void exit() throws EmptyStackException{
if(ptr==0) {
System.out.println("저장공간이 비어있습니다 ㅠ");
}
for(int i=0; i<ptr; i++) {
System.out.println("값이 존재 합니다.");
break;
}
}
//내부클래스로 예외 처리 만들기.
//오버플로우 발생시 처리할 예외내부클래스 생성.
@SuppressWarnings("serial")
public class OverfzlowIntStackException extends RuntimeException {
public OverfzlowIntStackException() {
}
}
@SuppressWarnings("serial")
public class EmptyIntStackException extends RuntimeException{
public EmptyIntStackException() {
}
}
}
package sw.search;
import java.util.EmptyStackException;
import java.util.Scanner;
public class InStackMain {
public static Scanner sc = new Scanner(System.in);
public static void startStack() {
//스택 객체를 생성, 스택의 크기를 설정할수 있게 한다.
IntStack stack = new IntStack(100);
do {
// 메뉴 작성하기
System.out.print("1: Push 2: POP 3:PEEK 4:DUMP 5.SEARCH 6.EMPTY 7: Stack Information 0: -종료-");
int menu = sc.nextInt();
if(menu==0) break;
switch(menu) {
case 1:
// 스택에 데이터 담기. push
System.out.print("데이터 : ");
int data = sc.nextInt();
stack.push(data);
try {
}catch(IntStack.OverfzlowIntStackException e) {
System.out.println("Stack Memory full...");
}
break;
case 2:
// 스택에서 데이터 꺼내기 .pop (제일마지막에 입력된것부터 차례대로)
try {
int popData = stack.pop();
System.out.println(popData);
}catch(IntStack.EmptyIntStackException e) {
System.out.println("스택이 비어있습니다.");
}
break;
case 3:
// 스택 제일 위에 존재하는 값 호출 마지막에 저장된 값.
try {
int peek=stack.peek();
System.out.println("마지막에 담긴 데이터: "+peek);
}catch(EmptyStackException e) {
System.out.println("스택이 비어있습니다.");
}
break;
case 4:
try {
stack.dump();
System.out.println();
}catch(EmptyStackException e){
System.out.println("스택이 비어있어용;");
}
break;
// 솔직히 이렇게 왔다갔다하면서 짜면 그게 더 머리가 아프고 여기봤다 저기봤다 해야되서
// 유지보수 측면에서 관리하기가 서브클래스와 메인클래스를 왔다갔다 하면서 계속 찾아봐야해서 이렇게 짜는건 정말 아니지 싶습니다
// 헷갈리기만하고....아니면 제가 이렇게 짰을때의 장점을 못느낀거일 수도...
//그래서 여기서부터는 수업과 다르게 그냥 제 맘대로 짜기 시작했습니다. 물론 결과는 똑같습니다!
case 5:
stack.search(); // 찾는 데이터가 있는 index 번호 알려주기.
break;
case 6:
stack.empty(); // 스택 객체의 데이터 전부 삭제.
break;
case 7:
stack.info();
// 스텍 정보 표시
// 용량
// 데이터의수
// 스택의 데이터정보
// 스텍의 데이터 존재하는지 유무
break;
default:
// 메뉴 잘못선택.
System.out.println("메뉴를 잘못 입력하셨습니다.");
System.out.println("0~7사이의 값을 입력하세요!");
}
}while(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
startStack();
}
}
한가지 수업을 들으면서 코딩을 할때 의구심이 들었던 것인데,,,
어떻게 보면 stack자료구조를 만드는것인데, 실질적으로 가변형태는 아닌 배열을 선택해서 만들었고,,,, 여기서부터 stack 자료구조랑은 차이점이 존재하고…
무엇보다도 코딩을 하면서 클래스 2개를 사용하여 서브클래스, 메인클래스를 왔다갔다 하면서
코딩을 짰는데…하나의 메소드 내용을 양쪽에 데이터를 분산해서 작성했다.
이게 객체지향관점에서 보게되면 메인클래스는 서브클래스 객체를 생성해서
메소드만 실행하면. 내가 원하는 데이터들이 나오고 만약에 특정 사항을 수정해야 된다고 하면,
위에 코드에서는 서브클래스에 70%정도 작성된 stack 메소드를 수정해야하고 또 다시 메인클래스로가서 소소한것들 몇개 고쳐줘야 하고,,,,,
무엇보다도 이렇게 되면 객체지향 개념이 거의 아니지 않나 싶었던게
이렇게 되면 stack이라는 자료구조를 실현한 클래스는 1개가 아니라 2개가 된다….
심지어 상속관계를 사용하여 구현한 것도 아니고, 만약에 타 클래스에서 이 자료구조를 사용하고 싶다고하면 , 빈번하게 코드를 변경해야되고 하나의 상속이 필요할게 2개가 필요하게 되고,
유지보수를 위해 코드의 가독성이 좋아야 하는데 한 메서드의 실행코드가 서브클래스, 메인클래스 나눠져 있어서 합쳐야지 사용이 가능하게 코딩을 한것이 개인적으로는 좀 많이 불편했다……😟
하지만 난 코딩의 “코”자도 아직 모르니 개소리 일 수도 있다 😂
'Data Structure' 카테고리의 다른 글
BinarySearchTree 구현해보기 (0) | 2023.01.13 |
---|---|
Tree 구조 순회방식 구현해보기 (0) | 2023.01.13 |
Tree 구조는 뭘까요…🥲 (0) | 2023.01.13 |
빠르고 좋다는 Quick 정렬 원리와 구현 (2) | 2023.01.13 |