Merge pull request #7 from wangzheng0822/master

合并上游代码
This commit is contained in:
leo 2018-10-24 11:30:59 +08:00 committed by GitHub
commit f0c4d7a167
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1278 additions and 76 deletions

0
c-cpp/11_sorts/.gitkeep Normal file
View File

139
c-cpp/11_sorts/sorts.c Normal file
View File

@ -0,0 +1,139 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
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;
}

47
c-cpp/11_sorts/sorts.cpp Normal file
View File

@ -0,0 +1,47 @@
// C program for implementation of selection sort
#include <stdio.h>
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;
}

89
c-cpp/11_sorts/sorts.hpp Normal file
View File

@ -0,0 +1,89 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/16.
*/
#ifndef SORTS_SORTS_HPP_
#define SORTS_SORTS_HPP_
#include <iterator>
#include <functional>
template <typename BidirIt,
typename BinaryPred = std::less<typename std::iterator_traits<BidirIt>::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 <typename BidirIt,
typename BinaryPred = std::less<typename std::iterator_traits<BidirIt>::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 <typename BidirIt,
typename BinaryPred = std::less<typename std::iterator_traits<BidirIt>::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 <typename FrwdIt,
typename BinaryPred = std::less<typename std::iterator_traits<FrwdIt>::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 <typename BidirIt,
typename BinaryPred = std::less<typename std::iterator_traits<BidirIt>::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_

View File

@ -0,0 +1,45 @@
#include <iostream>
#include <vector>
#include "sorts.hpp"
int main() {
const std::vector<int> test_data{1, 2, 3, 0};
std::vector<int> 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<int> 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<int> 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<int> 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<int> 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;
}

0
c-cpp/12_sorts/.gitkeep Normal file
View File

View File

@ -0,0 +1,62 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/17.
*/
#ifndef SORTS_MERGE_SORT_HPP_
#define SORTS_MERGE_SORT_HPP_
#include <functional>
#include <algorithm>
#include <iterator>
#include <vector>
namespace detail {
template <typename InputIt1, typename InputIt2, typename OutputIt,
typename BinaryPred = std::less<typename std::iterator_traits<InputIt1>::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 <typename FrwdIt,
typename BinaryPred = std::less<typename std::iterator_traits<FrwdIt>::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<typename std::iterator_traits<FrwdIt>::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 <typename BidirIt,
typename BinaryPred = std::less<typename std::iterator_traits<BidirIt>::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_

View File

@ -0,0 +1,28 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/17.
*/
#include <iostream>
#include <vector>
#include "merge_sort.hpp"
int main() {
const std::vector<int> test_data{0, -1, 3, 190, -500};
std::vector<int> a{test_data};
merge_sort(a.begin(), a.end());
for (auto i : a) {
std::cout << i << ' ';
}
std::cout << std::endl;
std::vector<int> b{test_data};
inplace_merge_sort(b.begin(), b.end());
for (auto i : b) {
std::cout << i << ' ';
}
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,71 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/17.
*/
#ifndef SORTS_QUICK_SORT_HPP_
#define SORTS_QUICK_SORT_HPP_
#include <functional>
#include <iterator>
#include <algorithm>
#include <utility>
namespace detail {
template <typename T, typename Compare = std::less<T>>
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 <typename Iter,
typename T = typename std::iterator_traits<Iter>::value_type,
typename Compare = std::less<T>>
const T& iter_median(Iter a, Iter b, Iter c, Compare comp = Compare()) {
return median(*a, *b, *c, comp);
}
template <typename BidirIt,
typename T = typename std::iterator_traits<BidirIt>::value_type,
typename Compare = std::less<T>>
std::pair<BidirIt, BidirIt> 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 <typename BidirIt,
typename T = typename std::iterator_traits<BidirIt>::value_type,
typename Compare = std::less<T>>
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_

View File

@ -0,0 +1,25 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/17.
*/
#include <iostream>
#include <vector>
#include <algorithm>
#include "quick_sort.hpp"
void test_quick_sort(std::vector<int> test_data) {
quick_sort(test_data.begin(), test_data.end());
std::transform(test_data.begin(), test_data.end(),
std::ostream_iterator<int>(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;
}

View File

@ -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]
}
}

View File

@ -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)
}

View File

@ -1,21 +1,21 @@
/**
*
*
* 1泛型动态数组
*
* Author: shi
* Author: shi
*/
public class GenericArray<T> {
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.");
}
}
}

View File

@ -58,6 +58,9 @@ public class Sorts {
}
}
if (minIndex == i)
continue;
// 交换
int tmp = a[i];
a[i] = a[minIndex];

View File

@ -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];
}
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)

100
notes/11_sorts/readme.md Normal file
View File

@ -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)

View File

@ -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)
print('origin',a)
a.delete(4)
print ('delete ',a)
a.insert(100,10000)
print (a)

View File

@ -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))

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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)

View File

@ -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)

BIN
swift/12_sorts/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -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<T: RandomAccessCollection & MutableCollection>(_ a: inout T) where T.Element: Comparable {
quickSort(&a, from: a.startIndex, to: a.index(before: a.endIndex))
}
fileprivate func quickSort<T: RandomAccessCollection & MutableCollection>(_ 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<T: RandomAccessCollection & MutableCollection>(_ 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
}

View File

@ -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.
}
}
}

View File

@ -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<T>(_ 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<T>(_ 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<T>(_ 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<T.Element>()
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: &current)
}
}

View File

@ -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..<counts.count {
counts[i] = counts[i-1] + counts[i]
}
var aSorted = Array(repeating: 0, count: a.count)
for num in a.reversed() {
let index = counts[num] - 1
aSorted[index] = num
counts[num] -= 1
}
for (i, num) in aSorted.enumerated() {
a[i] = num
}
}