data classNode<T>(vardata:T,varnext:Node<T>?=null)classSinglyLinkedList<T>{varhead:Node<T>?=nullvarsize:Int=0// 리스트가 비어 있는지 확인funisEmpty():Boolean=head==null// 리스트 맨 앞에 노드 추가funaddFirst(data:T){valnewNode=Node(data)newNode.next=headhead=newNodesize++}// 리스트 맨 뒤에 노드 추가funaddLast(data:T){valnewNode=Node(data)if(isEmpty()){head=newNodesize++return}varcurrent=headwhile(current?.next!=null){current=current.next}current?.next=newNodesize++}// 특정 노드 삭제funremove(node:Node<T>){if(isEmpty()){return}// 헤드 노드 삭제if(node===head){head=head?.nextsize--return}// 중간 또는 마지막 노드 삭제varcurrent=headwhile(current?.next!=null&¤t.next!==node){current=current.next}if(current?.next===node){current.next=node.nextsize--}}}
더미 노드 사용
data classNode<T>(vardata:T?=null,varnext:Node<T>?=null)classSinglyLinkedList<T>{// 더미 헤드 노드valhead:Node<T>init{head=Node()}// 리스트 맨 앞에 노드 추가funaddFirst(data:T){valnewNode=Node(data)newNode.next=head.nexthead.next=newNode}// 리스트 맨 뒤에 노드 추가funaddLast(data:T){valnewNode=Node(data)varcurrent=headwhile(current?.next!=null){current=current.next}current?.next=newNodesize++}// 특정 노드 삭제funremove(node:Node<T>){varcurrent=headwhile(current.next!=null&¤t.next!==node){current=current.next!!}// 삭제할 노드를 찾았을 경우if(current.next!=null&¤t.next===node){current.next=node.next}}}
이중 연결 리스트
더미 노드 미사용
data classNode<T>(vardata:T,varprev:Node<T>?=null,varnext:Node<T>?=null)classDoublyLinkedList<T>{varhead:Node<T>?=nullvartail:Node<T>?=nullvarsize:Int=0// 리스트가 비어 있는지 확인funisEmpty():Boolean=size==0// 리스트의 맨 앞에 노드 추가funaddFirst(data:T){valnewNode=Node(data)if(isEmpty()){head=newNodetail=newNode}else{newNode.next=headhead?.prev=newNodehead=newNode}size++}// 리스트의 맨 뒤에 노드 추가funaddLast(data:T){valnewNode=Node(data)if(isEmpty()){head=newNodetail=newNode}else{tail?.next=newNodenewNode.prev=tailtail=newNode}size++}// 리스트 중간에 노드 삽입funinsertAfter(node:Node<T>,data:T){if(node===tail){addLast(data)return}valnewNode=Node(data)newNode.prev=nodenewNode.next=node.nextnode.next?.prev=newNodenode.next=newNodesize++}// 특정 노드 삭제funremove(node:Node<T>){if(isEmpty()){return}// 헤드 노드 삭제if(node===head){head=node.nextif(head!=null){head!!.prev=null}// 테일 노드 삭제}elseif(node===tail){tail=node.previf(tail!=null){tail!!.next=null}// 중간 노드 삭제}else{node.prev?.next=node.nextnode.next?.prev=node.prev}size--}}
더미 노드 사용
data classNode<T>(vardata:T?=null,varprev:Node<T>?=null,varnext:Node<T>?=null)classDoublyLinkedList<T>{// 더미 헤드 노드varhead:Node<T>// 더미 테일 노드vartail:Node<T>init{head=Node()tail=Node()head.next=tailtail.prev=head}// 리스트의 맨 앞에 노드 추가funaddFirst(data:T){valnewNode=Node(data)valfirstNode=head.nextnewNode.prev=headnewNode.next=firstNodehead.next=newNodefirstNode?.prev=newNode}// 리스트의 맨 뒤에 노드 추가funaddLast(data:T){valnewNode=Node(data)vallastNode=tail.prevnewNode.prev=lastNodenewNode.next=tailtail.prev=newNodelastNode?.next=newNode}// 리스트 중간에 노드 삽입funinsertAfter(node:Node<T>,data:T){if(node===tail){return}valnewNode=Node(data)valnextNode=node.nextnewNode.prev=nodenewNode.next=nextNodenextNode?.prev=newNodenode.next=newNode}// 특정 노드 삭제funremove(node:Node<T>){// 더미 노드는 삭제하지 않는다.if(node===head||node===tail){return}node.prev?.next=node.nextnode.next?.prev=node.prev}}
LRU(least recently used) 캐시 구현
data classNode<K,V>(varkey:K,varvalue:V,varprev:Node<T>?=null,varnext:Node<T>?=null)classLRUCache(privatevalcapacity:Int){valcache=HashMap<Int,Node<Int,Int>>()varhead:Node<Int,Int>=Node()vartail:Node<Int,Int>=Node()init{head.next=tailtail.prev=head}funget(key:Int):Int{valnode=cache[key]if(node!=null){// 캐시 히트// 가장 최근 사용 노드로 이동remove(node)addFirst(node)returnnode.value?:-1}// 캐시 미스return-1}funput(key:Int,value:Int){// 캐시가 이미 존재하는 경우 (캐시 값 갱신, 가장 최근 사용 노드로 이동)// 가득 차더라도 LRU 제거가 필요하지 않음if(cache[key]!=null){cache[key]!!.value=valueremove(cache[key]!!)addFirst(cache[key]!!)// 캐시가 없는 경우 (캐시 값 추가, 가장 최근 사용 노드로 이동)// 가득찬 경우 LRU 제거, 가득 차지 않은 경우 LRU 제거하지 않고 캐시만 처리}else{// 가득찬 경우 LRU 제거if(cache.size>=capacity){if(tail.prev!=null){vallru=tail.prev!!remove(lru)cache.remove(lru.key)}cache[key]=Node(key,value)addFirst(cache[key]!!)// 가득 차지 않은 경우 LRU 제거하지 않고 캐시만 처리}else{cache[key]=Node(key,value)addFirst(cache[key]!!)}}}privatefunaddFirst(node:Node<Int,Int>){valnewNode=nodevalfirstNode=head.nextnewNode.prev=headnewNode.next=firstNodehead.next=newNodefirstNode?.prev=newNode}privatefunaddLast(node:Node<Int,Int>){valnewNode=nodevallastNode=tail.prevnewNode.prev=lastNodenewNode.next=tailtail.prev=newNodelastNode?.next=newNode}privatefunremove(node:Node<Int,Int>){valprevNode=node.prevvalnextNode=node.nextprevNode?.next=nextNodenextNode?.prev=prevNode}}
문자열은 연속된 문자들이 그룹화되어 구성된 자료 구조이다. 따라서 데이터를 그룹화한 추상 자료형인 컬렉션(collection)의 다양한 자료 구조로 문자열을 구조화할 수 있으며 다양한 자료 구조 탐색 알고리즘을 사용하여 부분 문자열들을 탐색 및 비교하는 등의 문제를 해결할 수 있다.
백트래킹(backtracking)(또는 역추적) 알고리즘이란 최적의 해결책을 찾기 위해 모든 가능한 방법을 후보(candidate)로 구성한 후, 점진적으로 후보들을 시도하면서 유효한 후보가 아닐 경우(문제의 정답 조건을 만족하지 않을 경우) 문제 해결 과정에서 제외하고 되돌아가 ...
Comments