数据结构学习笔记(一) 基础数据结构

本文详细解析了数组、链表和哈希表在运行时间和空间复杂度上的特点,比较了插入、查找和删除操作的效率,并介绍了如何利用它们实现栈、队列和优先级队列。核心话题包括Big O分析,数据结构选择指导,以及面试中可能涉及的相关问题。
摘要由CSDN通过智能技术生成

Date Structure Note Part.1

Big O notation: Runtime Complexity

  1. O(1): constance
  2. O(n): related to the input size
  3. O(n^2): O(n * n) very slow
  4. O(log n): very fast
  5. O(2^n): very very slow

Sort: O(1) > O(log n) > O(n) > O(n^2) > O(2^n)

Space complexity

  1. O(1) : constance
  2. O(n): related to the input size

Lists

Arrays

operation
  1. Lookup by Index: O(1)
  2. Lookup by Value: O(n)
  3. Insert: O(n)
  4. Delete: O(n)

Build an Array

package Arrays;

public class Main {
  public static void main(String[] args) {
    Array numbers = new Array(3);
    numbers.insert(10);
    numbers.insert(20);
    numbers.insert(30);
    numbers.insert(40);
    numbers.removeAt(3);
    System.out.println(numbers.indexOf(100));

  }
}
package Arrays;

public class Array {
  private int[] array;
  private int lastIndex = -1;

  public Array(int length) {
    array = new int[length];
  }

  public void insert(int item) {
    if (lastIndex + 1 >= array.length) resize();

    array[++lastIndex] = item;
  }

  public int removeAt(int index) {
    if (index > lastIndex) return -1;

    int result = array[index];

    for (int i = index + 1; i <= lastIndex; i++)
      array[i - 1] = array[i];
    lastIndex--;

    return result;
  }

  public int indexOf(int item) {
    for (int i = 0; i <= lastIndex; i++)
      if (array[i] == item) return i;

    return -1;
  }

  private void resize() {
    int[] newArray = new int[array.length * 2];

    // O(n)
    for (int i = 0; i < array.length; i++)
      newArray[i] = array[i];

    array = newArray;
  }
}

LinkedList

Overview of Linked Lists
  1. view: Head -> Node -> … -> Tail
  2. Structure: Value nextNode
Runtime Complexity
  1. Insert: At the End: O(1); At the Beginning: O(1); In the Middle: O(n);
  2. Delete: From the End: O(n); From the Beginning: O(1); From the Middle: O(n);
Build a Linked List
package Arrays;

public class Main {
  public static void main(String[] args) {
    LinkedList numbers = new LinkedList();
    numbers.addFirst(10);
    numbers.addFirst(20);
    numbers.addFirst(30);
    numbers.addFirst(40);
    numbers.deleteFirst();
    System.out.println(numbers.toString());
    System.out.println(numbers.indexOf(100));
  }
package LinkedList;

import java.util.Arrays;
import java.util.NoSuchElementException;

public class LinkedList {
  private class Node {
    private int value;
    private Node next;

    public Node(int value) {
      this.value = value;
    }
  }

  private Node first;
  private Node last;
  private int size = 0;

  public void addFirst(int item) {
    if (isEmpty()) first = last = new Node(item);
    else {
      Node node = new Node(item);
      node.next = first;
      first = node;
    }

    size++;
  }

  public void addLast(int item) {
    if (isEmpty()) first = last = new Node(item);
    else {
      Node node = new Node(item);
      last.next = node;
      last = node;
    }

    size++;
  }

  public void deleteFirst() {
    if (isEmpty()) throw new NoSuchElementException();

    if (size == 1)
      first = last = null;
    else {
      Node temp = first;
      first = first.next;
      temp.next = null;
    }

    size--;
  }

  public void deleteLast() {
    if (isEmpty()) throw new NoSuchElementException();

    if (size == 1)
      first = last = null;
    else {
      Node previous = getPrevious(last);
      last = previous;
      previous.next = null;
    }

    size--;
  }

  private Node getPrevious(Node node) {
    Node current = first;
    while (current != null && current.next != node)
      current = current.next;

    return null;
  }

  public int indexOf(int item) {
    int index = -1;
    Node current = first;
    for (int i = 0; i < size; i++) {
      if (current.value == item) index = i;
      current = current.next;
    }

    return index;
  }

  public boolean contains(int item) {
    return indexOf(item) != -1;
  }

  public int size() {
    return size;
  }


  public boolean isEmpty() {
    return first == null || last == null;
  }

  @Override
  public String toString() {
    Node current = first;
    int[] output = new int[size];

    for (int i = 0; i < size; i++) {
      output[i] = current.value;
      current = current.next;
    }

    return Arrays.toString(output);
  }
}

Array VS LinkedList

Quick
  1. Static arrays have a fixed size
  2. Dynamic arrays grow by 50-100%
  3. Linked lists don’t waste memory
  4. Use arrays if you know the number of items to store
  5. new ArrayList(100)
Compare runtime complexity

Lookup Arrays LinkedList

By Index O(1) O(n)

By Value O(n) O(n)

Insert

Beginning/End O(n) O(1)

Middle O(n) O(n)

Delete

Beginning O(n) O(1)

Middle O(n) O(n)

End O(n) O(n)/O(1) -> double linked list

Interview Question
  1. Reverse a linked list. (three pointer)

    eg. [10, 20, 30] -> [30, 20, 10]

public void reverse() {
  if (isEmpty()) return;

  Node previous = first;
  Node current = first.next;
  while (current != null) {
    Node next = current.next;
    current.next = previous;
    previous = current;
    current = next;
  }

  last = first;
  last.next = null;
  first = previous;
}
  1. Find the Kth node from the end of a linked list in one pass. (two pointer)

    eg. [10, 20, 30, 40, 50] k=1(50); k=2(40)…

public int getKthFromTheEnd(int k) {
  int distance = k - 1;
  if (distance > size || k <= 0) throw new IllegalArgumentException();

  Node left = first, right = first;
  for (int i = 0; i < distance; i++)
    right = right.next;

  while (right.next != null) {
    left = left.next;
    right = right.next;
  }

  return left.value;
}

Stack

What can use for

  1. Implement the undo feature
  2. Build compilers
  3. Evaluate expressions
  4. Build navigation

Feature: LIFO (Last in First out)

Operations

  1. push(item) O(1)
  2. pop() O(1)
  3. peek() O(1)
  4. isEmpty() O(1)

Interview Question

  1. Reversing a sting. (implement by stack)

    eg. “abcd” -> “dcba”

public String reverse(String str) {
  if (str == null) throw new IllegalArgumentException();
  Stack<Character> stack = new Stack<>();
  StringBuilder stringBuilder = new StringBuilder();

  for (char ch : str.toCharArray())
    stack.add(ch);

  while (!stack.isEmpty())
    stringBuilder.append(stack.pop());

  return stringBuilder.toString();
}
  1. Is string balanced.

    eg. “(1 + 1)” is balance; "(1 + " is not balance.

public static boolean isbalanced(String input) {
  if (input == null) throw new IllegalArgumentException();

  Stack<Character> leftBrace = new Stack<>();
  Stack<Character> rightBrace = new Stack<>();
  for (char ch : input.toCharArray())
    if (
        ch == '{' ||
        ch == '[' ||
        ch == '(' ||
        ch == '<' ||
        ch == '>' ||
        ch == ')' ||
        ch == ']' ||
        ch == '}')
      leftBrace.push(ch);

  while (!leftBrace.isEmpty()) {
    char ch = leftBrace.peek();
    if (
        ch == '>' ||
        ch == ')' ||
        ch == ']' ||
        ch == '}') {
      rightBrace.add(leftBrace.pop());
      continue;
    }

    if (ch == '<')
      if (rightBrace.isEmpty() || rightBrace.peek() != '>')
        return false;
    if (ch == '(')
      if (rightBrace.isEmpty() || rightBrace.peek() != ')')
        return false;
    if (ch == '[')
      if (rightBrace.isEmpty() || rightBrace.peek() != ']')
        return false;
    if (ch == '{')
      if (rightBrace.isEmpty() || rightBrace.peek() != '}')
        return false;
    rightBrace.pop();
    leftBrace.pop();
  }

  return rightBrace.isEmpty();
}
private final List<Character> leftBrackets = Arrays.asList('{', '[', '(', '<');
private final List<Character> rightBrackets = Arrays.asList('}', ']', ')', '>');

public boolean isbalanced(String input) {
  Stack<Character> stack = new Stack<>();

  for (char ch : input.toCharArray()) {
    if (isLeftBracket(ch))
      stack.push(ch);

    if (isRightBracket(ch)) {
      if (stack.empty()) return false;
      
      char top = stack.pop();
      if (bracketsMatch(top, ch)) return false;
    }
  }
  
  return true;
}

private boolean isLeftBracket(char ch) {
  return leftBrackets.contains(ch);
}  

private boolean isRightBracket(char ch) {
  return rightBrackets.contains(ch);
}

private boolean bracketsMatch(char left, char right) {
  return leftBrackets.indexOf(left) == rightBrackets.indexOf(right);
}

Build a Stack

import Stack.Stack;

public class Main {
  public static void main(String[] args) {
    Stack stack = new Stack();
    stack.push(1);
    stack.push(2);
    stack.push(3);
    stack.push(4);
    stack.push(5);
    int res = stack.pop();
    System.out.println(res);
    System.out.println(stack);
  }
}
package Stack;

import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack {
  private int[] items;
  private int count = 0;

  public Stack() {
    items = new int[10];
  }

  public void push(int item) {
    if (count == items.length) throw new StackOverflowError();
    items[count++] = item;
  }


  public int pop() {
    if (count == 0) throw new EmptyStackException();
    return items[--count];
  }

  public int peek() {
    if (count == 0) throw new EmptyStackException();
    return items[count - 1];
  }

  public boolean isEmpty() {
    return count == 0;
  }

  @Override
  public String toString() {
    int[] content = Arrays.copyOfRange(items, 0, count);
    return Arrays.toString(content);
  }
}

Queues

What can use for

  1. resources management
  2. printers
  3. operating systems
  4. web serbers
  5. live support systems

Feature: FIFO (First in First out)

Operations

  1. enqueue O(1) \ PriorityQueue: enqueue O(n)
  2. dequeue O(1)
  3. peek O(1)
  4. isEmpty O(1)
  5. isFull O(1)

Interview Question

  1. reverse a queue. (only allow using add\remove\isEmpty)
public void reverse(Queue<Integer> queue) {
  Stack<Integer> stack = new Stack<>();
  while (!queue.isEmpty())
    stack.push(queue.remove());
  while (!stack.isEmpty())
    queue.add(stack.pop());
}
  1. using two stack build a queue
package Queue;

import java.util.Stack;

public class StackQueue {
  private Stack<Integer> enqueue = new Stack<>();
  private Stack<Integer> dequeue = new Stack<>();

  public void add(int item) {
    enqueue.add(item);
  }

  public int remove() {
    if (isEmpty()) throw new IllegalStateException();
    moveEnqueueStackToDequeueStack();

    return dequeue.pop();
  }  
  
  public int peek() {
    if (isEmpty()) throw new IllegalStateException();
    moveEnqueueStackToDequeueStack();

    return dequeue.peek();
  }

  private void moveEnqueueStackToDequeueStack() {
    if (dequeue.isEmpty())
      while (!enqueue.isEmpty())
        dequeue.add(enqueue.pop());
  }

  private boolean isEmpty() {
    return enqueue.isEmpty() && dequeue.isEmpty();
  }
}

Build a Queue

package Queue;

import java.util.Arrays;

public class ArrayQueue {
  private int[] items = new int[5];
  private int front = 0;
  private int rear = 0;
  private int count;

  public void enqueue(int item) {
    if (isFull()) throw new IllegalStateException();

    items[rear] = item;
    rear = (rear + 1) % items.length;
    count++;
  }

  public int dequeue() {
    int item = items[front];
    items[front++] = 0;
    front = (front + 1) % items.length;
    count--;
    return item;
  }

  public int peek() {
    return items[front];
  }

  public boolean isEmpty() {
    return count == 0;

  }

  public boolean isFull() {
    return count == items.length;
  }

  @Override
  public String toString() {
    return Arrays.toString(items);
  }
}

Build a Priority Queue (Default: min Heap)

package Queue;

import java.util.Arrays;

public class PriorityQueue {
  private int[] items = new int[5];
  private int count;

  public void add(int item) {
    if (isFull()) throw new IllegalStateException();

    if (isEmpty()) {
      items[count++] =  item;
      return;
    }

    int i = shiftItemsToInsert(item);
    items[i] = item;
    count++;
  }

  private int shiftItemsToInsert(int item) {
    int i;
    for (i = count - 1; i >= 0; i--) {
      if (item < items[i])
        items[i + 1] = items[i];
      else
        break;
    }

    return i + 1;
  }

  public int remove() {
    if (isEmpty()) throw new IllegalStateException();

    return items[--count];
  }

  private boolean isEmpty() {
    return count == 0;
  }

  private boolean isFull() {
    return count == items.length;
  }

  @Override
  public String toString() {
    return Arrays.toString(items);
  }
}

Hash Tables

What can use for

  1. Spell checkers
  2. Dictionaries
  3. Compilers
  4. Code editors

Operations

  1. Insert O(1)
  2. Lookup O(1)
  3. Delete O(1)

Interview Question

  1. Find the first none repeated character.

    eg. “A Green Apple” -> ‘G’

public static char findTheFirstNoneRepeatedCharacter(String str) {
  str = str.toLowerCase();
  Map<Character, Integer> dic = new HashMap<>();

  char[] chars = str.toCharArray();
  for (char ch : chars) {
    if (!dic.containsKey(ch)) dic.put(ch, 1);
    else dic.put(ch, dic.get(ch) + 1);
  }

  for (char ch : chars)
    if (dic.get(ch) == 1) return ch;

  return ' ';
}

public static char findTheFirstNoneRepeatedCharacter2(String str) {
  if (str == null || str.trim() == "") return ' ';

  String copy = str.toLowerCase();
  Set<Character> repeated = new HashSet<>();
  int left = 0, right = 1;
  while (right < copy.length() && left < right) {
    if (copy.charAt(left) == ' ') left++;
    if (copy.charAt(left) != copy.charAt(right)) right++;
    else repeated.add(copy.charAt(left++));
  }

  return left < copy.length()
      && !repeated.contains(copy.charAt(left))
      ? copy.charAt(left)
      : ' ';
}
  1. Find the first repeated character.

    eg. “green apple” -> ‘e’

public static char findTheFirstRepeatedChar(String str) {
  Set<Character> repeated = new HashSet<>();
  Set<Character> noneRepeated = new HashSet<>();
  char[] chars = str.toLowerCase().toCharArray();
  for (char ch : chars) {
    if (!noneRepeated.contains(ch)) noneRepeated.add(ch);
    else repeated.add(ch);
  }

  for (char ch : chars)
    if (repeated.contains(ch)) return ch;

  return ' ';
}

Hash Function

  1. “1234” -> 10
  2. If the array size is 5, then mod the result by 5, and we get 0;
  3. “1234” -> 0;

Collisions

When input two different keys, but we get the same address.

​ eg. Key1->O->address<-O<-Key2

Solution:

  1. Channing: eg. Address: 🔢->Key1->Key2
  2. Open Addressing:
    1. Linear Probing: (hash(key) + i) % table_size
    2. Quadratic Probing: (hash(key) + i^2) % table_size
    3. Double Hashing:
      1. hash2(key) = prime - (key % prime);
      2. index = (hash1(key) + i * hash2(key)) % table_size;

Build a Hash Table

import HashTable.HashTable;

public class Main {
  public static void main(String[] args) {
    HashTable dic = new HashTable();
    dic.put(6, "b");
    dic.put(1, "a");
    System.out.println(dic.get(1));
  }
}
package HashTable;

import java.util.LinkedList;

public class HashTable {
  private class Entry {
    private int key;
    private String value;

    public Entry(int key, String value) {
      this.key = key;
      this.value = value;
    }
  }

  private LinkedList<Entry>[] entries = new LinkedList[5];

  public void put(int key, String value) {
    Entry entry = getEntry(key);
    if (entry != null) {
      entry.value = value;
      return;
    } 

    getOrCreateBucket(key).add(new Entry(key, value));
  }

  private int hash(int key) {
    return key % entries.length;
  }

  public String get(int key) {
    Entry entry = getEntry(key);
    return entry == null ? null : entry.value;
  }

  public void remove(int key) {
    Entry entry = getEntry(key);
    if (entry == null) throw new IllegalStateException();

    getBucket(key).remove(entry);
  }

  private Entry getEntry(int key) {
    int index = hash(key);
    LinkedList<Entry> bucket = entries[index];
    if (bucket != null)
      for (Entry entry : bucket)
        if (entry.key == key)
          return entry;
    
    return null;
  }

  private LinkedList<Entry> getBucket(int key) {
    return entries[hash(key)];
  }
  
  private LinkedList<Entry> getOrCreateBucket(int key) {
    int index = hash(key);
    LinkedList<Entry> bucket = entries[index];
    if (bucket == null) entries[index] = new LinkedList<>();
    
    return bucket;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值