diff --git a/c-cpp/11_sorts/.gitkeep b/c-cpp/11_sorts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/c-cpp/11_sorts/sorts.c b/c-cpp/11_sorts/sorts.c new file mode 100644 index 0000000..f759077 --- /dev/null +++ b/c-cpp/11_sorts/sorts.c @@ -0,0 +1,139 @@ +#include +#include +#include + +struct array { + int size; + int used; + int *arr; +}; + +void dump(struct array *array) +{ + int idx; + + for (idx = 0; idx < array->used; idx++) + printf("[%02d]: %08d\n", idx, array->arr[idx]); +} + +void alloc(struct array *array) +{ + array->arr = (int *)malloc(array->size * sizeof(int)); +} + +void bubble_sort(struct array *array) +{ + int i, j; + + if (array->used <= 1) + return; + + for (i = 0; i < array->used; i++) { + bool has_swap = false; + for (j = 0; j < array->used - i - 1; j++) { + if (array->arr[j] > array->arr[j+1]) { + int tmp; + tmp = array->arr[j]; + array->arr[j] = array->arr[j+1]; + array->arr[j+1] = tmp; + has_swap = true; + } + + } + if (!has_swap) + break; + } +} + +void bubble_sort_test() +{ + int idx; + struct array ten_int = {10, 0, NULL}; + + alloc(&ten_int); + for (idx = 0; idx < 10; idx++) + ten_int.arr[idx] = 30 - idx; + ten_int.used = 10; + dump(&ten_int); + bubble_sort(&ten_int); + dump(&ten_int); +} + +void insertion_sort(struct array *array) +{ + int i, j; + + if (array->used <= 1) + return; + + for (i = 1; i < array->used; i++) { + int val = array->arr[i]; + + for (j = i - 1; j >= 0; j--) { + if (val < array->arr[j]) + array->arr[j+1] = array->arr[j]; + else + break; + } + array->arr[j+1] = val; + } +} + +void insertion_sort_test() +{ + int idx; + struct array ten_int = {10, 0, NULL}; + + alloc(&ten_int); + for (idx = 0; idx < 10; idx++) + ten_int.arr[idx] = 30 - idx; + ten_int.used = 10; + dump(&ten_int); + insertion_sort(&ten_int); + dump(&ten_int); +} + +void selection_sort(struct array *array) +{ + int i, j; + + if (array->used <= 1) + return; + + for (i = 0; i < array->used - 1; i++) { + int tmp, idx = i; + + for (j = i + 1; j < array->used; j++) + if (array->arr[j] < array->arr[idx]) + idx = j; + + if (idx == i) + continue; + + tmp = array->arr[i]; + array->arr[i] = array->arr[idx]; + array->arr[idx] = tmp; + } +} + +void selection_sort_test() +{ + int idx; + struct array ten_int = {10, 0, NULL}; + + alloc(&ten_int); + for (idx = 0; idx < 10; idx++) + ten_int.arr[idx] = 30 - idx; + ten_int.used = 10; + dump(&ten_int); + selection_sort(&ten_int); + dump(&ten_int); +} + +int main() +{ + //bubble_sort_test(); + //selection_sort_test(); + insertion_sort_test(); + return 0; +} diff --git a/c-cpp/11_sorts/sorts.cpp b/c-cpp/11_sorts/sorts.cpp new file mode 100644 index 0000000..1adf676 --- /dev/null +++ b/c-cpp/11_sorts/sorts.cpp @@ -0,0 +1,47 @@ +// C program for implementation of selection sort +#include + +void swap(int *xp, int *yp) +{ + int temp = *xp; + *xp = *yp; + *yp = temp; +} + +void selectionSort(int arr[], int n) +{ + int i, j, min_idx; + + // One by one move boundary of unsorted subarray + for (i = 0; i < n-1; i++) + { + // Find the minimum element in unsorted array + min_idx = i; + for (j = i+1; j < n; j++) + if (arr[j] < arr[min_idx]) + min_idx = j; + + // Swap the found minimum element with the first element + swap(&arr[min_idx], &arr[i]); + } +} + +/* Function to print an array */ +void printArray(int arr[], int size) +{ + int i; + for (i=0; i < size; i++) + printf("%d ", arr[i]); + printf("\n"); +} + +// Driver program to test above functions +int main() +{ + int arr[] = {64, 25, 12, 22, 11}; + int n = sizeof(arr)/sizeof(arr[0]); + selectionSort(arr, n); + printf("Sorted array: \n"); + printArray(arr, n); + return 0; +} diff --git a/c-cpp/11_sorts/sorts.hpp b/c-cpp/11_sorts/sorts.hpp new file mode 100644 index 0000000..eb272c4 --- /dev/null +++ b/c-cpp/11_sorts/sorts.hpp @@ -0,0 +1,89 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/16. + */ + +#ifndef SORTS_SORTS_HPP_ +#define SORTS_SORTS_HPP_ + +#include +#include + +template ::value_type>> +void bubble_sort(BidirIt first, BidirIt last, BinaryPred comp = BinaryPred()) { + if (std::distance(first, last) <= 1) { return; } + bool flag = true; + for (auto it = first; flag and it != last; ++it) { + flag = false; + for (auto itt = first; itt != last - std::distance(first, it) - 1; ++itt) { + if (comp(*(itt + 1), *itt)) { + std::swap(*itt, *(itt + 1)); + flag = true; + } + } + } +} + +template ::value_type>> +void insertion_sort(BidirIt first, BidirIt last, BinaryPred comp = BinaryPred()) { + if (std::distance(first, last) <= 1) { return; } + for (auto it = first + 1; it != last; ++it) { + const auto target = *it; + auto itt = it; + for (; std::distance(first, itt) > 0 and comp(target, *(itt - 1)); --itt) { + *itt = *(itt - 1); + } + *itt = target; + } +} + +template ::value_type>> +void selection_sort(BidirIt first, BidirIt last, BinaryPred comp = BinaryPred()) { + if (std::distance(first, last) <= 1) { return; } + for (auto it = first; it != last - 1; ++it) { + auto tag = it; + for (auto itt = it + 1; itt != last; ++itt) { + if (comp(*itt, *tag)) { + tag = itt; + } + } + if (tag != it) { + std::swap(*it, *tag); + } + } +} + +template ::value_type>> +void bubble_down_sort(FrwdIt first, FrwdIt last, BinaryPred comp = BinaryPred()) { + if (std::distance(first, last) <= 1) { return; } + for (auto it = first; it != last; ++it) { + for (auto itt = it + 1; itt != last; ++itt) { + if (comp(*itt, *it)) { + std::swap(*it, *itt); + } + } + } +} + +template ::value_type>> +void shell_sort(BidirIt first, BidirIt last, BinaryPred comp = BinaryPred()) { + const size_t len = std::distance(first, last); + if (len <= 1) { return; } + for (size_t step = len / 2; step >= 1; step /= 2) { + for (auto it = first + step; it != last; ++it) { + auto target = *it; + auto itt = it - step; + for (; std::distance(first, itt) >= 0 and comp(target, *itt); itt -= step) { + *(itt + step) = *itt; + } + *(itt + step) = target; + } + } +} + +#endif // SORTS_SORTS_HPP_ + diff --git a/c-cpp/11_sorts/sorts_test.cc b/c-cpp/11_sorts/sorts_test.cc new file mode 100644 index 0000000..723942b --- /dev/null +++ b/c-cpp/11_sorts/sorts_test.cc @@ -0,0 +1,45 @@ +#include +#include + +#include "sorts.hpp" + +int main() { + const std::vector test_data{1, 2, 3, 0}; + + std::vector a(test_data.begin(), test_data.end()); + bubble_sort(a.begin(), a.end()); + for (auto i : a) { + std::cout << i << ' '; + } + std::cout << '\n'; + + std::vector b(test_data.begin(), test_data.end()); + insertion_sort(b.begin(), b.end()); + for (auto i : b) { + std::cout << i << ' '; + } + std::cout << '\n'; + + std::vector c(test_data.begin(), test_data.end()); + selection_sort(c.begin(), c.end()); + for (auto i : c) { + std::cout << i << ' '; + } + std::cout << '\n'; + + std::vector d(test_data.begin(), test_data.end()); + bubble_down_sort(d.begin(), d.end()); + for (auto i : d) { + std::cout << i << ' '; + } + std::cout << '\n'; + + std::vector e(test_data.begin(), test_data.end()); + shell_sort(e.begin(), e.end()); + for (auto i : e) { + std::cout << i << ' '; + } + std::cout << '\n'; + + return 0; +} diff --git a/c-cpp/12_sorts/.gitkeep b/c-cpp/12_sorts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/c-cpp/12_sorts/merge_sort.hpp b/c-cpp/12_sorts/merge_sort.hpp new file mode 100644 index 0000000..14ec7ba --- /dev/null +++ b/c-cpp/12_sorts/merge_sort.hpp @@ -0,0 +1,62 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/17. + */ + +#ifndef SORTS_MERGE_SORT_HPP_ +#define SORTS_MERGE_SORT_HPP_ + +#include +#include +#include +#include + +namespace detail { +template ::value_type>> +OutputIt merge(InputIt1 first1, InputIt1 last1, + InputIt2 first2, InputIt2 last2, + OutputIt d_first, + BinaryPred comp = BinaryPred()) { + for (; first1 != last1; ++d_first) { + if (first2 == last2) { + return std::copy(first1, last1, d_first); + } + if (comp(*first2, *first1)) { + *d_first = *first2; + ++first2; + } else { + *d_first = *first1; + ++first1; + } + } + return std::copy(first2, last2, d_first); +} +} // namespace detail + +template ::value_type>> +void merge_sort(FrwdIt first, FrwdIt last, BinaryPred comp = BinaryPred()) { + const auto len = std::distance(first, last); + if (len <= 1) { return; } + auto cut = first + len / 2; + merge_sort(first, cut, comp); + merge_sort(cut, last, comp); + std::vector::value_type> tmp; + tmp.reserve(len); + detail::merge(first, cut, cut, last, std::back_inserter(tmp), comp); + std::copy(tmp.begin(), tmp.end(), first); +} + +template ::value_type>> +void inplace_merge_sort(BidirIt first, BidirIt last, BinaryPred comp = BinaryPred()) { + const auto len = std::distance(first, last); + if (len <= 1) { return; } + auto cut = first + len / 2; + merge_sort(first, cut, comp); + merge_sort(cut, last, comp); + std::inplace_merge(first, cut, last, comp); +} + +#endif // SORTS_MERGE_SORT_HPP_ + diff --git a/c-cpp/12_sorts/merge_sort_test.cc b/c-cpp/12_sorts/merge_sort_test.cc new file mode 100644 index 0000000..35bc8a6 --- /dev/null +++ b/c-cpp/12_sorts/merge_sort_test.cc @@ -0,0 +1,28 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/17. + */ + +#include +#include +#include "merge_sort.hpp" + +int main() { + const std::vector test_data{0, -1, 3, 190, -500}; + + std::vector a{test_data}; + merge_sort(a.begin(), a.end()); + for (auto i : a) { + std::cout << i << ' '; + } + std::cout << std::endl; + + std::vector b{test_data}; + inplace_merge_sort(b.begin(), b.end()); + for (auto i : b) { + std::cout << i << ' '; + } + std::cout << std::endl; + + return 0; +} + diff --git a/c-cpp/12_sorts/quick_sort.hpp b/c-cpp/12_sorts/quick_sort.hpp new file mode 100644 index 0000000..e0c385a --- /dev/null +++ b/c-cpp/12_sorts/quick_sort.hpp @@ -0,0 +1,71 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/17. + */ + +#ifndef SORTS_QUICK_SORT_HPP_ +#define SORTS_QUICK_SORT_HPP_ + +#include +#include +#include +#include + +namespace detail { +template > +const T& median(const T& a, const T& b, const T& c, Compare comp = Compare()) { + if (comp(a, b) and comp(b, c) or comp(c, b) and comp(b, a)) { + return b; + } else if (comp(b, c) and comp(c, a) or comp(a, c) and comp(c, b)) { + return c; + } else { + return a; + } +} + +template ::value_type, + typename Compare = std::less> +const T& iter_median(Iter a, Iter b, Iter c, Compare comp = Compare()) { + return median(*a, *b, *c, comp); +} + +template ::value_type, + typename Compare = std::less> +std::pair inplace_partition(BidirIt first, + BidirIt last, + const T& pivot, + Compare comp = Compare()) { + BidirIt last_less, last_greater, first_equal, last_equal; + for (last_less = first, last_greater = first, first_equal = last; + last_greater != first_equal; ) { + if (comp(*last_greater, pivot)) { + std::iter_swap(last_greater++, last_less++); + } else if (comp(pivot, *last_greater)) { + ++last_greater; + } else { // pivot == *last_greater + std::iter_swap(last_greater, --first_equal); + } + } + const auto cnt = std::distance(first_equal, last); + std::swap_ranges(first_equal, last, last_less); + first_equal = last_less; + last_equal = first_equal + cnt; + return {first_equal, last_equal}; +} +} // namespace detail + +template ::value_type, + typename Compare = std::less> +void quick_sort(BidirIt first, BidirIt last, Compare comp = Compare()) { + for (auto size = std::distance(first, last); size > 1; size = std::distance(first, last)) { + const T pivot = detail::iter_median(first, last - 1, first + size / 2, comp); + const auto eq = detail::inplace_partition(first, last, pivot, comp); + quick_sort(first, eq.first, comp); + first = eq.second; // Liam Huang: economize half of recursive calling. + } +} + +#endif // SORTS_QUICK_SORT_HPP_ + diff --git a/c-cpp/12_sorts/quick_sort_test.cc b/c-cpp/12_sorts/quick_sort_test.cc new file mode 100644 index 0000000..742bdbb --- /dev/null +++ b/c-cpp/12_sorts/quick_sort_test.cc @@ -0,0 +1,25 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/17. + */ + +#include +#include +#include + +#include "quick_sort.hpp" + +void test_quick_sort(std::vector test_data) { + quick_sort(test_data.begin(), test_data.end()); + std::transform(test_data.begin(), test_data.end(), + std::ostream_iterator(std::cout, " "), [](int i){ return i; }); + std::cout << '\n'; +} + +int main() { + test_quick_sort({-3, -1, 1, -2, -3, 0, -3, 100, 1, 1, -100}); + test_quick_sort({1, 1, 1}); + test_quick_sort({1, 0, -1}); + test_quick_sort({1}); + return 0; +} + diff --git a/go/11_sorts/Sort.go b/go/11_sorts/Sort.go index 379c41b..005b4f0 100644 --- a/go/11_sorts/Sort.go +++ b/go/11_sorts/Sort.go @@ -1,54 +1,66 @@ package _1_sorts -func BubbleSort(a []int) { - arrLen := len(a) - if arrLen <= 1 { +/* +冒泡排序、插入排序、选择排序 + */ + +//冒泡排序,a是数组,n表示数组大小 +func BubbleSort(a []int, n int) { + if n <= 1 { return } - for i := arrLen - 1; i > 0; i-- { - for j := 0; j < i; j++ { + for i := 0; i < n; i++ { + // 提前退出标志 + flag := false + for j := 0; j < n-i-1; j++ { if a[j] > a[j+1] { - tmp := a[j+1] - a[j+1] = a[j] - a[j] = tmp + a[j], a[j+1] = a[j+1], a[j] + //此次冒泡有数据交换 + flag = true } } + // 如果没有交换数据,提前退出 + if !flag { + break + } } } -func InsertSort(a []int) { - arrLen := len(a) - if arrLen <= 1 { +// 插入排序,a表示数组,n表示数组大小 +func InsertionSort(a []int, n int) { + if n <= 1 { return } - for i := 1; i < arrLen; i++ { - v := a[i] + for i := 1; i < n; i++ { + value := a[i] j := i - 1 + //查找要插入的位置并移动数据 for ; j >= 0; j-- { - if a[j] > v { + if a[j] > value { a[j+1] = a[j] + } else { + break } } - a[j+1] = v + a[j+1] = value } } -func SelectionSort(a []int) { - arrLen := len(a) - if arrLen <= 1 { +// 选择排序,a表示数组,n表示数组大小 +func SelectionSort(a []int, n int) { + if n <= 1 { return } - for i := 0; i < arrLen; i++ { + for i := 0; i < n; i++ { + // 查找最小值 minIndex := i - for j := i + 1; j < arrLen; j++ { + for j := i + 1; j < n; j++ { if a[j] < a[minIndex] { minIndex = j } } - if minIndex != i { - tmp := a[minIndex] - a[minIndex] = a[i] - a[i] = tmp - } + // 交换 + a[i], a[minIndex] = a[minIndex],a[i] + } } diff --git a/go/11_sorts/Sort_test.go b/go/11_sorts/Sort_test.go index 565d230..3f1fbc8 100644 --- a/go/11_sorts/Sort_test.go +++ b/go/11_sorts/Sort_test.go @@ -1,43 +1,27 @@ package _1_sorts import ( + "fmt" "testing" ) func TestBubbleSort(t *testing.T) { - a := []int{5, 4, 3, 2, 1} - BubbleSort(a) - t.Log(a) + arr := []int{1,5,9,6,3,7,5,10} + fmt.Println("排序前:",arr) + BubbleSort(arr,len(arr)) + fmt.Println("排序后:",arr) +} + +func TestInsertionSort(t *testing.T) { + arr := []int{1,5,9,6,3,7,5,10} + fmt.Println("排序前:",arr) + InsertionSort(arr,len(arr)) + fmt.Println("排序后:",arr) } func TestSelectionSort(t *testing.T) { - a := []int{5, 4, 3, 2, 1} - SelectionSort(a) - t.Log(a) -} -func TestInsertSort(t *testing.T) { - a := []int{5, 4, 3, 2, 1} - InsertSort(a) - t.Log(a) -} - -func BenchmarkBubbleSort(b *testing.B) { - a := []int{5, 4, 3, 2, 1} - for i := 0; i < b.N; i++ { - BubbleSort(a) - } -} - -func BenchmarkSelectionSort(b *testing.B) { - a := []int{5, 4, 3, 2, 1} - for i := 0; i < b.N; i++ { - SelectionSort(a) - } -} - -func BenchmarkInsertSort(b *testing.B) { - a := []int{5, 4, 3, 2, 1} - for i := 0; i < b.N; i++ { - InsertSort(a) - } + arr := []int{1,5,9,6,3,7,5,10} + fmt.Println("排序前:",arr) + SelectionSort(arr,len(arr)) + fmt.Println("排序后:",arr) } diff --git "a/java/05_array/\bGenericArray.java" b/java/05_array/GenericArray.java similarity index 90% rename from "java/05_array/\bGenericArray.java" rename to java/05_array/GenericArray.java index 4769e72..07dc5dc 100644 --- "a/java/05_array/\bGenericArray.java" +++ b/java/05_array/GenericArray.java @@ -1,21 +1,21 @@ /** - * + * * 1)泛型动态数组 * - * Author: shi + * Author: shi */ public class GenericArray { private T[] data; private int size; - // 根据传入容量,构造Array + // 根据传入容量,构造Array public GenericArray(int capacity) { data = (T[]) new Object[capacity]; size = 0; } - // 无参构造方法,默认数组容量为10 + // 无参构造方法,默认数组容量为10 public GenericArray() { this(10); } @@ -57,7 +57,7 @@ return false; } - // 获取对应元素的下标, 未找到,返回 -1 + // 获取对应元素的下标, 未找到,返回 -1 public int find(T e) { for ( int i = 0; i < size; i++) { if (data[i].equals(e)) { @@ -66,12 +66,12 @@ } return -1; } - + // 在 index 位置,插入元素e, 时间复杂度 O(m+n) public void add(int index, T e) { checkIndex(index); - // 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍 + // 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍 if (size == data.length) { resize(2 * data.length); } @@ -96,7 +96,7 @@ // 删除 index 位置的元素,并返回 public T remove(int index) { checkIndex(index); - + T ret = data[index]; for (int i = index + 1; i < size; i++) { data[i - 1] = data[i]; @@ -158,7 +158,7 @@ private void checkIndex(int index) { if (index < 0 || index > size) { - throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size."); + throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size."); } } } diff --git a/java/11_sorts/Sorts.java b/java/11_sorts/Sorts.java index 2258106..aeda6f4 100644 --- a/java/11_sorts/Sorts.java +++ b/java/11_sorts/Sorts.java @@ -58,6 +58,9 @@ public class Sorts { } } + if (minIndex == i) + continue; + // 交换 int tmp = a[i]; a[i] = a[minIndex]; diff --git a/java/14_sorts/CountingSort.java b/java/14_sorts/CountingSort.java new file mode 100644 index 0000000..3cc5d58 --- /dev/null +++ b/java/14_sorts/CountingSort.java @@ -0,0 +1,53 @@ +package sorts; + +/** + * 计数排序 + * + * Author: ZHENG + */ +public class CountingSort { + + // 计数排序,a是数组,n是数组大小。假设数组中存储的都是非负整数。 + public static void countingSort(int[] a, int n) { + if (n <= 1) return; + + // 查找数组中数据的范围 + int max = a[0]; + for (int i = 1; i < n; ++i) { + if (max < a[i]) { + max = a[i]; + } + } + + // 申请一个计数数组c,下标大小[0,max] + int[] c = new int[max + 1]; + for (int i = 0; i < max + 1; ++i) { + c[i] = 0; + } + + // 计算每个元素的个数,放入c中 + for (int i = 0; i < n; ++i) { + c[a[i]]++; + } + + // 依次累加 + for (int i = 1; i < max + 1; ++i) { + c[i] = c[i-1] + c[i]; + } + + // 临时数组r,存储排序之后的结果 + int[] r = new int[n]; + // 计算排序的关键步骤了,有点难理解 + for (int i = n - 1; i >= 0; --i) { + int index = c[a[i]]-1; + r[index] = a[i]; + c[a[i]]--; + } + + // 将结果拷贝会a数组 + for (int i = 0; i < n; ++i) { + a[i] = r[i]; + } + } + +} diff --git a/javascript/05_array/Array.md b/javascript/05_array/Array.md index 0b0cc30..5af2394 100644 --- a/javascript/05_array/Array.md +++ b/javascript/05_array/Array.md @@ -282,7 +282,7 @@ Point 2: 2, 4 Point 3: 8, 1 Point 4: 2, 9 -也可以用之前的 puh() 等操作方法来操作对象数组 +也可以用之前的 push() 等操作方法来操作对象数组 ``` var p5 = new Point(11,13); point.push(p5); diff --git a/javascript/11_sorts/sort.js b/javascript/11_sorts/sort.js new file mode 100644 index 0000000..0a3c9c8 --- /dev/null +++ b/javascript/11_sorts/sort.js @@ -0,0 +1,68 @@ +/** + * 冒泡,插入,选择排序 + * + * Author: nameczz + */ + +// 冒泡排序 +const bubbleSort = (arr) => { + if (arr.length <= 1) return + for (let i = 0; i < arr.length; i++) { + let hasChange = false + for (let j = 0; j < arr.length - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + const temp = arr[j] + arr[j] = arr[j + 1] + arr[j + 1] = temp + hasChange = true + } + } + // 如果false 说明所有元素已经到位 + if (!hasChange) break + } + console.log(arr) +} + +// 插入排序 +const insertionSort = (arr) => { + if (arr.length <= 1) return + for (let i = 1; i < arr.length; i++) { + const temp = arr[i] + let j = i - 1 + // 若arr[i]前有大于arr[i]的值的化,向后移位,腾出空间,直到一个<=arr[i]的值 + for (j; j >= 0; j--) { + if (arr[j] > temp) { + arr[j + 1] = arr[j] + } else { + break + } + } + arr[j + 1] = temp + } + console.log(arr) +} + +// 选择排序 +const selectionSort = (arr) => { + if (arr.length <= 1) return + // 需要注意这里的边界, 因为需要在内层进行 i+1后的循环,所以外层需要 数组长度-1 + for (let i = 0; i < arr.length - 1; i++) { + let minIndex = i + for (let j = i + 1; j < arr.length; j++) { + if (arr[j] < arr[minIndex]) { + minIndex = j // 找到整个数组的最小值 + } + } + const temp = arr[i] + arr[i] = arr[minIndex] + arr[minIndex] = temp + } + console.log(arr) +} + +const test = [4, 5, 6, 3, 2, 1] +bubbleSort(test) +const testSort = [4, 1, 6, 3, 2, 1] +insertionSort(testSort) +const testSelect = [4, 8, 6, 3, 2, 1, 0, 12] +selectionSort(testSelect) \ No newline at end of file diff --git a/javascript/12_sorts/MergeSort.js b/javascript/12_sorts/MergeSort.js new file mode 100644 index 0000000..6185ab4 --- /dev/null +++ b/javascript/12_sorts/MergeSort.js @@ -0,0 +1,43 @@ +/** + * 归并排序 + * + * Author: nameczz + */ + +const mergeArr = (left, right) => { + let temp = [] + let leftIndex = 0 + let rightIndex = 0 + // 判断2个数组中元素大小,依次插入数组 + while (left.length > leftIndex && right.length > rightIndex) { + if (left[leftIndex] <= right[rightIndex]) { + temp.push(left[leftIndex]) + leftIndex++ + } else { + temp.push(right[rightIndex]) + rightIndex++ + } + } + // 合并 多余数组 + return temp.concat(left.slice(leftIndex)).concat(right.slice(rightIndex)) +} + +const mergeSort = (arr) => { + // 当任意数组分解到只有一个时返回。 + if (arr.length <= 1) return arr + const middle = Math.floor(arr.length / 2) // 找到中间值 + const left = arr.slice(0, middle) // 分割数组 + const right = arr.slice(middle) + // 递归 分解 合并 + return mergeArr(mergeSort(left), mergeSort(right)) +} + +const testArr = [] +let i = 0 +while (i < 100) { + testArr.push(Math.floor(Math.random() * 1000)) + i++ +} + +const res = mergeSort(testArr) +console.log(res) \ No newline at end of file diff --git a/javascript/12_sorts/QuickSort.js b/javascript/12_sorts/QuickSort.js new file mode 100644 index 0000000..d8ba3bd --- /dev/null +++ b/javascript/12_sorts/QuickSort.js @@ -0,0 +1,46 @@ +/** + * 快速排序 + * + * Author: nameczz + */ + +const swap = (arr, i, j) => { + const temp = arr[i] + arr[i] = arr[j] + arr[j] = temp +} + +// 获取 pivot 交换完后的index +const partition = (arr, pivot, left, right) => { + const pivotVal = arr[pivot] + let startIndex = left + for (let i = left; i < right; i++) { + if (arr[i] < pivotVal) { + swap(arr, i, startIndex) + startIndex++ + } + } + swap(arr, startIndex, pivot) + return startIndex +} + +const quickSort = (arr, left, right) => { + if (left < right) { + let pivot = right + let partitionIndex = partition(arr, pivot, left, right) + quickSort(arr, left, partitionIndex - 1 < left ? left : partitionIndex - 1) + quickSort(arr, partitionIndex + 1 > right ? right : partitionIndex + 1, right) + } + +} + + +const testArr = [] +let i = 0 +while (i < 10) { + testArr.push(Math.floor(Math.random() * 1000)) + i++ +} +console.log('unsort', testArr) +quickSort(testArr, 0, testArr.length - 1); +console.log('sort', testArr) \ No newline at end of file diff --git a/notes/11_sorts/readme.md b/notes/11_sorts/readme.md new file mode 100644 index 0000000..576668f --- /dev/null +++ b/notes/11_sorts/readme.md @@ -0,0 +1,100 @@ +# 排序(上) + +| 排序算法 | 时间复杂度 | 是否基于比较 | +|---------|----|----| +| 冒泡、插入、选择 | $O(n^2)$ | [y] | +| 快排、归并 | $O(n\log n)$ | [y] | +| 桶、基数、计数 | $O(n) | [x] | + +开篇问题:插入排序和冒泡排序的时间复杂度相同,都是 $O(n^2)$,在实际软件开发中,为什么我们更倾向于使用插入排序而不是冒泡排序? + +## 如何分析「排序算法」? + +### 算法执行效率 + +1. 最好、最坏、平均情况的时间复杂度 +2. 时间复杂度的系数、低阶、常数——在渐进复杂度相同的情况下,需要比较系数、低阶和常数 +3. 比较和交换(移动)的次数——基于比较的排序算法的两种基本操作 + +### 算法的内存消耗 + +是否为原地排序算法(In-place sort algorithm),即算法的空间复杂度是否为 $O(1)$。 + +### 排序的稳定性 + +经过排序算法处理后,值相同的元素,在原序列和排序后序列中的相对位置保持不变,则称该排序算法是稳定的。 + +> 待排序的 `item` 并不是简单的值,而是一个基于对象中的某个 `key` 进行排序时,排序的稳定性就有意义了。 + +## 冒泡排序 + +* 每次循环都从序列起始位置开始 +* 循环中的每个动作,都对比相邻两个元素的大小是否满足偏序要求,若不满足,则交换顺序 + +![冒泡排序例图](https://static001.geekbang.org/resource/image/88/34/8890cbf63ea80455ce82490a23361134.jpg) + +分析: + +* 原地排序 +* 稳定排序(偏序关系是严格的偏序关系,如 `<` 或 `>`) +* 时间复杂度 + * 最好 $O(n)$ + * 最坏 $O(n^2)$ + * 平均 $O(n^2)$ + +### 冒泡排序的平均时间复杂度非严格分析 + +* 有序度:序列中满足偏序关系的两两组合的元素对的个数 +* 满有序度:排序完成的序列的有序度,它等于 $n(n - 1) / 2$ +* 逆序度:序列中不满足偏序关系的亮亮组合的元素对的个数 + +显然,$\text{逆序度} = \text{满有序度} - \text{有序度}$。 + +在冒泡排序中,每产生一次「交换」操作,$\text{逆序度}--$。于是,平均情况下,需要 $n(n - 1)/4$ 次交换操作,它已经是 $O(n^2)$ 了。因此,尽管比较操作的数量会大于交换操作的数量,但我们依然能说,冒泡排序的平均时间复杂度是 $O(n^2)$。 + +> 分析过程不严格,但足够说明问题。 + +## 插入排序 + +1. 将待排序数列分为已排序区间和未排序区间 +2. 取未排序区间的第一个元素 +3. 遍历已排序区间,按照偏序关系,寻找合适的位置,插入未排序区间的第一个元素 +4. 重复 2 -- 3 直至未排序区间长度为零 + +![插入排序例图](https://static001.geekbang.org/resource/image/fd/01/fd6582d5e5927173ee35d7cc74d9c401.jpg) + +分析: + +* 原地排序 +* 稳定排序(值相同的元素,往后插) +* 时间复杂度 + * 最好 $O(n)$ + * 最坏 $O(n^2)$ + * 平均 $O(n^2)$(乘法法则) + +## 选择排序 + +1. 将待排序数列分为已排序区间和未排序区间 +2. 遍历未排序区间,取未排序区间的最小元素 +3. 交换上述最小元素与未排序区间中的第一个元素的位置 +4. 重复 2 -- 3 直至未排序区间长度为零 + +![选择排序例图](https://static001.geekbang.org/resource/image/32/1d/32371475a0b08f0db9861d102474181d.jpg) + +分析: + +* 非原地排序 +* 非稳定排序 +* 时间复杂度 + * 最好 $O(n^2)$ + * 最坏 $O(n^2)$ + * 平均 $O(n^2)$(乘法法则) + +## 开篇问题 + +* 对同一份未排序序列数据,冒泡排序和插入排序所需的交换(移动)次数是一定的,且是相等的 +* 单次数据交换,冒泡排序所需的时间更长(三次赋值操作,插排只需要一次) + +另有插入排序的优化版本[希尔排序](https://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F)。 + +![小结](https://static001.geekbang.org/resource/image/34/50/348604caaf0a1b1d7fee0512822f0e50.jpg) diff --git a/python/05_array/myarray.py b/python/05_array/myarray.py index e4df25b..8eea274 100644 --- a/python/05_array/myarray.py +++ b/python/05_array/myarray.py @@ -9,35 +9,53 @@ class MyArray: """A simple wrapper around List. You cannot have -1 in the array. """ + def __init__(self, capacity: int): + self._data = [] self._count = 0 self._capacity = capacity def __getitem__(self, position: int) -> int: + """Support for subscript. Perhaps better than the find() method below. """ return self._data[position] def find(self, index: int) -> Optional[int]: + if index >= self._count or index <= -self._count: return None return self._data[index] def delete(self, index: int) -> bool: + if index >= self._count or index <= -self._count: return False + self._data[index:-1] = self._data[index+1:] self._count -= 1 + # 真正将数据删除并覆盖原来的数据 ,这个需要增加 + self._data = self._data[0:self._count] + print ('delet function',self._data) return True def insert(self, index: int, value: int) -> bool: - if index >= self._count or index <= -self._count: return False + + #if index >= self._count or index <= -self._count: return False if self._capacity == self._count: return False - self._data.insert(index, value) + # 如果还有空间,那么插入位置大于当前的元素个数,可以插入最后的位置 + if index >= self._count: + self._data.append(value) + # 同上,如果位置小于0 可以插入第0个位置. + if index < 0: + print (index) + self._data.insert(0, value) + self._count += 1 return True def insert_to_tail(self, value: int) -> bool: + if self._count == self._capacity: return False if self._count == len(self._data): self._data.append(value) @@ -47,11 +65,13 @@ class MyArray: return True def __repr__(self) -> str: + return " ".join(str(num) for num in self._data[:self._count]) def print_all(self): + for num in self._data[:self._count]: - print(f"{num}", end=" ") + print("{num}", end=" ") print("\n", flush=True) if __name__ == "__main__": @@ -59,7 +79,10 @@ if __name__ == "__main__": for i in range(6): a.insert_to_tail(i) - a.delete(2) - print(a) - a.insert_to_tail(7) - print(a) \ No newline at end of file + print('origin',a) + a.delete(4) + print ('delete ',a) + + a.insert(100,10000) + print (a) + diff --git a/python/06_linkedlist/palindrome.py b/python/06_linkedlist/palindrome.py new file mode 100644 index 0000000..25dd69e --- /dev/null +++ b/python/06_linkedlist/palindrome.py @@ -0,0 +1,54 @@ +""" + check a single-linked list whether a palindrome +""" + +import sys +# 引用当前文件夹下的single_linked_list +sys.path.append('singly_linked_list') +from singly_linked_list import SinglyLinkedList + +def reverse(head): + reverse_head = None + while head: + next = head._next + head._next = reverse_head + reverse_head = head + head = next + + return reverse_head + +def is_palindrome(l): + l.print_all() + slow = l._head + fast = l._head + position = 0 + while fast and fast._next: + slow = slow._next + fast = fast._next._next + position += 1 + + reverse_node = reverse(slow) + head_node = l._head + is_palin = True + while (head_node and reverse_node): + if (head_node.data == reverse_node.data): + head_node = head_node._next + reverse_node = reverse_node._next + else: + is_palin = False + break + + return is_palin + +if __name__ == '__main__': + # the result should be False, True, True, True, True + test_str_arr = ['ab', 'aa', 'aba', 'abba', 'abcba'] + for str in test_str_arr: + l = SinglyLinkedList() + for i in str: + l.insert_value_to_head(i) + + print(is_palindrome(l)) + + + diff --git a/python/09_queue/array_queue.py b/python/09_queue/array_queue.py index 1b1252e..b8ffe4b 100644 --- a/python/09_queue/array_queue.py +++ b/python/09_queue/array_queue.py @@ -21,7 +21,7 @@ class ArrayQueue: return False else: for i in range(0, self._tail - self._head): - self._data[i] = self._items[i + self._head] + self._items[i] = self._items[i + self._head] self._tail = self._tail - self._head self._head = 0 diff --git a/python/11_sorts/sorts.py b/python/11_sorts/sorts.py index 7e7f488..b9e3493 100644 --- a/python/11_sorts/sorts.py +++ b/python/11_sorts/sorts.py @@ -11,8 +11,8 @@ from typing import List def bubble_sort(a: List[int]): if len(a) <= 1: return - made_swap = False for i in range(len(a)): + made_swap = False for j in range(len(a) - i - 1): if a[j] > a[j+1]: a[j], a[j+1] = a[j+1], a[j] diff --git a/python/12_sorts/merge_sort.py b/python/12_sorts/merge_sort.py new file mode 100644 index 0000000..9bcacec --- /dev/null +++ b/python/12_sorts/merge_sort.py @@ -0,0 +1,48 @@ +""" + Author: Wenru +""" + +from typing import List + +def merge_sort(a: List[int]): + _merge_sort_between(a, 0, len(a)-1) + +def _merge_sort_between(a: List[int], low: int, high: int): + # The indices are inclusive for both low and high. + if low >= high: return + mid = low + (high - low)//2 + _merge_sort_between(a, low, mid) + _merge_sort_between(a, mid+1, high) + + _merge(a, low, mid, high) + +def _merge(a: List[int], low: int, mid: int, high: int): + # a[low:mid], a[mid+1, high] are sorted. + i, j = low, mid+1 + tmp = [] + while i <= mid and j <= high: + if a[i] <= a[j]: + tmp.append(a[i]) + i += 1 + else: + tmp.append(a[j]) + j += 1 + start = i if i <= mid else j + end = mid if i <= mid else high + tmp.extend(a[start:end+1]) + a[low:high+1] = tmp + + +if __name__ == "__main__": + a1 = [3, 5, 6, 7, 8] + a2 = [2, 2, 2, 2] + a3 = [4, 3, 2, 1] + a4 = [5, -1, 9, 3, 7, 8, 3, -2, 9] + merge_sort(a1) + print(a1) + merge_sort(a2) + print(a2) + merge_sort(a3) + print(a3) + merge_sort(a4) + print(a4) \ No newline at end of file diff --git a/python/12_sorts/quick_sort.py b/python/12_sorts/quick_sort.py new file mode 100644 index 0000000..f426751 --- /dev/null +++ b/python/12_sorts/quick_sort.py @@ -0,0 +1,43 @@ +""" + Author: Wenru +""" + +from typing import List +import random + +def quick_sort(a: List[int]): + _quick_sort_between(a, 0, len(a)-1) + +def _quick_sort_between(a: List[int], low: int, high: int): + if low >= high: return + # get a random position as the pivot + k = random.randint(low, high) + a[low], a[k] = a[k], a[low] + + m = _partition(a, low, high) # a[m] is in final position + _quick_sort_between(a, low, m-1) + _quick_sort_between(a, m+1, high) + +def _partition(a: List[int], low: int, high: int): + pivot, j = a[low], low + for i in range(low+1, high+1): + if a[i] <= pivot: + j += 1 + a[j], a[i] = a[i], a[j] # swap + a[low], a[j] = a[j], a[low] + return j + + +if __name__ == "__main__": + a1 = [3, 5, 6, 7, 8] + a2 = [2, 2, 2, 2] + a3 = [4, 3, 2, 1] + a4 = [5, -1, 9, 3, 7, 8, 3, -2, 9] + quick_sort(a1) + print(a1) + quick_sort(a2) + print(a2) + quick_sort(a3) + print(a3) + quick_sort(a4) + print(a4) \ No newline at end of file diff --git a/python/14_sorts/counting_sort.py b/python/14_sorts/counting_sort.py new file mode 100644 index 0000000..1bdcd8b --- /dev/null +++ b/python/14_sorts/counting_sort.py @@ -0,0 +1,40 @@ +""" + 计数排序 + + Author: Wenru +""" + +from typing import List +import itertools + +def counting_sort(a: List[int]): + if len(a) <= 1: return + + # a中有counts[i]个数不大于i + counts = [0] * (max(a) + 1) + for num in a: + counts[num] += 1 + counts = list(itertools.accumulate(counts)) + + # 临时数组,储存排序之后的结果 + a_sorted = [0] * len(a) + for num in reversed(a): + index = counts[num] - 1 + a_sorted[index] = num + counts[num] -= 1 + + a = a_sorted + + +if __name__ == "__main__": + a1 = [1, 2, 3, 4] + counting_sort(a1) + print(a1) + + a2 = [1, 1, 1, 1] + counting_sort(a2) + print(a2) + + a3 = [4, 5, 0, 9, 3, 3, 1, 9, 8, 7] + counting_sort(a3) + print(a3) \ No newline at end of file diff --git a/swift/12_sorts/.DS_Store b/swift/12_sorts/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/swift/12_sorts/.DS_Store differ diff --git a/swift/12_sorts/QuickSort.swift b/swift/12_sorts/QuickSort.swift new file mode 100644 index 0000000..984527f --- /dev/null +++ b/swift/12_sorts/QuickSort.swift @@ -0,0 +1,36 @@ +// +// QuickSort.swift +// algo +// +// Created by Wenru Dong on 2018/10/17. +// Copyright © 2018年 Wenru Dong. All rights reserved. +// + +import Foundation + +public func quickSort(_ a: inout T) where T.Element: Comparable { + quickSort(&a, from: a.startIndex, to: a.index(before: a.endIndex)) +} + +fileprivate func quickSort(_ a: inout T, from low: T.Index, to high: T.Index) where T.Element: Comparable { + if low >= high { return } + + let m = partition(&a, from: low, to: high) + quickSort(&a, from: low, to: a.index(before: m)) + quickSort(&a, from: a.index(after: m), to: high) +} + +fileprivate func partition(_ a: inout T, from low: T.Index, to high: T.Index) -> T.Index where T.Element: Comparable { + let pivot = a[low] + var j = low + var i = a.index(after: low) + while i <= high { + if a[i] < pivot { + a.formIndex(after: &j) + a.swapAt(i, j) + } + a.formIndex(after: &i) + } + a.swapAt(low, j) + return j +} diff --git a/swift/12_sorts/SortsTests.swift b/swift/12_sorts/SortsTests.swift new file mode 100644 index 0000000..7100aed --- /dev/null +++ b/swift/12_sorts/SortsTests.swift @@ -0,0 +1,58 @@ +// +// SortsTests.swift +// SortsTests +// +// Created by Wenru Dong on 2018/10/14. +// Copyright © 2018年 Wenru Dong. All rights reserved. +// + +import XCTest + +class SortsTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testMergeSort() { + var a1 = [1, 1, 1, 1] + mergeSort(&a1) + XCTAssertEqual(a1, [1, 1, 1, 1]) + + var a2 = [4, 3, 2, 1] + mergeSort(&a2) + XCTAssertEqual(a2, [1, 2, 3, 4]) + + var a3 = [3, 6, 9, 7, 8, -1, 9, 3, -2, 0] + mergeSort(&a3) + XCTAssertEqual(a3, [-2, -1, 0, 3, 3, 6, 7, 8, 9, 9]) + } + + func testQuickSort() { + var a1 = [1, 1, 1, 1] + quickSort(&a1) + XCTAssertEqual(a1, [1, 1, 1, 1]) + + var a2 = [4, 3, 2, 1] + quickSort(&a2) + XCTAssertEqual(a2, [1, 2, 3, 4]) + + var a3 = [3, 6, 9, 7, 8, -1, 9, 3, -2, 0] + quickSort(&a3) + XCTAssertEqual(a3, [-2, -1, 0, 3, 3, 6, 7, 8, 9, 9]) + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/swift/12_sorts/mergeSort.swift b/swift/12_sorts/mergeSort.swift new file mode 100644 index 0000000..7050164 --- /dev/null +++ b/swift/12_sorts/mergeSort.swift @@ -0,0 +1,52 @@ +// +// sorts.swift +// algo +// +// Created by Wenru Dong on 2018/10/14. +// Copyright © 2018年 Wenru Dong. All rights reserved. +// + +import Foundation + +public func mergeSort(_ a: inout T) where T: RandomAccessCollection, T: MutableCollection, T.Element: Comparable { + mergeSort(&a, from: a.startIndex, to: a.index(before: a.endIndex)) +} + +fileprivate func mergeSort(_ a: inout T, from low: T.Index, to high: T.Index) where T: RandomAccessCollection, T: MutableCollection, T.Element: Comparable { + if low >= high { return } + let dist = a.distance(from: low, to: high) + let mid = a.index(low, offsetBy: dist/2) + mergeSort(&a, from: low, to: mid) + mergeSort(&a, from: a.index(mid, offsetBy: 1), to: high) + merge(&a, from: low, through: mid, to: high) +} + +fileprivate func merge(_ a: inout T, from low: T.Index, through mid: T.Index, to high: T.Index) where T: RandomAccessCollection, T: MutableCollection, T.Element: Comparable { + var i = low + var j = a.index(mid, offsetBy: 1) + var tmp = Array() + tmp.reserveCapacity(a.distance(from: low, to: high) + 1) + while i <= mid && j <= high { + if a[i] <= a[j] { + tmp.append(a[i]) + a.formIndex(after: &i) + } else { + tmp.append(a[j]) + a.formIndex(after: &j) + } + } + + var start = i + var end = mid + if j <= high { + start = j + end = high + } + tmp.append(contentsOf: a[start...end]) + + var current = low + for element in tmp { + a[current] = element + a.formIndex(after: ¤t) + } +} diff --git a/swift/14_sorts/CountingSort.swift b/swift/14_sorts/CountingSort.swift new file mode 100644 index 0000000..fc0dc93 --- /dev/null +++ b/swift/14_sorts/CountingSort.swift @@ -0,0 +1,33 @@ +// +// CountingSort.swift +// algo +// +// Created by Wenru Dong on 2018/10/18. +// Copyright © 2018年 Wenru Dong. All rights reserved. +// + +import Foundation + +// 假设数组中储存的都是非负整数 +public func countingSort(_ a: inout [Int]) { + if a.count <= 1 { return } + + var counts = Array(repeating: 0, count: a.max()! + 1) + for num in a { + counts[num] += 1 + } + for i in 1..