Javascript/DSA

List Data Structure

미스터황탄 2016. 6. 16. 22:08

자바 스크립트에서 리스트는 Array에 있는 프로퍼티를 기준으로 구현이 가능하다.

리스트 클래스를 생성하기에 앞서 개념적인 부분을 정리하고자 한다 ADT란 무엇일까?

Abstrat Data Type

추상적 자료형(Abstract Data Type, 줄여서 ADT)은 컴퓨터 과학에서 자료들과 그 자료들에 대한 연산들을 명기한 것이다. 추상적 자료형은 구현 방법을 명시하고 있지 않다는 점에서 자료 구조와 다르다. 비슷한 개념의 추상적 자료 구조는 각 연산의 시간 복잡도를 명기하고 있지만 추상적 자료형에서는 이것조차 명기하지 않는다. -위키백과

자료에 대한 연산은 질의를 던지는것과 자료를 변경하기 위한 연산으로 나뉜다.

1.질의를 던지는것

pos() 현재 위치
length() 리스트의 요소 수 반환
toString() 리스트를 문자열로 표현해 반환
currPos() 리스트의 현재 위치 반환

2. 자료를 변경하기 위한 연산

clear() 리스트의 모든 요소 삭제
insert() 기존 요소 위로 새 요소를 추가
append() 새요소를 리스트의 끝에 추가
remove() 리스트의 요소 삭제
front() 현재 위치를 리스트 첫 번째 요소로 설정
end() 현재 위치를 리스트 마지막 요소로 설정
prev() 현재 위치를 한 요소 뒤로 이동
next() 현재 위치를 한 요소 앞으로 이동
moveTo() 현재 위치를 지정된 위치로 이동

클래스를 구현한다.. function 쓰기가 귀찬아서.. ES6 문법으로 작성했다 양해바란다. (__);

class List(){

    constructor(){

        this.listSize = 0;
        this.pos = 0;
        this.dataStore = [];

    }
    //추가
     append(element){
        this.dataStore[this.listSize++] = element; //요소추가후 1만큼 증가시킨다.
    }
   //탐색
   //indexOf 와 같은역할을 하지만 문자열이 완전히 일치하는지를 판별하기 때문에 구분됨.
     find(element){
        for (var i=0; i< this.dataStore.length; ++i){
            if(this.dataStore[i] == element ){
                return i;
            }
        }
        return -1;
    }
   //제거
     remove(element){
        var foundAt = this.find(element);
        if(foundAt >-1){
            this.dataStore.splice(foundAt,1);
            --this.listSize;
            return true;
        }
        return false;
    }
   //길이
     length(){
        return this.listSize;
    }
    //출력
     toString(){
        return this.dataStore;
    }
    //삽입
     insert(element,after){
        var insertPos = this.find(after);
        if(insertPos > -1){
            this.dataStore.splice(insertPos+1,0,element);
            ++this.listSize;
            return true;
        }
        return false;
    }
    //리스트 초기화
     clear(){
        delete this.dataStore;
        this.dataStore.length = 0;
        this.listSize = this.pos = 0;
        }
        //포함되어 있는지 여부
         contains(element){
                for( var i = 0; i < this.dataStore.length; ++i ) {
                    if(this.dataStore[i] == element ){
                        return true;
                    }
                }
                return false;
            }
       //리스트의 현재위치를 처음으로 이동
         front(){
            this.pos = 0;
        }
        //리스트의 현재위치를 마지막으로 이동
         end(){
            this.pos = this.listSize-1;
        }
        //리스트의 현재위치를 한요소 뒤로 이동
             prev(){
                if(this.pos > 0){
                    --this.pos;
                }
            }
         //리스트의 현재위치를 한요소 앞으로 이동
           next(){
                if(this.pos < this.listSize-1){
                    ++this.pos;
                }
            }
         //리스트의 현재위치
           currPos(){
                return this.pos;
            }
         //리스트의 해당 위치로 이동
           moveTo(position){
                this.pos = position;
            }
          //리스트의 요소 반환
            getElement(){
                return this.dataStore[this.pos];
            }


}

indexOf 를 활용한것 외엔 특별히 눈여겨 볼점이 없었다. 이것저것 가지고 놀아 보면된다.

연습문제

Write a function that inserts an element into a list only if the element to be inserted is larger than any of the elements currently in the list. Larger can mean either greater than when working with numeric values, or further down in the alphabet, when working with textual values.
Write a function that inserts an element into a list only if the element to be inserted is smaller than any of the elements currently in the list.

사실 연습문제가 이번 포스팅에 주된 핵심 내용이다. 시간관계상 코드리뷰를 받지 못했지만 문제에 대한 정의가 에매했던 만큼

해석도 각양 각색 다양한 코드에 대한 생각들을 공유 받을수 있었다.

function Compare(){

            var numArr = [];
            var charArr = [];
            var firstCharMovie =[];
            var movies = [
                {"1": "The Shawshank Redemption"},{"2": "The Godfather"},
                {"3": "The Godfather : Part II"},{"4":"Pulp Fiction"},
                {"5":"The Good, the Bad and the Ugly"},
                {"6":"12 Angry Men"},{"7":"Schindler's List"},{"8":"The Dark Knight"},
                {"9":"The Lord of the Rings: The Return of the King"},{"10": "Fight Club"},
                {"11":"Star Wars : Episode V - The Empire Strikes Back"},
                {"12": "One Flew Over the Cuckoo's Nest"},
                {"13": "The Lord of the Rings: The Fellowship of the Ring"},
                {"14": "Inception"},{"15": "Goodfellas"},{"16": "Star Wars"},
                {"17": "Seven Samurai"},{"18": "The Matrix"},
                {"19": "Forrest Gump"},{"20": "City of God"}
            ];
            var elementEA = movies.length+1;
            this.elementSmall =elementSmall;
            this.elementBig = elementBig;
            this.toString = toString;

        movies.forEach(function(v,i){ // v:value  , i : index

            var firstChar = v[i+1].split("");
            //숫자인지 문자열인지 식별 한다.
            if( !isNaN(firstChar[0]) ){ //숫자
                if(numArr.indexOf(firstChar[0]) ==-1){ //중복값이없을경우.
                     numArr.push(firstChar[0]);
                }
            }else{//문자
                if(charArr.indexOf(firstChar[0])==-1){
                    charArr.push(firstChar[0]);
                }
            }
        });
        function toString(){
            return movies;
        }
        //요소가 큰지여부.
        function elementBig(movie){
             firstCharMovie = movie.trim().split("");
                //입력받은 값에 첫글자가 숫자인지 판별.
                if( !isNaN(firstCharMovie[0]) ){

                      var arrChk =  numArr.every(function(v,i){ return v < firstCharMovie[0]; });

                      if(!arrChk){
                            console.log("입력한 요소가 기존 요소와 같거나 작습니다.");
                      }else{
                            movies.push( { elementEA : movie } );
                            console.log('영화 추가완료');
                      }

                }else{

                    var arrChk =  charArr.every(function(v,i){ return v < firstCharMovie[0]; });

                     if(!arrChk){
                            console.log("입력한 요소가 기존 요소와 같거나 작습니다.");
                      }else{
                            movies.push({elementEA:movie});
                            console.log('영화 추가완료');
                      }


                }
        }
        function elementSmall(movie){
               //입력받은 값에 첫글자가 숫자인지 판별.
               firstCharMovie = movie.trim().split("");
                if( !isNaN(firstCharMovie[0]) ){

                      var arrChk =  numArr.every(function(v,i){ return v > firstCharMovie[0]; });

                      if(!arrChk){
                            console.log("입력한 요소가 기존 요소와 같거나 큽니다.");
                      }else{
                            movies.push({elementEA:movie});
                            console.log('추가완료');
                      }

                }else{

                    var arrChk =  charArr.every(function(v,i){ return v > firstCharMovie[0]; });

                     if(!arrChk){
                            console.log("입력한 요소가 기존 요소와 같거나 큽니다.");
                      }else{
                            movies.push({elementEA:movie});
                            console.log('추가완료');
                      }
                }
        }
}

var compare = new Compare();

compare.elementBig("100");

console.log(compare.toString());

ES5 에서 추가된 every 함수를 활용했고 isNaN 을 사용해 숫자를 판별하고 있다.

isNaN을 사용할경우 문제점

console.log(isNaN(10))                   // false
console.log(isNaN('a'))                    // true
console.log(isNaN(true))                // false
console.log(isNaN(null))                 // false
console.log(isNaN(undefined))      // true
console.log(isNaN({}))                   // true
console.log(isNaN([]))                   // false
console.log(isNaN(function(){}))   // true
console.log(isNaN(NaN))              // true

그래서 숫자인지 정확히 판별하기 위해서 Number.isNaN을 사용하는것이 좋다.

그리고 every 함수의 경우, Array 에서 소개한대로 전부 true 일경우 true 를 반환한다.

every 함수를 사용하기보다 for문안에 if 를 넣어서 처리하려고 했으나

이내용을 보고 성능에 관점을 둬서 every 함수를 사용했다.
http://jindo.dev.naver.com/jsMatch/index.html?d=231&openResult=1

벤치결과 반복문안에 if 절보다 미묘하게 느린것이 확인되고 every 함수 사용방향성에 대해서 의문을 갖게되었다.

이때 스터디장이 귀감이 될만한 이야기를 해주었다. 첫번째 실수를 줄인다. 두번째 가독성을 높인다.

속도만이 프로그래밍에서 중요한것은 아니라는점을 상기시켜줬다.

그렇다. 협업을 통해 이미 스파게티코드를 경험해본 입장으로서 팀을 위한 후임자를 위한 코딩이 얼마나 중요한지

깨닮은바 있다.

그리고 ES6에 대해서 var 와 let 의 속도 비교도 간단히 해보면 도움이 될꺼라는 첨언도 같이 들었다.

바로 해당사이트에서 간단한 반복문으로 let 과 var 벤치마크를 진행하였는데. let 이 var 보다 조금 느린 결과 차이를 가져왔다.

let은 블록 스코프 변수인데.. 더 빠르지않을까 라는 생각과는 다른 결과 였다..

참으로 배울것이 많았던 소중한 시간이다.