inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[인프런 워밍업클럽 CS 2기] 1주차 발자국

김형진
1

자료구조와 알고리즘

export class Node{
  constructor(data, next = null){
    this.data = data;
    this.next = next;
  }
}

// * 연결 리스트 추상 자료형
// 1. 모든 데이터 출력 -> printAll();
// 2. 모든 데이터 제거 -> clear();
// 3. 원하는 인덱스에 데이터를 삽입 -> insertAt(index, data);
// 4. 마지막 데이터 뒤에 데이터를 삽입 -> insertLast(data);
// 5. 원하는 인덱스에 데이터를 삭제 -> deleteAt(index);
// 6. 마지막 데이터를 제거 -> deleteLast();
// 7. 원하는 인덱스에 있는 데이터 읽기 -> getNodeAt(index);

export class LinkedList {
  constructor(){
    // 연결 리스트의 시작 Node를 가리킨다.
    this.head = null;

    // 총 저장된 Node의 수
    this.count = 0;
  }

  /**
   * 원하는 인덱스에 데이터를 삽입
   * @param {number} index - 삽입할 위치 index
   * @param {any} data - 삽입할 데이터
   */
  insertAt(index, data){    
    // 예외 처리
    if(index > this.count || index < 0) throw new Error('범위를 넘어갔습니다.');
    
    // 새로운 Node 생성
    let newNode = new Node(data); 
   
    if(index === 0){ 
      // 리스트의 가장 앞부분에 삽입할 경우

      // 1. 생성된 Node의 next가 head를 가리키도록 설정
      newNode.next = this.head; 
      // 2. 생성된 Node를 head로 설정
      this.head = newNode; 

    }else{ 
      // 앞부분 삽입을 제외한 원하는 인덱스에 삽입할 경우
      
      // head에서 부터 시작하기 때문에 head로 초기화
      let currentNode = this.head; 

      // 목표 인덱스 바로 전까지 next를 이용해 currentNode를 이동시킨다.
      for(let i=0; i<index -1; i++){
        currentNode = currentNode.next;  
      }

      // 1. 새로운 Node가 currentNode의 next Node를 가리키도록 설정
      newNode.next = currentNode.next;
      // 2. currentNode가 새로운 Node를 가리키도록 설정
      currentNode.next = newNode
    }

    // 새로운 Node가 삽입되었으니 count를 증가
    this.count++;
  }

  /**
   * 모든 데이터 출력
   * @returns {string} - 모든 Node의 data를 하나의 문자열에 담아 반환
   */
  printAll(){
    let currentNode = this.head;
    let text = '['

    while(currentNode){
      text += currentNode.data
      currentNode = currentNode.next;

      if(currentNode) text += ', ';
    }
    text += ']';
    console.log(text);    
    return text;
  }

  /**
   * 모든 데이터 제거
   */
  clear(){
    this.head = null; // head 초기화
    this.count = 0; // count 초기화
  }

  /**
   * 마지막 데이터 뒤에 데이터를 삽입
   * @param {any} data - 삽입할 데이터
   */
  insertLast(data){
    this.insertAt(this.count, data);
  }

  /**
   * 원하는 인덱스에 데이터를 삭제
   * @param {number} index - 제거할 위치 index
   * @return {{data: number, next: {data: number, next: any} | null}} - 제거된 노드의 데이터와 그 다음 노드에 대한 정보.
   */
  deleteAt(index){
    // 예외 처리
    if(index >= this.count || index < 0) throw new Error('제거할 수 없습니다.');

    let currentNode = this.head;

    if(index === 0){
      // 리스트의 가장 앞부분에 제거할 경우

      // 반환하기 위해 삭제된 Node를 저장
      const deleteNode = this.head;
      // head를 다음 Node인 head.next로 설정
      this.head = this.head.next;
      // 제거했으므로 count를 내린다.
      this.count--;

      // 삭제한 Node 반환
      return deleteNode;

    }else{
      // 리스트의 가장 앞부분을 제외한 위치를 제거할 경우

      // 제거할 Node 이전 Node까지 순회해 제거할 Node의 이전 Node를 가리키게 한다.
      for(let i=0; i<index -1; i++){
        currentNode = currentNode.next;
      }

      // currentNode.next가 참조하고 있는 다음 Node 즉, 제거해야 할 Node를 저장
      let deleteNode = currentNode.next; 
      
      // 제거할 Node의 next Node를 가리키게 한다.
      currentNode.next = currentNode.next.next;

      // 제거했으므로 count를 내린다.
      this.count--;

      // 삭제한 Node 반환
      return deleteNode;      
    }
  }

  /**
   * 마지막 데이터를 제거
   * @return {{data: number, next: {data: number, next: any} | null}} - 제거된 노드의 데이터와 그 다음 노드에 대한 정보.
   */
  deleteLast(){
    return this.deleteAt(this.count - 1);
  }

  /**
   * 원하는 인덱스에 있는 데이터 읽기 
   * @param {number} index - 읽고자하는 Node의 index
   * @return {{data: number, next: any}} - 해당 Node 반환
   */
  getNodeAt(index){
    // 예외 처리
    if(index >= this.count || index < 0) throw new Error('범위를 넘어갔습니다.');

    let currentNode = this.head;

    // currentNode가 해당 index까지 순회한다.
    for(let i=0; i< index ; i++){
      currentNode = currentNode.next;
    }

    // 최종적으로 이동한 Node를 반환
    return currentNode;
  }
}

 

 

스택(Stack) :

import { LinkedList } from './../LinkedList/LinikedList.mjs';

// * 스택의 추상자료형
// 1. 데이터 삽입 -> push();
// 2. 데이터 제거 -> pop();
// 3. top에 있는 데이터 참조 -> peek();
// 4. 스택이 비었는지 체크 -> isEmpty();

export class Stack{
  constructor(){
    this.list = new LinkedList();
  }

  push(data){
    this.list.insertAt(0, data);
  }

  pop(){
    try {      
      return this.list.deleteAt(0);
    } catch (error) {
      return null;
    }
  }

  peek(){
    return this.list.getNodeAt(0);
  }

  isEmpty(){
    return this.list.count === 0;
  }
}

 

 

큐 (Queue):

import { DoublyLinkedList } from "./DoublyLinkedList.mjs";
// * 기존에 구현한 Node에서 이전 Node도 가리킬 수 있도록 Node를 수정
// * 기존의 LinkedLst를 연결 리스트의 끝을 가리킬 수 있도록 수정 -> DoublyLinkedList

// * 큐의 추상자료형
// 1. 데이터 삽입 -> enqueue();
// 2. 데이터 제거 -> dequeue();
// 3. 데이터 참조 -> front();
// 4. 큐가 비었는지 확인 -> isEmpty();

class Queue{
    constructor(){
        this.list = new DoublyLinkedList();
    }

    enqueue(data){
        this.list.insertAt(0, data);
    }

    dequeue(){
        try{
            return this.list.deleteLast();
        } catch(e){
            return null;
        }
    }

    front(){
        return this.list.tail;
    }

    isEmpty(){
        return (this.list.count == 0);
    }
}

export {Queue};

 


운영체제

알고리즘 · 자료구조 워밍업클럽 CS

답변 0