讀書筆記知識導航
源代碼查閱方便
這裏的代碼與JDK的實現還相差甚遠,只能算作算法/數據結構的實現思路展示,很多細節沒考慮...
目錄
0. 思維導圖
1. 代碼導航
數據結構可以分爲物理結構
,邏輯結構
,所以這裏分兩個包,一個是phy
,一個是logic
;邏輯結構又分爲幾大類,如隊列,棧,樹
2. 數組(Array)
public class Array {
private int[] data;
private int size;
private final static int DEFAULT_SIZE = 10;
public Array() {
this(DEFAULT_SIZE);
}
public Array(int capacity) {
if(size < 0) {
throw new IllegalArgumentException("Capacity must be >= 0");
}
data = new int[capacity];
}
public Array(int[] data) {
Objects.requireNonNull(data);
this.data = new int[data.length];
while(size < data.length) {
this.data[size] = data[size++];
}
}
public int get(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
return data[index];
}
public void set(int index, int elem) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
data[index] = elem;
}
public int size() {
return size;
}
/**
* Insert element into SArray
* Time Complexity: O(N)
*
* index
* ↓
* | j | k | ... | z |
*
* | | j | k | ... | z |
* @param index
* @param elem
*/
public void insert(int index, int elem) {
if(index < 0 || index > size) {
throw new IndexOutOfBoundsException();
}
// 先判斷是否可擴容
if(size >= data.length) {
resize();
}
// 移動元素位置
int i = size;
while(i > index) {
data[i] = data[--i];
}
data[i] = elem;
size++;
}
/**
* Time Complexity: O(N)
*
* index
* ↓
* | j | k | ... | z |
*
* @param index
* @return
*/
public int remove(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
int retData = data[index];
while(index <= size-2) {
data[index] = data[++index];
}
size--;
return retData;
}
private void resize() {
// 擴容爲兩倍
int[] newData = new int[size << 1];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
@Override
public String toString() {
int[] arr = new int[size];
System.arraycopy(data, 0, arr, 0, size);
return Arrays.toString(arr);
}
/**
* 測試數據結構SArray
* @param args
*/
public static void main(String... args) {
Array array = new Array();
array.insert(0, 3);
array.insert(1, 7);
array.insert(2, 9);
array.insert(3, 5);
array.insert(1, 6);
array.remove(1);
System.out.println(array);
}
}
3. 鏈表
public class LinkedList {
private Node head;
private Node last;
private int size;
public LinkedList() { }
public LinkedList(int[] data) {
Objects.requireNonNull(data);
Node p = head = new Node(data[size++]);
while(size < data.length) {
p.next = new Node(data[size++]);
p = p.next;
}
}
public Node get(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
Node node = head;
for(int i = 0 ; i < index ; i++) {
node = node.next;
}
return node;
}
public void insert(int index, int elem) {
if(index < 0 || index > size) {
throw new IndexOutOfBoundsException();
}
Node insertedNode = new Node(elem);
if(size == 0) {
// 插入第一個
head = last = insertedNode;
} else if(index == 0) {
// 首部插入
insertedNode.next = head;
head = insertedNode;
} else if(index == size) {
// 尾部插入
last.next = insertedNode;
last = insertedNode;
} else {
// 插中間節點
Node prev = get(index-1);
insertedNode.next = prev.next;
prev.next = insertedNode;
}
size++;
}
public int remove(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
Node removedNode = null;
if(index == 0) {
// 刪除頭
removedNode = head;
head = head.next;
} else if(index == size-1) {
// 刪除尾
Node prev = get(index-1);
removedNode = prev.next;
prev.next = null;
last = prev;
} else {
// 刪除中間節點
Node prev = get(index-1);
removedNode = prev.next;
prev.next = removedNode.next;
removedNode.next = null;
}
size--;
return removedNode.data;
}
public int size() {
return size;
}
private static class Node {
int data;
Node next;
Node() { }
Node(int data) {
this.data = data;
}
}
@Override
public String toString() {
Array sArray = new Array();
Node node = head;
for(int i = 0 ; node != null ; i++, node = node.next) {
sArray.insert(i, node.data);
}
return sArray.toString();
}
/**
* 測試數據結構SLinkedList
* @param args
*/
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.insert(0, 3);
linkedList.insert(1, 7);
linkedList.insert(2, 9);
linkedList.insert(3, 5);
linkedList.insert(1, 6);
linkedList.remove(0);
System.out.println(linkedList);
}
}
4. 棧(Stack)
4.1 ArrayStack
用數組實現的棧結構,這裏的棧結構,我們使用上文已經定義過的Array
public class ArrayStack {
private Array stack;
public ArrayStack() {
stack = new Array();
}
public ArrayStack(int capacity) {
stack = new Array(capacity);
}
public void push(int elem) {
stack.insert(stack.size(), elem);
}
public int pop() {
int ret;
try{
ret = stack.remove(stack.size()-1);
} catch (Exception e) {
throw new EmptyStackException();
}
return ret;
}
public static void main(String[] args) {
ArrayStack stack = new ArrayStack();
System.out.print("Push : ");
for(int i = 0 ; i < 5 ; i++) {
System.out.print(i + " ");
stack.push(i);
}
System.out.print("\nPop : ");
for(int i = 0 ; i < 5 ; i++) {
System.out.print(stack.pop() + " ");
}
// try a exceptional operation : EmptyStack
// System.out.println(stack.pop());
}
}
4.2 LinkedListStack
基於鏈表實現的棧結構
public class LinkedStack {
private LinkedList stack;
public LinkedStack() {
stack = new LinkedList();
}
public void push(int elem) {
stack.insert(stack.size(), elem);
}
public int pop() {
int ret;
try {
ret = stack.remove(stack.size()-1);
} catch (Exception e) {
throw new EmptyStackException();
}
return ret;
}
public static void main(String[] args) {
LinkedStack stack = new LinkedStack();
System.out.print("Push : ");
for(int i = 0 ; i < 5 ; i++) {
System.out.print(i + " ");
stack.push(i);
}
System.out.print("\nPop : ");
for(int i = 0 ; i < 5 ; i++) {
System.out.print(stack.pop() + " ");
}
// try a exceptional operation : EmptyStack
// System.out.println(stack.pop());
}
}
5. 循環隊列
public class CyclicQueue {
private int[] queue;
private int font;
private int rear;
public CyclicQueue(int capacity) {
queue = new int[capacity];
}
public void enQueue(int elem) {
if((rear+1)%queue.length == font) {
throw new RuntimeException("Full Queue...");
}
queue[rear] = elem;
rear = (rear+1) % queue.length;
}
public int deQueue() {
if(font == rear) {
throw new RuntimeException("Empty Queue...");
}
int deQueueElem = queue[font];
font = (font+1)%queue.length;
return deQueueElem;
}
public static void main(String[] args) {
CyclicQueue queue = new CyclicQueue(10);
System.out.print("Push : ");
for(int i = 0 ; i < 5 ; i++) {
System.out.print(i + " ");
queue.enQueue(i);
}
System.out.print("\nPop : ");
for(int i = 0 ; i < 5 ; i++) {
System.out.print(queue.deQueue() + " ");
}
// try a exceptional operation : EmptyQueue
// System.out.println(queue.deQueue());
}
}
6. 二叉樹
這裏會用遞歸/非遞歸
的方式實現二叉樹的先序,中序,後序
;以及二叉樹層序遍歷
;
public class BinaryTree {
private TreeNode root;
private static Random random = new Random(System.currentTimeMillis());
private BinaryTree(TreeNode root) {
this.root = root;
}
public static BinaryTree newBinaryTree(LinkedList list) {
TreeNode root = newTree(list);
return new BinaryTree(root);
}
private static TreeNode newTree(LinkedList list) {
if(list == null || list.size() <= 0) {
return null;
}
TreeNode root = null;
int data;
if((data = list.remove(0)) != TreeNode.NULL) {
root = new TreeNode(data);
TreeNode leftTree, rightTree; ;
if((leftTree = newTree(list)) != null) {
root.left = leftTree;
}
if((rightTree = newTree(list)) != null) {
root.right = rightTree;
}
}
return root;
}
/**
* 前序遍歷
* @param consumer 函數式consumer
*/
public void preOrderTraversal(Consumer<Integer> consumer) {
Objects.requireNonNull(consumer);
int rand = random.nextInt(3);
if(rand == 0) {
System.out.println("遞歸先序遍歷: ");
preOrderTraversal(root, consumer);
} else if(rand == 1) {
System.out.println("非遞歸先序遍歷: ");
preOrderTraversal0(root, consumer);
} else {
System.out.println("層序遍歷: ");
preOrderTraversal1(root, consumer);
}
}
private void preOrderTraversal(TreeNode root, Consumer<Integer> consumer) {
if(root != null) {
consumer.accept(root.data);
preOrderTraversal(root.left, consumer);
preOrderTraversal(root.right, consumer);
}
}
private void preOrderTraversal0(TreeNode root, Consumer<Integer> consumer) {
java.util.LinkedList<TreeNode> stack = new java.util.LinkedList<>();
TreeNode node = root;
while(node != null || !stack.isEmpty()) {
while(node != null) {
consumer.accept(node.data);
stack.push(node);
node = node.left;
}
if(!stack.isEmpty()) {
node = stack.pop();
node = node.right;
}
}
}
private void preOrderTraversal1(TreeNode root, Consumer<Integer> consumer) {
Queue<TreeNode> q = new java.util.LinkedList<>();
q.offer(root);
while(!q.isEmpty()) {
TreeNode node = q.poll();
consumer.accept(node.data);
if(node.left != null) {
q.offer(node.left);
}
if(node.right != null) {
q.offer(node.right);
}
}
}
/**
* 中序遍歷
* @param consumer
*/
public void inOrderTraversal(Consumer<Integer> consumer) {
Objects.requireNonNull(consumer);
if (random.nextBoolean()) {
System.out.println("遞歸中序遍歷: ");
inOrderTraversal(root, consumer);
} else {
System.out.println("非遞歸中序遍歷: ");
inOrderTraversal0(root, consumer);
}
}
private void inOrderTraversal(TreeNode root, Consumer<Integer> consumer) {
if(root != null) {
inOrderTraversal(root.left, consumer);
consumer.accept(root.data);
inOrderTraversal(root.right, consumer);
}
}
private void inOrderTraversal0(TreeNode root, Consumer<Integer> consumer) {
java.util.LinkedList<TreeNode> stack = new java.util.LinkedList<>();
TreeNode node = root;
while(node != null || !stack.isEmpty()) {
while(node != null) {
stack.push(node);
node = node.left;
}
if(!stack.isEmpty()) {
node = stack.pop();
consumer.accept(node.data);
node = node.right;
}
}
}
public void postOrderTraversal(Consumer<Integer> consumer) {
Objects.requireNonNull(consumer);
if (random.nextBoolean()) {
System.out.println("遞歸後序遍歷: ");
postOrderTraversal(root, consumer);
} else {
System.out.println("非遞歸後序遍歷: ");
postOrderTraversal0(root, consumer);
}
}
private void postOrderTraversal(TreeNode root, Consumer<Integer> consumer) {
if(root != null) {
postOrderTraversal(root.left, consumer);
postOrderTraversal(root.right, consumer);
consumer.accept(root.data);
}
}
private void postOrderTraversal0(TreeNode root, Consumer<Integer> consumer) {
// ----- | mid | right | left ...
java.util.LinkedList<TreeNode> sourceStack = new java.util.LinkedList<>();
// ----- | left | right | mid ...
java.util.LinkedList<TreeNode> targetStack = new java.util.LinkedList<>();
sourceStack.push(root);
while(!sourceStack.isEmpty()) {
TreeNode node = sourceStack.pop();
targetStack.push(node);
if(node.left != null) {
sourceStack.push(node.left);
}
if(node.right != null) {
sourceStack.push(node.right);
}
}
while(!targetStack.isEmpty()) {
consumer.accept(targetStack.pop().data);
}
}
private static class TreeNode {
private static final int NULL = Integer.MIN_VALUE;
int data;
TreeNode left;
TreeNode right;
TreeNode(int data) {
this.data = data;
}
}
/**
* 測試深入優先遍歷的:前序,中序,後序
* 3
* ↙ ↘
* 2 8
* ↙ ↘ ↙ ↘
* 9 10 NULL 4
* ↙ ↘ ↙ ↘
*NULL NULL NULL NULL
*
* pre : 3 2 9 10 8 4
* in : 9 2 10 3 8 4
* post : 9 10 2 4 8 3
* @param args
*/
public static void main(String[] args) {
final int NULL = TreeNode.NULL;
int[] data = { 3, 2, 9, NULL, NULL, 10, NULL, NULL, 8, NULL, 4 };
LinkedList list = new LinkedList(data);
BinaryTree binaryTree = BinaryTree.newBinaryTree(list);
binaryTree.preOrderTraversal(x -> System.out.print(x + " "));
System.out.println();
binaryTree.inOrderTraversal(x -> System.out.print(x + " "));
System.out.println();
binaryTree.postOrderTraversal(x -> System.out.print(x + " "));
System.out.println();
}
}
7. 最小堆
主要是上浮
和下沉
算法的實現,這個要特別關注。
public class MinHeap {
private int[] data;
public MinHeap(int[] data) {
this.data = data;
}
/**
* 構建二叉堆,本質就是讓所有非葉子節點一次"下沉"
* @param data
* @return
*/
public static MinHeap buildHeap(int[] data) {
Objects.requireNonNull(data);
MinHeap heap = new MinHeap(data);
for(int i = (data.length-2)/2; i >= 0 ; i--) {
heap.downAdjust(i, data.length);
}
return heap;
}
/**
* parentIndex(tmp)
* ↙ ↘
* childIndex childIndex+1
* @param parentIndex 讓parentIndex元素下沉
*/
public void downAdjust(int parentIndex, int size) {
// 我們要下沉的元素存起來,等到最終位置確定了,再進行賦值即可
int tmp = data[parentIndex];
int childIndex = (parentIndex<<1) + 1;
while(childIndex < size) {
if(childIndex+1 < size // 如果有右孩子
&& data[childIndex+1] < data[childIndex]) { // 且右孩子小於左孩子
childIndex++;
}
// 最小堆, tmp爲父節點
if(tmp <= data[childIndex]) {
break;
}
data[parentIndex] = data[childIndex];
parentIndex = childIndex;
childIndex = (childIndex<<1) + 1;
}
data[parentIndex] = tmp;
}
public void upAdjust(int childIndex) {
// int childIndex = data.length-1;
int parentIndex = (childIndex-1) >> 1;
int tmp = data[childIndex];
while(childIndex > 0 && tmp < data[parentIndex]) {
data[childIndex] = data[parentIndex];
childIndex = parentIndex;
parentIndex = (childIndex-1) >> 1;
}
data[childIndex] = tmp;
}
public static void main(String[] args) {
int[] arr = { 1, 3, 2, 6, 5, 7, 8, 9, 10, 0 };
MinHeap minHeap = new MinHeap(arr);
minHeap.upAdjust(arr.length-1);
System.out.println(Arrays.toString(arr));
arr = new int[]{ 7, 1, 3, 10, 5, 2, 8, 9, 6 };
minHeap = MinHeap.buildHeap(arr);
System.out.println(Arrays.toString(arr));
}
}
8. 最小優先隊列
使用最小堆實現最小優先隊列
public class PriorityQueue {
private MinHeap heap;
private int[] data;
private int size;
private final static int DEFAULT_SIZE = 32;
public PriorityQueue() {
this(DEFAULT_SIZE);
}
public PriorityQueue(int capacity) {
if(capacity <= 0) {
throw new RuntimeException("Capacity must be > 0");
}
data = new int[capacity];
heap = new MinHeap(data);
}
public void enQueue(int key) {
if(size >= data.length) {
resize();
}
data[size++] = key;
heap.upAdjust(size-1);
}
public int deQueue() {
if(size <= 0) {
throw new RuntimeException("Empty Queue...");
}
int head = data[0];
data[0] = data[--size];
heap.downAdjust(0, size);
return head;
}
private void resize() {
int newSize = size << 1;
data = Arrays.copyOf(data, newSize);
heap = new MinHeap(data);
}
public static void main(String[] args) {
PriorityQueue q = new PriorityQueue();
int[] arr = { 3, 5, 10, 2, 7 };
for(int i = 0 ; i < arr.length ; i++) {
q.enQueue(arr[i]);
}
for(int i = 0 ; i < arr.length ; i++) {
System.out.print(q.deQueue() + " ");
}
}
}
9. 排序——比較交換
這裏實現了一些基本的排序算法:
冒泡排序
,及其簡單優化快速排序
,單路快排
,雙路快排
,三路快排
,基於棧的非遞歸實現快速排序
堆排序
,這裏的堆排序用到了上面我實現的堆的數據結構
public class Sort {
private static Random random = new Random(System.currentTimeMillis());
/**
* 基礎冒泡排序
* @param data
*/
public static void bubbleSort(int[] data) {
Objects.requireNonNull(data);
for(int i = 0 ; i < data.length ; i++) {
for(int j = 0 ; j < data.length-1-i ; j++) {
if(data[j] > data[j+1]) {
swap(data, j, j+1);
}
}
}
}
/**
* 冒泡排序簡單優化1
* @param data
*/
public static void bubbleSort1(int[] data) {
Objects.requireNonNull(data);
for(int i = 0 ; i < data.length ; i++) {
boolean isSorted = true;
for(int j = 0 ; j < data.length-1-i ; j++) {
if(data[j] > data[j+1]) {
swap(data, j, j+1);
isSorted = false;
}
}
if(isSorted) {
break;
}
}
}
/**
* 冒泡排序簡單優化2
* @param data
*/
public static void bubbleSort2(int[] data) {
Objects.requireNonNull(data);
int lastChangeIndex = 0;
int border = data.length - 1;
for(int i = 0 ; i < data.length ; i++) {
boolean isSorted = true;
for(int j = 0 ; j < border ; j++) {
if(data[j] > data[j+1]) {
swap(data, j, j+1);
isSorted = false;
lastChangeIndex = j;
}
}
border = lastChangeIndex;
if(isSorted) {
break;
}
}
}
/**
* 快速排序入口
* @param arr
*/
public static void quickSort(int[] arr) {
Objects.requireNonNull(arr);
if (random.nextBoolean()) {
System.out.println("基於遞歸的快速排序: ");
quickSort(arr, 0, arr.length - 1);
} else {
System.out.println("基於棧的快速排序: ");
quickSort0(arr, 0, arr.length - 1);
}
}
/**
* 快速排序入口子方法
* @param arr
* @param l
* @param r
*/
private static void quickSort(int[] arr, int l, int r) {
if(l >= r) {
return;
}
// 這裏的3Way可以換成多種不同的實現,如1Way,2Way等
int pivotIndex = partition3Way(arr, l, r);
quickSort(arr, l, pivotIndex-1);
quickSort(arr, pivotIndex+1, r);
}
/**
* 基於棧的快速排序
* @param arr
* @param l
* @param r
*/
private static void quickSort0(int[] arr, int l, int r) {
LinkedList<Pair> stack = new LinkedList<>();
stack.push(new Pair(l, r));
while(!stack.isEmpty()) {
Pair top = stack.pop();
int pivotIndex = partition3Way(arr, top.l, top.r);
if(top.l + 1 < pivotIndex) {
stack.push(new Pair(top.l, pivotIndex-1));
}
if(pivotIndex + 1 < top.r) {
stack.push(new Pair(pivotIndex+1, top.r));
}
}
}
/**
* arr[l, p-1] < arr[p] and arr[p+1, r] > arr[p]
*
* // arr[l+1, j] < v ; arr[j+1, i) > v
* // | arr[l] | \ \ \ \ \ \ \ | / / / / / / / / |
* // l+1 j j+1 i
* @param arr
* @param l
* @param r
* @return p
*/
private static int partition1Way(int[] arr, int l, int r) {
int j = l, i = l+1;
while(i <= r) {
if(arr[i] < arr[l]) {
swap(arr, ++j, i);
}
i++;
}
swap(arr, l, j);
return j;
}
/**
* arr[l+1, i) < v ; arr(j, r] > v
* @param arr
* @param l
* @param r
* @return
*/
private static int partition2Way(int[] arr, int l, int r) {
int pivot = arr[l];
int i = l+1, j = r;
while(true) {
while(i <= r && arr[i] < pivot) {
i++;
}
while(j >= l+1 && arr[j] > pivot) {
j--;
}
if(i > j) {
break;
}
swap(arr, i++, j--);
}
// i爲從前向後看第一個 >= v的元素索引
// j爲從後向前看第一個 <= v的元素索引
swap(arr, l, j);
return j;
}
/**
* arr[l+1, lt] < v ; arr[lt+1, i) == v ; arr[gt, r] > v
*
* [l] [l+1 ... lt] [lt+1 ... i-1] [i .... ] [gt ... r]
* < v == v > v
* i == gt -> break;
* @param arr
* @param l
* @param r
* @return
*/
private static int partition3Way(int[] arr, int l, int r) {
int pivot = arr[l];
int lt = l, i = l+1, gt = r+1;
while(i < gt) {
if(arr[i] < pivot) {
swap(arr, ++lt, i);
} else if(arr[i] > pivot){
swap(arr, i--, --gt);
}
i++;
}
swap(arr, l, lt);
return lt;
}
private static class Pair {
int l, r;
public Pair(int l, int r) {
this.l = l;
this.r = r;
}
}
private static void swap(int[] data, int i, int j) {
int tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
/**
* 以最小堆排序,能夠得到降序(從大到小)的數組序列
* @param arr
*/
public static void heapSort(int[] arr) {
Objects.requireNonNull(arr);
MinHeap heap = MinHeap.buildHeap(arr);
for(int i = arr.length-1 ; i > 0 ; i--) {
swap(arr, 0, i);
heap.downAdjust(0, i);
}
}
public static void main(String[] args) {
int[] arr = { 5, 3, 1, 2, 6, 8, 4, 7};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
10. 排序——線性時間排序
這裏實現了計數排序
,桶排序
public class LinearSort {
/**
* 這裏我們假定元素的取值範圍爲0~10
* @param arr
*/
public static void counterSort(int[] arr) {
int[] counter = new int[11];
for(int i = 0 ; i < arr.length ; i++) {
counter[arr[i]]++;
}
int k = 0;
for(int i = 0 ; i < counter.length ; i++) {
int count = counter[i];
for(int j = 0 ; j < count ; j++) {
arr[k++] = i;
}
}
}
/**
* 假定元素的範圍全部在[min, max]之間,且這個區間比較小
* 我們使用如下的計數排序來優化
* @param arr
*/
public static void counterSort1(int[] arr) {
Objects.requireNonNull(arr);
// 首先找到最小值,最大值
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
for(int i = 0 ; i < arr.length ; i++) {
min = Math.min(min, arr[i]);
max = Math.max(max, arr[i]);
}
// 遍歷,並開始計數
int[] counter = new int[max - min + 1];
for(int i = 0 ; i < arr.length ; i++) {
counter[arr[i] - min]++;
}
// 寫回數據,相當於對原數組排序
int k = 0;
for(int i = 0 ; i < counter.length ; i++) {
int count = counter[i];
for(int j = 0 ; j < count ; j++) {
// 注意,這裏i加上了一個偏移量
arr[k++] = i+min;
}
}
}
/**
* 計數排序要求每個元素都是整數,因爲數組的索引必須爲整數
* 而桶排序則解決了這種困難
* @param arr
*/
public static void bucketSort(double[] arr) {
Objects.requireNonNull(arr);
double min = Double.MAX_VALUE, max = Double.MIN_VALUE;
for(int i = 0 ; i < arr.length ; i++) {
min = Math.min(min, arr[i]);
max = Math.max(max, arr[i]);
}
double d = max - min;
int bucketNum = arr.length;
ArrayList<LinkedList<Double>> bucketList = new ArrayList<>(bucketNum);
for(int i = 0 ; i < bucketNum ; i++) {
bucketList.add(new LinkedList<>());
}
for(int i = 0 ; i < arr.length ; i++) {
int num = (int)((arr[i] - min) * (bucketNum-1) / d);
bucketList.get(num).add(arr[i]);
}
for(LinkedList<Double> list : bucketList) {
Collections.sort(list);
}
int index = 0;
for(LinkedList<Double> list : bucketList) {
for(double data : list) {
arr[index++] = data;
}
}
}
public static void main(String[] args) {
//int[] arr;
//counterSort(new int[]{ 4, 4, 6, 5, 3, 2, 8, 1, 7, 5, 6, 0, 10 });
//counterSort1(arr = new int[]{ 95, 94, 91, 98, 99, 90, 93, 91, 92 });
double[] arr = { 4.12, 6.421, 0.0023, 3.0, 2.123, 8.122, 4.12, 10.09 };
bucketSort(arr);
System.out.println(Arrays.toString(arr));
}
}