|  개념

기수란? 수를 나타내는 데 기초가 되는 수. 

- 10진법에서는 0~9까지의 정수를 말하며, 2진법에서는 0~1까지 정수를 말한다.

 

|  기수 변환을 수행하는 프로그램

package _00_두잇;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class _01_기수변환 {
    //정수값 x를 r로 변환하여 배열 d에 아랫자리부터 넣어두고 자릿수를 반환한다.
	static int convert(int x, int r, char[] d) {
		int digits = 0;
		String dchar = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		
		//배열 안에 나눈 나머지를 하나씩 넣는다 
		while (x != 0) {
		  d[digits++] = dchar.charAt(x % r);
		  x = x / r;
		} 
		
		//배열의 역순이 변환한 진수값이다.
		for (int i = 0; i < digits/2; i++) {
			char tmp = d[i];
			d[i] = d[digits-1-i];
			d[digits-1-i] = tmp;
		}
		
		//변환한 수의 자릿수
		return digits;
		
	}
	
	public static void main(String[] args) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		
		//변환하려는 수
		int num;
		//기수
		int jin;
		//변환한 수의 자릿수
		int digits;
		//변환 후 각 자리의 숫자를 넣어주는 문자 배열
		char[] cvArr = new char[32];
		
		System.out.print("변환하려는 수 : ");
		
		num = Integer.parseInt(reader.readLine());
		
		System.out.print("자릿수(2~36) : ");
		
		jin = Integer.parseInt(reader.readLine());
		
		digits = convert(num, jin, cvArr);
		
		System.out.print(jin+"진수로 ");
		for (int i = 0; i < digits; i++) {
			System.out.print(cvArr[i]);
		}
		System.out.print("입니다.\n");
		
	}
}

>> 결과

변환하려는 수 : 35
자릿수(2~36) : 2
2진수로 100011입니다.

 

[출처]

[자료구조와 함께 배우는 알고리즘 입문], BohYoh Shibata지음

■ 정렬의 속도 / 메모리 사용 비교

- 미니멈이 1이고, 맥시멈이 백만인 숫자를 입력받아 정렬한다고 할 때, 어떤 정렬을 쓰는게 좋을까....?

- 문제를 풀어본 결과, Merge sort가 가장 빨랐고, 그 다음에 Arrays.sort, 그 다임이 Quck Sort 였다.

- 그럼 Arrays.sort는 무슨 정렬을 사용하는 걸까...

 

https://www.acmicpc.net/problem/2751

 

2751번: 수 정렬하기 2

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 수가 주어진다. 이 수는 절댓값이 1,000,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.

www.acmicpc.net

 

Collections와 Arrays의 Sort 메소드가 사용하는 정렬방식

[1] Arrays.sort() : 듀얼 피봇 퀵정렬 (Dual-Pivot QuckSort)

[2] Collections.sort() : Tim 정렬 (삽입 정렬 + 합병정렬을 결합한 방식)

https://sabarada.tistory.com/138

 

[Java] Java의 정렬 알고리즘 - Arrays와 Collections

안녕하세요. 오늘 포스팅은 Java의 Collection에서 사용하고 있는 정렬에 대해서 알아보려고 합니다. Java를 사용하다보면 정렬해서 처리해야할 경우가 생깁니다. 그럴경우 아래와 같이코드를 작성

sabarada.tistory.com

 

■ 결론

- 위 문제에서는 결국, 병합정렬을 사용할 때 가장 빠르고, 그 다음에 듀얼 피봇 퀵정렬을 사용할 때 빨랐다.

- 퀵 정렬은 오히려 시간이 오래 걸려 시간 초과가 나타났다.

   ☆ 공부한 내용을 정리한 내용입니다. 잘못된 부분이 있으면 고정 위해 댓글 부탁드립니다.

 

https://www.youtube.com/watch?v=QAyl79dCO_k&list=PLjSkJdbr_gFZMNhIMl2AJ9n5c2hNK-qJk&index=2 

 

■ 병합 정렬

- 병합 정렬이란? 요소가 하나만 남을 때까지 리스트를 나눠준 후[분할],

                       나눴던 리스트를 대소 관계에 맞게 다시 합치는 방법[병합]

- 분할 분할 분할 분할.... 병합 병합 병합 병합... 을 반복한 결과

- 안정적이지만, 자료구조를 하나 더 만들 필요가 있다.

   *자료구조를 더 만들 수 없을 땐 퀵 소트를 쓴다.

- 시간 복잡도 O(n log n) , 최악(n log n) 

부스트코스

 

■ 자바로 구현한 병합 정렬

//[[부스트 코스 방식]]
static int[] array, temp;

public static void mergeSort(int[] arr) {
    array = arr;
    temp = new int[array.length];
    split(0, array.length-1);
}

//리스트가 1개가 남을 때까지 나눈다.
private static void split(int low, int high) {
    if (low == high) return; //값이 하나만 있으면 정렬할 필요 없음
    int mid = high + low / 2;
    split(low, mid);
    split(mid+1,high);
    merge(low,mid,high);
}

//대소 비교 후 순서에 맞게 열거한다.
private static void merge(int low, int mid, int high) {
    int i = low, j = mid+1, tempposn = low;

    //나눈 리스트의 대소 비교와 정렬
    while (i <= mid && j <= high) {
        if (array[i] <= array[j]) {
            temp[tempposn++] = array[i++];
        }
        else {
            temp[tempposn++] = array[j++];
        }
    }

    //i가 mid로 가고, j가 high로 갈 때까지 반복
    while (i <= mid) temp[tempposn++] = array[i++];
    while (j <= high) temp[tempposn++] = array[j++];

    //원래 배열에 다시 복사
    for (tempposn = low; tempposn <= high; tempposn++)
        array[tempposn] = temp[tempposn];

}
//[[엔지니어 대한민국 방식]]
private static void mergeSort2(int[] arr2) {
    int[] tmp = new int[arr2.length];
    mergeSort2(arr2, tmp, 0, arr2.length - 1);
}

private static void mergeSort2(int[] arr2, int[] tmp, int start, int end) {
    if (start < end) {
        int mid = (start + end) / 2;
        mergeSort2(arr2, tmp, start, mid);
        mergeSort2(arr2, tmp, mid+1, end);
        merge2(arr2, tmp, start, mid, end);
    }
}

private static void merge2(int[] arr, int[] tmp, int start, int mid, int end) {
    for (int i = start; i <= end; i++) {
        tmp[i] = arr[i];
    }
    int part1 = start;
    int part2 = mid + 1;
    int index = start;
    while (part1 <= mid && part2 <= end) {
        if (tmp[part1] <= tmp[part2]) {
            arr[index] = tmp[part1];
            part1++;
        }else {
            arr[index] = tmp[part2];
            part2++;
        }
        index++;
    }
    for (int i = 0; i <= mid - part1; i++) {
        arr[index+i] = tmp[part1+i];
    }
}
   ☆ 공부한 내용을 정리한 내용입니다. 잘못된 부분이 있으면 고정 위해 댓글 부탁드립니다.

 

■ 퀵 정렬

원리 ) 중심점(Pivot Point)을 임의로 고른 후
       이 중심점보다 작은 수를 한 쪽으로 분류하고, 큰 수들은 다른 쪽으로 분류하여 정렬하는 방법
       * 분할과 정복

- 중앙값 정렬 방식을 확장하여 개발한 방식.

- 평균 정렬 결과가 필요할 때 사용하는 것이 좋다.

- 퀵 정렬은 멀리 있는 값을 서로 비교하고 교환하기 때문에 안정성은 떨어진다.

- 시간 복잡도 O(n log n) 

 

※ 피벗을 중간 또는 마지막을 잡는 이유 :

- 피벗은 첫번째, 중간, 마지막 인덱스나 랜덤으로 선정 가능하다.

- 무엇을 피벗으로 잡느냐에 따라 처리 시간이 달라진다.

- 피벗 값이 중간 크기일 수록 더 균등하게 리스트를 분할 할 수 있다.

 

■ 재귀적인 퀵 정렬 (배열 사용)

package _02_정렬;

import java.util.Arrays;

public class _00_QuickSort3_안보고구현하기 {
	
	//오름차순 퀵소트 메소드를 구현하라
	private static void quickSortAsc(int[] arr, int left, int right) {
		int pl = left;
		int pr = right;
		int pivot = arr[(pl + pr)/2];
		
		//피봇 값을 기준으로 좌우를 정렬
		while (pl <= pr) {
			while (arr[pl] < pivot) pl++; //큰값이 나올때까지
			while (arr[pr] > pivot) pr--; //작은값이 나올때까지
			
			if (pl <= pr) {
				swap(arr, pl, pr); //교환하고
				pl++; //다시 커서 이동
				pr--;
			}
		}
		
		//재귀를 사용해 분할&정렬을 반복한다. (이 시점에서 pr < pl)
		if (left < pr) { //1개 이상일 때 
			quickSortAsc(arr, left, pr);
		}
		
		if (pl < right) {
			quickSortAsc(arr, pl, right);
		}
		
	}
	
	//내림차순 퀵소트 메소드를 구현하라
	private static void quickSortDes(int[] arr, int left, int right) {
		int pl = left;
		int pr = right;
		int pivot = arr[(pl + pr)/2];
		
		//피봇 값을 기준으로 좌우를 정렬
		while (pl <= pr) {
			while (arr[pl] > pivot) pl++; //작은값이 나올때까지
			while (arr[pr] < pivot) pr--; //큰값이 나올때까지
			
			if (pl <= pr) {
				swap(arr, pl, pr); //교환하고
				pl++; //다시 커서 이동
				pr--;
			}
		}
		
		//재귀를 사용해 분할&정렬을 반복한다. (이 시점에서 pr < pl)
		if (left < pr) { //1개 이상일 때 
			quickSortDes(arr, left, pr);
		}
		
		if (pl < right) {
			quickSortDes(arr, pl, right);
		}
	}
	
	//교환 메소드
	static void swap(int[] arr, int index1, int index2) {
		int tmp = arr[index1];
		arr[index1] = arr[index2];
		arr[index2] = tmp;
	}
	
	//랜덤 메소드
	public static int[] random(int[] arr) {
		
		OUTER :
		for (int i = 0; i < arr.length; i++) {
			
			arr[i] = (int)(Math.random()*10)+1;
			
			for (int j = 0; j < i; j++) {
				
				if (arr[j] == arr[i]) {
					i--;
					continue OUTER;
				}
			}
		}
		
		return arr;
		
	}

	public static void main(String[] args) {
		int[] arr = new int[10];
		
		random(arr);
		
		System.out.println(Arrays.toString(arr));
		
		quickSortAsc(arr, 0, arr.length-1);
		
		System.out.println(Arrays.toString(arr));
		
		quickSortDes(arr, 0, arr.length-1);
		
		System.out.println(Arrays.toString(arr));
		
	}

}

>> 결과

[1, 7, 5, 10, 2, 4, 3, 8, 9, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
더보기
//엔지니어 대한민국 방식
private static void quickSort(int[] arr) {
    quickSort(arr,0,arr.length-1);
}

private static void quickSort(int[] arr, int start, int end) {
    int part2 = partition(arr, start, end);
    if (start < part2 - 1) { //오른쪽 파티션이 왼쪽 파티션보다 1개 보다 더 많이 차이날때
        quickSort(arr, start, part2 - 1);
    }
    if (start < end) { //오른쪽 파티션이 1개 이상일 때
        quickSort(arr, part2, end);
    }
}

private static int partition(int[] arr, int start, int end) {
    int pivot = arr[(start + end) / 2];
    while (start <= end) {
        while (arr[start] < pivot) start++;
        while (arr[end] > pivot) end--;
        if (start <= end) {
            swap (arr, start, end);
            start++;
            end--;
        }
    }
    return start;
}

private static void swap(int[] arr, int start, int end) {
    int tmp = arr[start];
    arr[start] = arr[end];
    arr[end] = tmp;
}

private static void printArray(int[] arr) {
    for (int data : arr) {
        System.out.print(data + ",");
    }
    System.out.println();
}

 

■ 비재귀적인 퀵 정렬 (ArrayList or Stack 사용)

//알고리즘과 자료구조 방식
public static <T extends Comparable<? super T>> List<T> quicksort(List<T> list)
{
    if (list.size() <= 1) return list;

    int pivot = list.size() / 2;

    List<T> a = new ArrayList<T>(); //lesser
    List<T> b = new ArrayList<T>(); //greater

    int c = 0; //same

    for (T number : list) {
        if (list.get(pivot).compareTo(number) < 0) //-1, number > pivot
            b.add(number);
        else if (list.get(pivot).compareTo(number) > 0) //+1, number < pivot
            a.add(number);
        else
            c++;
    }

    a = quicksort(a);
    for (int i = 0; i < c; i++) {
        a.add(list.get(pivot));
    }

    b = quicksort(b);

    List<T> sorted = new ArrayList<T>();
    sorted.addAll(a);
    sorted.addAll(b);
    return sorted;

}

 

 

[출처]

- 부스트코스, 자바로 구현하고 배우는 자료구조

- 유투브, 엔지니어 대한민국, 퀵정렬에 대해 알아보고 자바로 구현하기

- 책, [그림으로 정리한 알고리즘과 자료구조], 조민호 지음

- 책, [do it 자료구조와 함께 배우는 알고리즘 입문]

'Computer Science > Algorithm' 카테고리의 다른 글

[정렬] 정렬 문제 풀이 및 속도 비교  (0) 2022.05.11
[정렬] 병합정렬(Merge Sort)  (0) 2022.05.11
[자료구조] 큐(Queue)  (0) 2022.04.28
[자료구조] 스택  (0) 2022.04.18
[검색] 선형탐색과 이진탐색  (0) 2022.04.12

란?

- FIFO (First in First Out) 방식으로 데이터를 입출력

- 현실 세계의 큐 예 )

    티켓 판매기에서 대기하고 있는 사람들,

    일방통행 도로의 차동자들, 인쇄기의 인쇄 순서, CPU의 테스크 스케줄링

- 큐의 한계 :

  1) front부터 삭제되며, 삭제된 공간을 다시는 사용하지 못한다. 

  2) (배열을 사용할 경우) 큐의 크기가 정해지기 때문에 rear가 더 움직이지 못한다.

     (-> 이 부분은 자바에서는 동적관리 객체인 LinkedList로 해결했다)

- 큐의 한계를 보완 : 원형 큐, 우선순위 큐

 

큐의 내부 구조

- 유투브의 영상에 나와있는 튜토리얼에 따라 큐를 구현해보았다. 

https://www.youtube.com/watch?v=W3jNbNGyjMs&list=PLjSkJdbr_gFZL2BNnGLvTgMYXptKGIyum&index=2 

☞ 확인 사항

- 큐는 데이터를 넣을 때 마지막에 넣고, 꺼낼 때는 앞에서부터 꺼낸다

  (1) offer을 할 때는 : REAR가 가리키는 것이 있을 때 ) REAR의 NEXT에 연결

                            FRONT가 가리키는 것이 없을 때(= 저장된 데이터의 사이즈가 0) )

                                FRONT와 REAR가 모두 null임을 명시한다.

  (2) poll을 할 때는 : FRONT가 가리키는 것이 없을 때 ) 꺼낼 수 없으므로 예외 (NoSuchElementException)를 발생

                           FRONT를 꺼낸 뒤 FRONT->NEXT를 FRONT로 변경

                           만약에 새로운 FRONT가 가리키는게 없을때(= 저장된 데이터의 사이즈가 0)

                               FRONT와 REAR가 모두 null임을 명시한다.

※ 자바의 경우 큐는 인터페이스며, LinkedList가 이를 구현하고 있다.

   아래의 실제 자바 Queue메소드는 LinkedList에서 사용 가능하다.
실제 자바 Queue 메소드 구현객체의 메소드 내용
offer(data) add(data) 데이터 추가
poll() remove() 가장 앞 데이터 꺼내기
peek() peek() 가장 앞 데이터 읽기
isEmpty() isEmpty() 비어있는지 확인

☞ 구현 하기

import java.util.NoSuchElementException;

class Queue<T>{
	
	class Node<T>{
		private T data;
		private Node<T> next;
		
		public Node(T data) {
			this.data = data;
		}
	}
	
	private Node<T> first;
	private Node<T> last;
	
	public void add(T item) {
		Node<T> t = new Node<T>(item);
		
		if (last != null) {
			last.next = t;
		}
		last = t;
		
		if (first == null) {
			first = last;
		}
	} 
	
	public T remove() {
		if (first == null) {
			throw new NoSuchElementException();
		}
		
		T data = first.data;
		first = first.next;
		
		if (first == null) {
			last = null;
		}
		return data;
	}
	
	public T peek() {
		if (first == null) {
			throw new NoSuchElementException();
		}
		return first.data;
	}
	
	public boolean isEmpty() {
		return first == null;
	}

}//end class Queue

 

■ 큐 알고리즘 예제

https://www.acmicpc.net/problem/2164

☞ 계획 수립

  [1] LinkedList를 사용하여 데이터를 하나씩 넣어준다.
  [2] 반복문을 통해 [1] poll [2] poll & offer을 반복한다.

☞ 계획 수행

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;

public class Ex01_2164_카드2 {

	public static void main(String[] args) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		
		int N = Integer.parseInt(reader.readLine());
		
		LinkedList<Integer> list = new LinkedList<Integer>();
		
	    //순서대로 1~N값 입력
		for (int i = 1; i <= N; i++) {
			list.offer(i);
		}
		
		//버리고, 밑으로 내리는 것 반복
		while (list.size() != 1) {			
			list.poll(); //첫번째로 꺼낸 것은 버린다.
			list.offer(list.poll()); //두번째로 꺼낸 것은 가장 마지막에 넣는다.
		}
		System.out.println(list.peek());
		
	}

}

- 여기까지는 문제가 어렵지 않았다.. 그런데 아래의 문제들을 만난 뒤 당황..

 

■ 원형 큐 (Circular Queue)의 원리를 사용한 알고리즘 문제

- 원형 큐의 개념 : 큐를 원형의 구조처럼 한 바퀴를 돌리며 사용하는 방식

☞ 계획 수립

  [1] LinkedList를 사용한다.
  [2] 이중 루프를 돌려,
      - 바깥에서는 큐가 빌 때까지 반복,
      - 안쪽에서는 K번째 전까지는 poll & offer을 반복하고, K번째에는 poll을 한다.
  [3] 출력은 StringBuffer를 사용한다.

 

☞ 계획 수행

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Ex02_11866_요세푸스문제1_원형큐사용 {

	public static void main(String[] args) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		StringBuffer buffer = new StringBuffer();
		StringTokenizer token = new StringTokenizer(reader.readLine());
		
		int N = Integer.parseInt(token.nextToken());
		int K = Integer.parseInt(token.nextToken());
		
		//1~N까지의 데이터를 담을 연결리스트
		Queue<Integer> queue = new LinkedList<Integer>();
		
		//1~N까지 데이터 채우기
		for (int i = 1; i <= N; i++) {
			queue.offer(i);
		}
		
		buffer.append("<");
		
		int count = 0;
		
		//큐가 더 이상 아무것도 없을 때까지 반복
		while (!queue.isEmpty()) {
			//K보다 작을 때까지 poll&offer을 반복
			for (int i = 1; i < K; i++) {
				queue.offer(queue.poll());
			}
			
			//K번째에 poll해서 buffer에 저장
			if (count == 0) {
				buffer.append(queue.poll());
				count++;
				continue;
			}
			
			buffer.append(", ").append(queue.poll()); 
			
		}//end while
		
		buffer.append(">");

		System.out.println(buffer);
		
	}
	
}

 

>> 결과

7 3
<3, 6, 2, 7, 5, 1, 4>

▼ 처음에 일반큐 + 배열 + 커서변수를 사용해서 예제를 풀었었다. 

    그렇게 하니 코드도 길고 내가 적고도 다른 사람에게 설명할 수 없는 코드가 만들어졌다.

    스터디 때 다른 팀원분이 원형큐에 대해 설명해주셔서 알아보고 다시 작성을 해보았는데

    원형큐를 사용하니 메모리 사용량은 더 많았어도 시간은 더 준 걸 볼 수 있었다.

 

 

[참조]

https://st-lab.tistory.com/184

https://velog.io/@delicate1290/%EB%B0%B1%EC%A4%80-%EB%AC%B8%EC%A0%9C-%ED%92%80%EC%9D%B4-%EC%9A%94%EC%84%B8%ED%91%B8%EC%8A%A4-%EB%AC%B8%EC%A0%9C-1158%EB%B2%88

'Computer Science > Algorithm' 카테고리의 다른 글

[정렬] 병합정렬(Merge Sort)  (0) 2022.05.11
[정렬] 퀵 정렬(Quick Sort)  (1) 2022.05.10
[자료구조] 스택  (0) 2022.04.18
[검색] 선형탐색과 이진탐색  (0) 2022.04.12
[자바의 정석] 스택과 큐  (0) 2022.03.30

[자료구조 알고리즘] Stack 구현하기 in Java - YouTube

 

[ 스택의 활용 예 : 출처 자바의 정석 ]

수식 계산, 수식괄호검사, 워드프로세서의 undo/redo, 웹브라우저의 뒤로/앞으로

 

★ 문제 : 10828번: 스택 (acmicpc.net)

 

10828번: 스택

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지

www.acmicpc.net

★ 스택 단계 (acmicpc.net)

 

스택 단계

주어진 문자열이 올바른 괄호열인지 판단하는 문제

www.acmicpc.net

 

■ 스택을 생성해보는 예제 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class _00_스택 {
	public static void main(String[] args) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer token;
		
		//스택 인스턴스 생성
		Stack stack = new Stack();
		
		//첫번째줄 입력값(명령의 수) 
		int N = Integer.parseInt(reader.readLine()); 
		
		//명령 문자열 한 줄
		String input;
		//명령어
		String order;
		
		while (N > 0) {
			input = reader.readLine();
			token = new StringTokenizer(input);
			order = token.nextToken();
			
			//명령어에 따라 스택 메소드 실행
			if (order.equals("push")) {
				int item = Integer.parseInt(token.nextToken());
				stack.push(item);
			} else if (order.equals("pop")) {
				stack.pop();
			} else if (order.equals("size")) {
				stack.size();
			} else if (order.equals("empty")) {
				stack.empty();
			} else if (order.equals("top")) {
				stack.top();
			}
			
			N--;
		}
	}
}

class Stack {
	//노드 내부 클래스 정의
	class Node {
		private int data;
		private Node next;
	}
	
	//가장 위에 있는 노드
	private Node top;
	
	//push메소드 : 노드 삽입
	public void push(int item) {
		Node t = new Node();
		t.data = item;
		t.next = top;
		top = t;
	
	//pop메소드 : 노드 빼기 (뺄 때, 데이터값 읽기)
	public void pop() {
	    if (top == null) {
	    	System.out.println("-1");
	    }else {
	    	Node tmp = top;
	    	top = top.next;
	    	System.out.println(tmp.data);
	    }
	}//pop()
	
	//size메소드 : 노드의 갯수 반환
	public void size() {
		int count = 1;
		Node tmp = top;
		
		if (top == null) {
			System.out.println(0);
		} else {
			while(tmp.next != null) {
				tmp = tmp.next;
				count++;
			}
			System.out.println(count);
		}
	}//size()
	
	//empty메소드(isEmpty) : 노드가 있는지 여부 확인
	public void empty() {
		if (top == null) {
			System.out.println(1);
		} else {
			System.out.println(0);
		}
	}//empty()
	
	//top메소드(peek) : top노드 데이터 읽기
	public void top() {
		if (top == null) {
			System.out.println("-1");
		} else {
			System.out.println(top.data);
		}
	}//top()
	
}

 

 

'Computer Science > Algorithm' 카테고리의 다른 글

[정렬] 퀵 정렬(Quick Sort)  (1) 2022.05.10
[자료구조] 큐(Queue)  (0) 2022.04.28
[검색] 선형탐색과 이진탐색  (0) 2022.04.12
[자바의 정석] 스택과 큐  (0) 2022.03.30
[자바의 정석] ArrayList/LinkedList  (0) 2022.03.29

■ 선형검색 : 정렬되지 않은 데이터를 0부터 끝까지 확인할 때 유리

- 의사코드

for i from 0 to n-1
  if i'th element is the target value
     return true
  return false

- 자바코드

package linearSearch;

import java.util.Arrays;

public class LinearSearch1 {

	public static void main(String[] args) {
		int[] arr = new int[10];
		init(arr);
		System.out.println(Arrays.toString(arr));
		
		//linear search
		//전제 : 정렬되지 않은 데이터
		//찾으려는 수 : 5
		for (int i = 0; i < arr.length; i++) {
			if (arr[i]==5) {
				System.out.println("index : "+i);
				break;
			}
		}
	}
	
	public static void init(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			arr[i] = (int)(Math.random()*arr.length)+1;
			for (int j = 0; j < i; j++) {
				if (arr[i]==arr[j]) {
					i--;
					break;
				}
			}
		}
	}
}

>> 결과

[9, 3, 6, 8, 1, 5, 7, 4, 2, 10]
index : 5

 

■ 이진검색 : 정렬된 데이터들 안에서 특정 데이터를 찾을 때 유리

- 의사코드

*찾고자 하는 값이 50일 때,

if middle item is 50
	return true
else if 50 < middle item
	search left half
else if 50 > middle item 
	search right half

- 수학적 논리 : 중앙값을 지정한 후, left~right의 범위를 줄여가면서 logN의 속도로 탐색을 하는 방법

- 자바 코드

package BasicSearch;

public class _01_BinarySearch {

	public static void main(String[] args) {
		int[] arr = new int[] {1,2,3,4,5,6,7,8,9,10};
		int key = 3;
		
		int mid;
		int left = 0;
		int right = arr.length-1;
		while(left<=right) {
			mid = (left+right)/2;
			
			if(key==arr[mid]) {
				System.out.println("index : "+mid);
				break;
			}
			
			if(key < arr[mid]) {
				right = mid-1;
			}else if(key > arr[mid]) {
				left = mid+1;
			}
		}//end while
	}//end main

}

>> 결과

index : 2

 

 

※ 참조 : 자료구조에 대한 정리

https://why-dev.tistory.com/6?category=917883 

 

[컴퓨터 공학_복습] 알고리즘 정의, 검색과 정렬 알고리즘

심플한 개발 [컴퓨터 공학_복습] 알고리즘 정의, 검색과 정렬 알고리즘 본문 컴퓨터공학 [컴퓨터 공학_복습] 알고리즘 정의, 검색과 정렬 알고리즘 심플한 개발 2022. 1. 26. 17:27 Prev 1 ··· 3 4 5 6 7 Ne

why-dev.tistory.com

 

1. 스택과 큐

https://www.youtube.com/watch?v=ktvhRSRohR4 

▶ 스택(Stack) : 밑이 막힌 상자

   - LIFO구조. Last in First Out / push(저장) & pop(추출) 방식

   - 배열이 적합   *순차적인 추가/삭제

▶ 큐(Queue)  : 양끝이 뚫린 상자(포장마차의 종이컵 빼는 것과 같다)

   - FIFO구조. First in First Out / otter(저장, 제공한다) & poll(추출) 

   - 링크드리스트가 적합   *비순차적인 추가/삭제

 

■ 스택의 메소드 **JAVA에서 스택은 클래스 (객체생성 가능)

push(Object) : Object  --- Stack객체에 item을 저장

pop( ) : Object      ---  맨 위의 것 꺼내기

empty( ) : boolean ---  비어있는지

peek(  )  : Object   ---  맨 위의 것 읽기 (꺼내지X)

search(Object) : int ---  맨 위에서 1부터시작해서 순서 반환 *못찾으면 -1 반환

 

■ 큐의 메소드  **JAVA에서 큐는 인터페이스 (객체생성 불가능)

offer(Object) : boolean  --- Queue 객체에 item을 저장(예외 발생X)

poll( ) : Object      ---  객체를 꺼내서 반환(예외 발생X)

peek(  )  : Object   ---  삭제 없이 요소 읽음(꺼내지X)

add(Object) : boolean  --- Queue 객체에 item을 저장(예외 발생O)

remove() : Object  ---  객체를 꺼내서 반환(예외 발생O)

   [ 큐 사용법]
   1. 큐를 직접 구현
   2. 큐를 구현한 클래스를 사용 >> Java API 중 Queue를 구현한 목록 확인 (LinkedList도 큐 구현)
      Queue q = new LinkedList();

 

1. ArrayList : 배열 기반 리스트

https://www.youtube.com/watch?v=_2e-cgwMOyc 

▶ Vector를 개선. *차이점) Vector는 동기화 가능/ ArrayList는 동기화X

▶ 생성자

ArrayList()  
ArrayList(Collection c) 컬렉션을 넣으면 배열리스트로 변경됨
ArrayList(int initalCapacity) 저장하려는 갯수만큼 길이 지정

* 저장갯수를 지정해주지 않으면 배열이 늘어나고 줄어들 때마다 배열이 새로 생성되기에 성능 떨어진다.

▶ 메소드

추가 삭제 검색 기타
add(Object o) : boolean
add(int index, Object element) 
addAll(컬렉션)
addAll(index, 컬렉션)
remove(Object o) : boolean
remove(int index)
removeAll(Collection c)
clear()
indexOf() : int  <- index
lastIndexOf() : int
contains()
get(int index) : Object
set(index, Object) : Object
subList()
toArray() : Object[]
isEmpty()
trimToSize() - 빈공간제거
size() - 갯수 반환

▶ ArrayList에서 객체를 추가하거나 삭제할 때 배열의 복사가 이루어질 수 있다.

    ★ 삭제할 때, Last in First Out 방식을 취할 경우, 배열 복사가 발생하지 않는다. (성능 ↑)

 

[예제 연습1]

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ArrayListEx2 {

	public static void main(String[] args) {
		final int LIMIT = 10;
		String source = "0123456789abcdefghijABCDEFGHIJ!@#$%^&*()ZZZ"; 
		int length = source.length(); 
		
		List list = new ArrayList(length/LIMIT+10);
		
		for(int i = 0; i < length; i+=LIMIT) {
			if(i+LIMIT < length)
				list.add(source.substring(i,i+LIMIT));
			else
				list.add(source.substring(i));
		}
		
		for(int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
		
	}//end main
}//end class

>> 결과

0123456789
abcdefghij
ABCDEFGHIJ
!@#$%^&*()
ZZZ

 

2. LinkedList 

https://www.youtube.com/watch?v=1ey5QpqbapU 

[배열의 장단점]

- 장점 : 배열의 구조가 간단하고, 데이터를 읽는데 걸리는 시간이 짧다. 

- 단점1 : (실행중) 크기를 변경할 수 없다. (크기를 변경할 경우 : 크기를 늘려 복사해서 참조변경)

         * 크기 변경을 피하기 위해 충분히 큰 배열을 생성하면, 메모리가 낭비됨

- 단점2 : 비순차적인(=중간에) 데이터의 추가, 삭제에 시간이 많이 걸린다. 

         * 데이터를 추가/삭제하려면 다른 데이터를 옮겨야함

         * 순차적인 데이터 추가(끝에 추가)와 삭제(끝부터 삭제)는 빠르다.

[LinkedList <- 배열의 단점을 보완]

- 배열과 달리, 링크드 리스트는 불연속적으로 존재하는 데이터를 연결

▶ 데이터의 삭제 : 단 한 번의 참조 변경으로 가능

▶ 데이터의 추가 : 한 번의 객체 생성과 두 번의 참조변경만으로 가능

- 단점 : 데이터 접근성이 나쁘다 (why? 노드들이 next로 하나씩 연결되어 있음)

- 개선한 것

▶ 더블리 링크드 리스트 : 이중 연결리스트 *하나의 노드에 next + previous

▶ 더블리 써큘러 링크드 리스트 : 이중원형 연결리스트 *첫번째->맨끝 / 맨끝->첫번째 연결

- 자바는 더블리 링크드 리스트를 사용한다.

 

ArrayList vs LinkedList 비교

그림으로 보는 ArrayList와 LinkedList의 비교

  특징 읽기(접근시간) 추가/삭제 비고
ArrayList 연속적 빠르다 느리다 순차적인 추가삭제는 더 빠르다.
비효율적인 메모리사용
LinedList 불연속 느리다 빠르다 데이터가 많을수록 접근성이 떨어진다.

 

+ Recent posts