Algorithm & Data Structures/Data Structures

โœ๏ธ ๋‚ด ์ฝ”๋“œ๊ฐ€ ๋А๋ ธ๋˜ ์ด์œ : LinkedList๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฐ”๊พธ๊ณ  ์ƒ๊ธด ์ผ

Geisha 2025. 4. 16. 18:05

 

 

๐Ÿฃ ์‹œ์ž‘์€ ์ฝ”๋“œ ๋น„๊ต์—์„œ

 

์ตœ๊ทผ์— ๋ฐฑ์ค€ 14002๋ฒˆ: ๊ฐ€์žฅ ๊ธด ์ฆ๊ฐ€ํ•˜๋Š” ๋ถ€๋ถ„ ์ˆ˜์—ด 5 ๋ฌธ์ œ๋ฅผ ํ’€๋‹ค๊ฐ€,

๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ํ’€์ด์™€ ๋‚ด ํ’€์ด ์‚ฌ์ด์—์„œ ์†๋„ ์ฐจ์ด๊ฐ€ ์œ ๋… ํฌ๊ฒŒ ๋‚˜๋Š” ๊ฑธ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

๋กœ์ง์€ ๊ฐ™์•˜๋‹ค.

LIS(Longest Increasing Subsequence) ๊ตฌํ•˜๊ณ , ์‹ค์ œ ์ˆ˜์—ด์„ ์—ญ์ถ”์ ํ•ด์„œ ์ถœ๋ ฅํ•œ๋‹ค.

 

๊ทธ๋Ÿฐ๋ฐ ๋‚˜๋Š” ์ด๋ ‡๊ฒŒ ์ผ๋‹ค:

LinkedList<Integer> result = new LinkedList<>();
while (idx != -1) {
    result.addFirst(arr[idx]);
    idx = prev[idx];
}

๋ฐ˜๋ฉด, ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ์ฝ”๋“œ๋Š” ์ด๋ ‡๊ฒŒ ๋ฐฐ์—ด๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์—ˆ๋‹ค:

int[] result = new int[length];
int pos = length - 1;
while (idx != -1) {
    result[pos--] = arr[idx];
    idx = prev[idx];
}
๐Ÿค” ์ฝ”๋“œ ์ฐจ์ด? ๋‹จ์ˆœํžˆ addFirst()๋ƒ, ๋ฐฐ์—ด ์ธ๋ฑ์Šค๋ƒ.
๊ทธ๋Ÿฐ๋ฐ ์‹คํ–‰ ์†๋„๋Š”… ์ฐจ์›์ด ๋‹ฌ๋ž๋‹ค!

 

๐Ÿ” ๊ถ๊ธˆ์ฆ: ์™œ ์ด๋ ‡๊ฒŒ ๋А๋ฆฌ์ง€?

 

์ฒ˜์Œ์—” ์˜์•„ํ–ˆ๋‹ค.

LinkedList.addFirst()๋Š” O(1)์ธ๋ฐ? → ๊ทผ๋ฐ ์™œ ๋А๋ฆด๊นŒ?

 


๐Ÿ“ฆ ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€์ ์—์„œ ๋ถ„์„ํ•ด๋ณด์ž

 

 

1. ๐Ÿงฑ ๋ฐฐ์—ด (Array)

 

  • ์—ฐ์†๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์— ์ €์žฅ๋จ
  • ํŠน์ • ์ธ๋ฑ์Šค๋กœ์˜ ์ ‘๊ทผ์ด O(1)
  • CPU ์บ์‹œ ์ ์ค‘๋ฅ ์ด ๋†’์Œ → ์†๋„ ๋น ๋ฆ„

 

๐Ÿ’ก ๊ณ ์†๋„๋กœ์ฒ˜๋Ÿผ ๋‹ฌ๋ฆผ. ๋ฐฐ์—ด[1000000] ํ•ด๋„ ์ฆ‰์‹œ ๋„์ฐฉ.

 

2. ๐Ÿ”— LinkedList

 

  • ๊ฐ ๋…ธ๋“œ๋Š” ๊ฐ’ + ๋‹ค์Œ ๋…ธ๋“œ ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง
  • ๋ฉ”๋ชจ๋ฆฌ์ƒ์— ํฉ์–ด์ ธ ์žˆ์Œ → ์ ‘๊ทผ ์‹œ ์ฐธ์กฐ ๋”ฐ๋ผ๊ฐ€์•ผ ํ•จ
  • ํฌ์ธํ„ฐ ์—ฐ๊ฒฐ ๋•Œ๋ฌธ์— GC์™€ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๋ถ€ํ•˜ ์žˆ์Œ

 

๐Ÿ’ก ์ง‘์ง‘๋งˆ๋‹ค ๋ฐฉ๋ฌธํ•˜๋Š” ํƒ๋ฐฐ์ฐจ ๋А๋‚Œ. ๋А๋ฆผ.

 

 

3. ๐Ÿ’ฃ addFirst()์˜ ์‹ค์ฒด

result.addFirst(value); // O(1)

์ด๋ก ์ƒ O(1)์ด์ง€๋งŒ ํ˜„์‹ค์€ ๋‹ค๋ฆ„.

 

  • ๊ฐ์ฒด ์ƒ์„ฑ (Node)
  • ํฌ์ธํ„ฐ ๋ณ€๊ฒฝ
  • ํž™์— ํฉ์–ด์ง„ ๊ตฌ์กฐ
  • GC ํŠธ๋ž˜ํ‚น ๋ถ€๋‹ด

 

๐Ÿ’ฅ ๋ฐ˜๋ณต๋˜๋ฉด ์บ์‹œ๋„ ์•ˆ ๋จน๊ณ , ์ฐธ์กฐ ๋ถ€ํ•˜๋„ ์Œ“์ด๊ณ , ๊ฒฐ๊ตญ ๋А๋ ค์ง.
โš ๏ธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์ฐจ์ด๋Š” ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ์ปค์ง„๋‹ค.

 

 

 

โœ… ๊ฒฐ๋ก : ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์ง€๊ณ  ๋ณ€๊ฒฝ์ด ์—†๋‹ค๋ฉด ๋ฐฐ์—ด์ด ํ›จ์”ฌ ์œ ๋ฆฌ

๋น„๊ต ํ•ญ๋ชฉ Array LinkedList
๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ ์—ฐ์†์  ๋น„์—ฐ์† (ํฌ์ธํ„ฐ ๊ธฐ๋ฐ˜)
์ ‘๊ทผ ๋ฐฉ์‹ ์ง์ ‘ ์ธ๋ฑ์‹ฑ (๋น ๋ฆ„) ์ฐธ์กฐ ๋”ฐ๋ผ๊ฐ€๊ธฐ (๋А๋ฆผ)
์บ์‹œ ํšจ์œจ ๋†’์Œ ๋‚ฎ์Œ
GC ์˜ํ–ฅ ์ ์Œ ํผ
๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ๊ฐ•๋ ฅ ์ถ”์ฒœ ์ง€์–‘

 


๐Ÿงฉ ๊ทธ๋ ‡๋‹ค๋ฉด LinkedList๋Š” ์–ธ์ œ ์“ฐ๋Š” ๊ฒŒ ์ข‹์„๊นŒ?

 

์•ž์—์„œ๋Š” LinkedList.addFirst() ๋•Œ๋ฌธ์— ์ƒ๊ธด ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์‚ฌ๋ก€๋กœ ๋ณด์—ฌ์ฃผ๋ฉฐ,

LinkedList์˜ ๊ตฌ์กฐ์  ํ•œ๊ณ„์— ๋Œ€ํ•ด ๋‹ค๋ค˜๋‹ค.

 

๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ “LinkedList๋Š” ์ ˆ๋Œ€ ์“ฐ๋ฉด ์•ˆ ๋˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์•ผ!” ๋ผ๋Š” ๊ฑด ์•„๋‹ˆ๋‹ค.

LinkedList๋„ ๋ถ„๋ช… ๋ฐฐ์—ด๋กœ๋Š” ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฌธ์ œ๋“ค์— ํŠนํ™”๋˜์–ด ์žˆ๋‹ค.


 

๐Ÿ›  LinkedList์˜ ๊ฐ•์ ์€?

1. ๐Ÿงท ์ค‘๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ๊ฐ€ ์žฆ์„ ๋•Œ

 

๋ฐฐ์—ด์€ ์ค‘๊ฐ„ ์š”์†Œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ๋•Œ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋’ค๋กœ ๋ฐ€๊ฑฐ๋‚˜ ๋‹น๊ฒจ์•ผ ํ•œ๋‹ค.

// ๋ฐฐ์—ด์—์„œ ์ธ๋ฑ์Šค 2์— ์‚ฝ์ž…
for (int i = size; i > 2; i--) {
    arr[i] = arr[i - 1]; // ๋’ค๋กœ ๋ฐ€๊ธฐ
}

→ O(N) ์‹œ๊ฐ„ ์†Œ์š”

๋ฐ์ดํ„ฐ ํฌ๊ณ  ์ค‘๊ฐ„ ์ˆ˜์ • ๋งŽ์œผ๋ฉด ์น˜๋ช…์ 

 

๐Ÿ“Œ ๋ฐ˜๋ฉด LinkedList๋Š” ๋…ธ๋“œ ๊ฐ„ ์—ฐ๊ฒฐ๋งŒ ๋ฐ”๊พธ๋ฉด ๋˜๋ฏ€๋กœ:

node.prev.next = newNode;
newNode.prev = node.prev;
newNode.next = node;
node.prev = newNode;

→ O(1) ์‚ฝ์ž…/์‚ญ์ œ ๊ฐ€๋Šฅ

→ ์ฆ‰, ์ค‘๊ฐ„ ์กฐ์ž‘์ด ๋งŽ์„ ๋•Œ ์œ ๋ฆฌ

 

 

2. ๐Ÿ“š ๋ฐ์ดํ„ฐ ํฌ๊ธฐ๊ฐ€ ์œ ๋™์ ์ผ ๋•Œ

๋ฐฐ์—ด์€ ๊ณ ์ •๋œ ํฌ๊ธฐ๋กœ ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์—, ํฌ๊ธฐ ์กฐ์ •์ด ํ•„์š”ํ•˜๋ฉด ๋ณต์‚ฌ ๋น„์šฉ์ด ๋ฐœ์ƒํ•จ.

int[] newArr = new int[arr.length * 2];
System.arraycopy(arr, 0, newArr, 0, arr.length);

๋ฐ˜๋ฉด, LinkedList๋Š” ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํฌ๊ธฐ ์กฐ์ • ๋น„์šฉ์ด ์—†์Œ.

 

3. ๐ŸŽฏ ์„ ํ˜• ํƒ์ƒ‰ ๊ธฐ๋ฐ˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ์œ ๋ฆฌํ•  ๋•Œ

 

  • ์˜ˆ: ๊ตฌํ˜„ ๋ฌธ์ œ์—์„œ ๋ฑ(Deque) ํ˜•ํƒœ๋กœ ์•ž๋’ค๋กœ ์›์†Œ๋ฅผ ์ถ”๊ฐ€/์‚ญ์ œํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ
  • Queue, Deque, Stack ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•  ๋•Œ

 

Java์—์„œ LinkedList๋Š” Deque ์ธํ„ฐํŽ˜์ด์Šค๋„ ๊ตฌํ˜„ํ•˜๋ฏ€๋กœ, ์–‘๋ฐฉํ–ฅ ํ๋กœ์„œ ์•„์ฃผ ์œ ์šฉํ•จ:

Deque<Integer> deque = new LinkedList<>();
deque.addFirst(1);
deque.addLast(2);
deque.pollFirst(); // 1
deque.pollLast();  // 2

→ ๋ฐฐ์—ด๋กœ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ArrayDeque์ด ๋” ๋‚ซ์ง€๋งŒ,

๊ธฐ๋Šฅ ๊ตฌํ˜„ ํ…Œ์ŠคํŠธ๋‚˜, ์ธํ„ฐํŽ˜์ด์Šค ์ค‘์‹ฌ ์ฝ”๋“œ์—์„œ๋Š” LinkedList๋„ ๊ฐ•์  ์žˆ์Œ

 


๐Ÿ” ์ •๋ฆฌ: LinkedList vs Array

์ƒํ™ฉ์ถ”์ฒœ ์ž๋ฃŒ๊ตฌ์กฐ

์š”์†Œ ์ ‘๊ทผ์ด ๋งŽ๋‹ค (get(i)) ๋ฐฐ์—ด (Array)
์ค‘๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ๊ฐ€ ๋งŽ๋‹ค LinkedList
๋ฐ์ดํ„ฐ ํฌ๊ธฐ๊ฐ€ ๊ณ„์† ๋ณ€ํ•œ๋‹ค LinkedList
๋Œ€๋Ÿ‰์˜ ์›์†Œ ์ฒ˜๋ฆฌ (์„ฑ๋Šฅ ์ค‘์š”) ๋ฐฐ์—ด
์•ž๋’ค๋กœ ์ถ”๊ฐ€/์‚ญ์ œ๋งŒ ํ•œ๋‹ค ArrayDeque or LinkedList (์ž‘์€ ๋ฐ์ดํ„ฐ์ผ ๋•Œ๋Š” ํฐ ์ฐจ์ด ์—†์Œ)

 

 

 

โœ… ํ•œ ์ค„ ์š”์•ฝ

 

๋ฐฐ์—ด์€ ์ฝ๊ณ  ์“ธ ๋•Œ ๋น ๋ฅด๊ณ , LinkedList๋Š” ์ค‘๊ฐ„์—์„œ ์œ ์—ฐํ•˜๋‹ค.
์ƒํ™ฉ์— ๋”ฐ๋ผ ์“ฐ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ๋‹ฌ๋ผ์ ธ์•ผ ํ•œ๋‹ค.

 

 

๐ŸŽ ๋งˆ๋ฌด๋ฆฌ

 

์ด๋ฒˆ ๊ฒฝํ—˜์„ ํ†ตํ•ด ํ•˜๋‚˜ ๋” ํ™•์‹คํžˆ ๋ฐฐ์šด ๊ฑด,

“์ž๋ฃŒ๊ตฌ์กฐ๋Š” ๋„๊ตฌ๋‹ค. ๋„๊ตฌ๋Š” ์šฉ๋„์— ๋งž๊ฒŒ ์จ์•ผ ์ง„์งœ ๊ฐ’์ด ๋‚œ๋‹ค.” ๋Š” ์ ์ด๋‹ค.

 

LinkedList๋Š” ๋А๋ฆด ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋•Œ๋กœ๋Š” ๋ฐฐ์—ด๋กœ๋Š” ๊ตฌํ˜„์ด ๋ฒˆ๊ฑฐ๋กœ์šด ๋ฌธ์ œ๋ฅผ

๊ฐ„๋‹จํ•˜๊ฒŒ ํ’€ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ๋‹ค. ์„ฑ๋Šฅ๋งŒ ๋ณผ ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ตฌํ˜„์˜ ํŽธ์˜์„ฑ, ์š”๊ตฌ๋˜๋Š” ๊ธฐ๋Šฅ, ์œ ์—ฐ์„ฑ๊นŒ์ง€ ๊ณ ๋ คํ•ด์„œ

์ ์ ˆํ•œ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒŒ ์ง„์งœ ๊ฐœ๋ฐœ์ž์˜ ์„ผ์Šค๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.