This commit is contained in:
wangzheng 2018-10-28 23:07:51 +08:00
commit d4eba0b686
61 changed files with 2539 additions and 75 deletions

View File

@ -33,7 +33,7 @@ int insert(struct array *array, int elem)
}
if (idx < array->used)
memmove(&array->arr[array->used], &array->arr[idx],
memmove(&array->arr[idx+1], &array->arr[idx],
(array->used - idx) * sizeof(int));
array->arr[idx] = elem;

View File

@ -0,0 +1,281 @@
#include "singleList.h"
#include <string.h>
linkedList * listCreate()
{
linkedList *list = NULL;
list = malloc(sizeof(*list));
if (NULL == list)
{
return NULL;
}
list->dup = NULL;
list->free = NULL;
list->match = NULL;
list->head = NULL;
list->len = 0;
return list;
}
// 释放
void listRelease(linkedList *list)
{
if (NULL == list)
{
return;
}
listEmpty(list);
free(list);
list = NULL;
}
void listEmpty(linkedList *list)
{
if (NULL == list)
{
return;
}
while (NULL != list->head)
{
listNode *pNode = list->head;
list->head = pNode->next;
if (NULL != list->free)
{
list->free(pNode->value);
}
else
{
free(pNode->value);
}
pNode->next = NULL;
free(pNode);
pNode = NULL;
}
}
linkedList * listAddNodeHead(linkedList *list, void * value)
{
if (NULL == list || NULL == value)
{
return list;
}
listNode *node = NULL;
node = malloc(sizeof(*node));
if (NULL == node)
{
return list;
}
node->value = value;
node->next = list->head;
list->head = node;
++list->len;
return list;
}
linkedList * listAddNodeTail(linkedList *list, void *value)
{
if (NULL == list || NULL == value)
{
return list;
}
listNode *node = NULL;
node = malloc(sizeof(*node));
if (NULL == node)
{
return list;
}
node->value = value;
node->next = NULL;
if (NULL == list->head
&& list->len == 0)
{
list->head = node;
}
else
{
listNode *tail = list->head;
listNode *pre = list->head;
while (NULL != tail)
{
pre = tail;
tail = tail->next;
}
pre->next = node;
}
++list->len;
return list;
}
linkedList * listInsertNode(linkedList *list, listNode *old_node, void *value, bool after)
{
if (NULL == list || NULL == old_node)
{
return list;
}
listNode *pNode = NULL;
pNode = malloc(sizeof(*pNode));
if (NULL == pNode)
{
return list;
}
pNode->value = value;
if (after)
{
pNode->next = old_node->next;
old_node->next = pNode;
}
else
{
listNode *pre = list->head;
while (pre->next != old_node)
{
pre = pre->next;
}
if (NULL != pre)
{
pre->next = pNode;
pNode->next = old_node;
}
}
++list->len;
return list;
}
// 没设置释放函数时不做释放处理
void listDelNode(linkedList *list, listNode *node)
{
if (NULL == list || NULL == node)
{
return;
}
listNode *pre = list->head;
listNode *cur = list->head;
while (NULL != cur && cur != node)
{
pre = cur;
cur = cur->next;
}
// 不在该链表中
if (NULL == pre)
{
return;
}
pre->next = node->next;
node->next = NULL;
--list->len;
if (NULL != list->free)
{
list->free(node->value);
free(node);
node = NULL;
}
}
listNode * listSearchKey(linkedList *list, void *key)
{
if (NULL == list)
{
return NULL;
}
listNode *node = list->head;
while (NULL != node)
{
if (NULL != list->match)
{
if (list->match(key, node->value) == 0)
{
return node;
}
}
else
{
if (key == node->value)
{
return node;
}
}
node = node->next;
}
return NULL;
}
listNode * listIndex(linkedList *list, long index)
{
if (NULL == list)
{
return NULL;
}
if (index <= 0
|| index > list->len)
{
return NULL;
}
listNode *pNode = list->head;
for (long i = 0; i < index; ++i)
{
pNode = pNode->next;
}
return pNode;
}
linkedList* listRewind(linkedList *list)
{
if (NULL == list)
{
return NULL;
}
listNode *head = list->head;
listNode *pre = NULL;
listNode *next = NULL;
while (NULL != head)
{
next = head->next;
head->next = pre;
pre = head;
head = next;
}
list->head = pre;
return list;
}
size_t listLength(linkedList *list)
{
if (NULL == list)
{
return 0;
}
return list->len;
}

View File

@ -0,0 +1,46 @@
#ifndef __SINGLELIST_H__
#define __SINGLELIST_H__
#include <stdlib.h>
#include <stdbool.h>
typedef struct listNode
{
struct listNode *next;
void *value;
}listNode;
typedef struct linkedList
{
listNode *head;
size_t len;
size_t typesize;
void(*dup)(void*, void*);
int(*match)(void*, void*);
void(*free)(void*);
}linkedList;
#define listSetDupMethod(l,m) ((l)->dup = (m))
#define listSetFreeMethod(l,m) ((l)->free = (m))
#define listSetMatchMethod(l,m) ((l)->match = (m))
#define listGetDupMethod(l) ((l)->dup)
#define listGetFree(l) ((l)->free)
#define listGetMatchMethod(l) ((l)->match)
linkedList *listCreate();
void listRelease(linkedList *list);
void listEmpty(linkedList *list);
linkedList *listAddNodeHead(linkedList *list, void *value);
linkedList *listAddNodeTail(linkedList *list, void *value);
linkedList *listInsertNode(linkedList *list, listNode *old_node, void *value, bool after);
void listDelNode(linkedList *list, listNode *node);
listNode *listSearchKey(linkedList *list, void *key);
listNode *listIndex(linkedList *list, long index);
linkedList* listRewind(linkedList *list);
size_t listLength(linkedList *list);
#endif // !__SINGLELIST_H__

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,84 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
void dump(int *arr, int size)
{
int idx;
for (idx = 0; idx < size; idx++)
printf("%08d\n", arr[idx]);
}
void __merge(int *arr, int p, int q, int r)
{
int *tmp;
int i, j, k;
tmp = (int*)malloc((r - p + 1) * sizeof(int));
if (!tmp)
abort();
for (i = p, j = q + 1, k = 0; i <= q && j <= r;) {
if (arr[i] <= arr[j])
tmp[k++] = arr[i++];
else
tmp[k++] = arr[j++];
}
if (i == q + 1) {
for (; j <= r;)
tmp[k++] = arr[j++];
} else {
for (; i <= q;)
tmp[k++] = arr[i++];
}
memcpy(arr + p, tmp, (r - p + 1) * sizeof(int));
free(tmp);
}
void __merge_sort(int *arr, int p, int r)
{
int q;
if (p >= r)
return;
q = (p + r) / 2;
__merge_sort(arr, p, q);
__merge_sort(arr, q + 1, r);
__merge(arr, p, q, r);
}
void merge_sort(int *arr, int size)
{
__merge_sort(arr, 0, size - 1);
}
void merge_verify()
{
int test[10] = {5, 8, 9, 23, 67, 1, 3, 7, 31, 56};
__merge(test, 0, 4, 9);
dump(test, 10);
}
void merge_sort_test()
{
int test[10] = {5, 8, 9, 23, 67, 1, 3, 7, 31, 56};
merge_sort(test, 10);
dump(test, 10);
}
int main()
{
//merge_verify();
merge_sort_test();
return 0;
}

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;
inplace_merge_sort(first, cut, comp);
inplace_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,69 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
void dump(int *arr, int size)
{
int idx;
for (idx = 0; idx < size; idx++)
printf("%08d\n", arr[idx]);
}
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int partition(int *arr, int p, int r)
{
//int pivot = arr[r];
int i, j;
i = j = p;
for (; j < r; j++) {
if (arr[j] < arr[r]) {
swap(arr + i, arr + j);
i++;
}
}
swap(arr + i, arr + r);
return i;
}
void __quick_sort(int *arr, int p, int r)
{
int q;
if (p >= r)
return;
q = partition(arr, p, r);
__quick_sort(arr, p, q-1);
__quick_sort(arr, q+1, r);
}
void quick_sort(int *arr, int size)
{
__quick_sort(arr, 0, size - 1);
}
void quick_sort_test()
{
int test[10] = {5, 8, 9, 23, 67, 1, 3, 7, 31, 56};
quick_sort(test, 10);
dump(test, 10);
}
int main()
{
quick_sort_test();
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;
}

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

View File

@ -0,0 +1,8 @@
# C++ STL 中的 std::sort 分析
参见 [Liam Huang 的博客](https://liam.page/)中的 3 篇文章:
* [谈谈基于比较的排序算法的复杂度下界](https://liam.page/2018/08/28/lower-bound-of-comparation-based-sort-algorithm/)
* [谈谈内省式排序算法](https://liam.page/2018/08/29/introspective-sort/)
* [谈谈 STL 中的 std::sort](https://liam.page/2018/09/18/std-sort-in-STL/)

View File

@ -0,0 +1,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
void dump(int *arr, int size)
{
int i;
for (i = 0; i < size; i++)
printf("%08d\n", arr[i]);
}
// content in arr must be positive integer
void counting_sort(int *arr, int size)
{
int max, i;
int *count, *tmp;
if (size <= 1)
return;
max = 0;
// find the biggest integer
for (i = 0; i < size; i++) {
if (max < arr[i])
max = arr[i];
}
// init count to 0
count = (int*)malloc((max+1) * sizeof(int));
tmp = (int*)malloc(size * sizeof(int));
if (!count || !tmp)
return;
memset(count, 0, (max + 1) * sizeof(int));
// counting
for (i = 0; i < size; i++)
count[arr[i]]++;
for (i = 1; i < max + 1; i++)
count[i] = count[i-1] + count[i];
// iterate arr and put it to the correct index in tmp
for (i = 0; i < size; i++){
int index = count[arr[i]] - 1;
tmp[index] = arr[i];
count[arr[i]]--;
}
// move back to arr
memcpy(arr, tmp, size * sizeof(int));
}
void counting_sort_test()
{
int test_data[10] = {3, 23, 98, 1, 27, 36, 52, 89, 76, 44};
counting_sort(test_data, 10);
dump(test_data, 10);
}
int main()
{
counting_sort_test();
return 0;
}

View File

View File

@ -0,0 +1,66 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/24.
*/
#ifndef BSEARCH_BSEARCH_HPP_
#define BSEARCH_BSEARCH_HPP_
#include <iterator>
#include <functional>
enum class BsearchPolicy { FIRST, LAST, UNSPECIFIED };
// Liam Huang: The algorithm works right with iterators that meet the ForwardIterator requirement,
// but with a bad time complexity. For better performance, iterators should meet
// the RandomAccessIterator requirement.
template <typename IterT,
typename ValueT = typename std::iterator_traits<IterT>::value_type,
typename Compare>
IterT bsearch(IterT first,
IterT last,
ValueT target,
Compare comp,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
IterT result = last;
while (std::distance(first, last) > 0) {
IterT mid = first + std::distance(first, last) / 2;
if (comp(*mid, target)) {
first = mid + 1;
} else if (comp(target, *mid)) {
last = mid;
} else { // equal
if (policy == BsearchPolicy::FIRST) {
if (mid == first or comp(*(mid - 1), *mid)) {
result = mid;
break;
} else {
last = mid;
}
} else if (policy == BsearchPolicy::LAST) {
if (std::distance(mid, last) == 1 or comp(*mid, *(mid + 1))) {
result = mid;
break;
} else {
first = mid + 1;
}
} else {
result = mid;
break;
}
}
}
return result;
}
template <typename IterT,
typename ValueT = typename std::iterator_traits<IterT>::value_type,
typename Compare = std::less<ValueT>>
IterT bsearch(IterT first,
IterT last,
ValueT target,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
return bsearch(first, last, target, Compare(), policy);
}
#endif // BSEARCH_BSEARCH_HPP_

View File

@ -0,0 +1,38 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/24.
*/
#include <iostream>
#include <vector>
#include "bsearch.hpp"
template <typename VecT, typename T = typename VecT::value_type>
void test_bsearch(const VecT& test,
T target,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
auto it = bsearch(test.begin(), test.end(), target, policy);
std::cout << std::distance(test.begin(), it) << std::endl;
}
int main() {
std::vector<int> test{0, 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 5, 6, 7}; // std::less<int>()
test_bsearch(test, 8); // 14
test_bsearch(test, -1); // 14
test_bsearch(test, 0); // 0, 1
test_bsearch(test, 0, BsearchPolicy::FIRST); // 0
test_bsearch(test, 0, BsearchPolicy::LAST); // 1
test_bsearch(test, 4); // 5, 6
test_bsearch(test, 4, BsearchPolicy::FIRST); // 5
test_bsearch(test, 4, BsearchPolicy::LAST); // 6
test_bsearch(test, 5); // 7, 8, 9, 10, 11
test_bsearch(test, 5, BsearchPolicy::FIRST); // 7
test_bsearch(test, 5, BsearchPolicy::LAST); // 11
test_bsearch(test, 7); // 13
test_bsearch(test, 7, BsearchPolicy::FIRST); // 13
test_bsearch(test, 7, BsearchPolicy::LAST); // 13
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)
}

48
go/12_sorts/MergeSort.go Normal file
View File

@ -0,0 +1,48 @@
package _2_sorts
func MergeSort(arr []int) {
arrLen := len(arr)
if arrLen <= 1 {
return
}
mergeSort(arr, 0, arrLen-1)
}
func mergeSort(arr []int, start, end int) {
if start >= end {
return
}
mid := (start + end) / 2
mergeSort(arr, start, mid)
mergeSort(arr, mid+1, end)
merge(arr, start, mid, end)
}
func merge(arr []int, start, mid, end int) {
tmpArr := make([]int, end-start+1)
i := start
j := mid + 1
k := 0
for ; i <= mid && j <= end; k++ {
if arr[i] < arr[j] {
tmpArr[k] = arr[i]
i++
} else {
tmpArr[k] = arr[j]
j++
}
}
for ; i <= mid; i++ {
tmpArr[k] = arr[i]
k++
}
for ; j <= end; j++ {
tmpArr[k] = arr[j]
k++
}
copy(arr[start:end+1], tmpArr)
}

View File

@ -0,0 +1,13 @@
package _2_sorts
import "testing"
func TestMergeSort(t *testing.T) {
arr := []int{5, 4}
MergeSort(arr)
t.Log(arr)
arr = []int{5, 4, 3, 2, 1}
MergeSort(arr)
t.Log(arr)
}

38
go/12_sorts/QuickSort.go Normal file
View File

@ -0,0 +1,38 @@
package _2_sorts
func QuickSort(arr []int) {
arrLen := len(arr)
if arrLen <= 1 {
return
}
quickSort(arr, 0, arrLen-1)
}
func quickSort(arr []int, start, end int) {
if start >= end {
return
}
pivot := partition(arr, start, end)
quickSort(arr, start, pivot)
quickSort(arr, pivot+1, end)
}
func partition(arr []int, low, high int) int {
pivotV := arr[low]
for low < high {
for low < high && arr[high] > pivotV { //指针从右边开始向右找到一个比pivot小的数
high--
}
arr[low] = arr[high] //将这个数放到low位注意第一次这个位置放的是pivot值所以不会丢
for low < high && arr[low] < pivotV { //指针从左边开始向右找到第一个比pivot大的数
low++
}
arr[high] = arr[low] //将这个数赋值给之前的high指针因为之前high指针指向的数已经被一定所以不会丢
}
//最后将pivot的值放入合适位置此时low与high相等
arr[low] = pivotV
return low
}

View File

@ -0,0 +1,13 @@
package _2_sorts
import "testing"
func TestQuickSort(t *testing.T) {
arr := []int{5, 4}
QuickSort(arr)
t.Log(arr)
arr = []int{5, 4, 3, 2, 1}
QuickSort(arr)
t.Log(arr)
}

View File

@ -0,0 +1,33 @@
package _4_sorts
import "math"
func CountingSort(a []int, n int) {
if n <= 1 {
return
}
var max int = math.MinInt32
for i := range a {
if a[i] > max {
max = a[i]
}
}
c := make([]int, max+1)
for i := range a {
c[a[i]]++
}
for i := 1; i <= max; i++ {
c[i] += c[i-1]
}
r := make([]int, n)
for i := range a {
index := c[a[i]] - 1
r[index] = a[i]
c[a[i]]--
}
copy(a, r)
}

View File

@ -0,0 +1,13 @@
package _4_sorts
import "testing"
func TestCountingSort(t *testing.T) {
arr := []int{5, 4}
CountingSort(arr, len(arr))
t.Log(arr)
arr = []int{5, 4, 3, 2, 1}
CountingSort(arr, len(arr))
t.Log(arr)
}

View File

@ -0,0 +1,47 @@
package _5_binarysearch
func BinarySearch(a []int, v int) int {
n := len(a)
if n == 0 {
return -1
}
low := 0
high := n - 1
for low <= high {
mid := (low + high) / 2
if a[mid] == v {
return mid
} else if a[mid] > v {
high = mid - 1
} else {
low = mid + 1
}
}
return -1
}
func BinarySearchRecursive(a []int, v int) int {
n := len(a)
if n == 0 {
return -1
}
return bs(a, v, 0, n-1)
}
func bs(a []int, v int, low, high int) int {
if low > high {
return -1
}
mid := (low + high) / 2
if a[mid] == v {
return mid
} else if a[mid] > v {
return bs(a, v, low, mid-1)
} else {
return bs(a, v, mid+1, high)
}
}

View File

@ -0,0 +1,27 @@
package _5_binarysearch
import "testing"
func TestBinarySearch(t *testing.T) {
var a []int
a = []int{1, 3, 5, 6, 8}
if BinarySearch(a, 8) != 4 {
t.Fatal(BinarySearch(a, 3))
}
if BinarySearch(a, 4) != -1 {
t.Fatal(BinarySearch(a, 4))
}
}
func TestBinarySearchRecursive(t *testing.T) {
var a []int
a = []int{1, 3, 5, 6, 8}
if BinarySearchRecursive(a, 8) != 4 {
t.Fatal(BinarySearch(a, 3))
}
if BinarySearchRecursive(a, 4) != -1 {
t.Fatal(BinarySearch(a, 4))
}
}

View File

@ -2,20 +2,20 @@
*
* 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);
}
@ -71,7 +71,7 @@
// index 位置插入元素e, 时间复杂度 O(m+n)
public void add(int index, T e) {
checkIndex(index);
// 如果当前元素个数等于数组容量则将数组扩容为原来的2倍
// 如果当前元素个数等于数组容量则将数组扩容为原来的2倍
if (size == data.length) {
resize(2 * data.length);
}
@ -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

@ -49,15 +49,31 @@ public class Sorts {
// 选择排序a表示数组n表示数组大小
public static void selectionSort(int[] a, int n) {
if (n <= 1) return;
<<<<<<< HEAD
for (int i = 0; i < n; ++i) {
// 查找最小值
int minIndex = i;
int minValue = a[i];
for (int j = i; j < n; ++j) {
if (a[j] < minValue) {
minValue = a[j];
=======
for (int i = 0; i < n - 1; ++i) {
// 查找最小值
int minIndex = i;
for (int j = i + 1; j < n; ++j) {
if (a[j] < a[minIndex]) {
>>>>>>> upstream/master
minIndex = j;
}
}
<<<<<<< HEAD
=======
if (minIndex == i)
continue;
>>>>>>> upstream/master
// 交换
int tmp = a[i];
a[i] = a[minIndex];

View File

@ -15,8 +15,8 @@ public class MergeSort {
// 递归终止条件
if (p >= r) return;
// 取p到r之间的中间位置q
int q = (p+r)/2;
// 取p到r之间的中间位置q,防止p+r的和超过int类型最大值
int q = p + (r - p)/2;
// 分治递归
mergeSortInternally(a, p, q);
mergeSortInternally(a, q+1, r);

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

@ -28,6 +28,8 @@ function expression($str)
array_push($operStack, $arr[$i]);
break;
case '*':
<<<<<<< HEAD
=======
$arrLen = count($operStack);
while ($operStack[$arrLen-1] === '/'){
compute($numStack, $operStack);
@ -36,6 +38,7 @@ function expression($str)
array_push($operStack, $arr[$i]);
break;
>>>>>>> upstream/master
case '/':
case '(':
array_push($operStack, $arr[$i]);
@ -78,9 +81,13 @@ function compute(&$numStack, &$operStack){
case '-':
array_push($numStack, array_pop($numStack) - $num);
break;
<<<<<<< HEAD
=======
case '(':
throw new \Exception("不匹配的(", 2);
break;
>>>>>>> upstream/master
}
}
expression('-1+2-(1+2*3)');

66
php/12_sort/mergeSort.php Normal file
View File

@ -0,0 +1,66 @@
<?php
$arr = [4, 5, 6, 1, 3, 2];
$length = count($arr);
$p = 0;
$r = $length - 1;
$result = $this->mergeSort($arr, $p, $r);
var_dump($result);
//递归调用,分解数组
function mergeSort(array $arr, $p, $r)
{
if ($p >= $r) {
return [$arr[$r]];
}
$q = (int)(($p + $r) / 2);
$left = $this->mergeSort($arr, $p, $q);
$right = $this->mergeSort($arr, $q + 1, $r);
return $this->merge($left, $right);
}
//合并
function merge(array $left, array $right)
{
$tmp = [];
$i = 0;
$j = 0;
$leftLength = count($left);
$rightLength = count($right);
do {
if ($left[$i] <= $right[$j]) {
$tmp[] = $left[$i++];
} else {
$tmp[] = $right[$j++];
}
} while ($i < $leftLength && $j < $rightLength);
$start = $i;
$end = $leftLength;
$copyArr = $left;
if ($j < $rightLength) {
$start = $j;
$end = $rightLength;
$copyArr = $right;
}
for (; $start < $end; $start++) {
$tmp[] = $copyArr[$start];
}
return $tmp;
}

View File

@ -17,7 +17,11 @@
* findMiddleNode 求链表的中间结点
#### 08_stack
<<<<<<< HEAD
* 链栈实现
=======
* 链栈实现
#### 09_stack
* 队列链表实现
>>>>>>> upstream/master

78
php/Stack/Compute.php Normal file
View File

@ -0,0 +1,78 @@
<?php
// 四则运算 +-*/()
function expression($str)
{
$str = str_replace(' ','',$str);
$arr = preg_split('/([\+\-\*\/\(\)])/', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$numStack = []; // 存放数字
$operStack = []; // 存放运算符
$operStack[] = NULL;
for ($i = 0; $i < count($arr); $i++){
if (ord($arr[$i]) >= 48 && ord($arr[$i] <= 57)){
array_push($numStack, $arr[$i]);
continue;
}
switch ($arr[$i]){
case '+':
case '-':
$arrLen = count($operStack);
while ($operStack[$arrLen-1] === '*' || $operStack[$arrLen-1] === '/' || $operStack[$arrLen-1] === '-'){
compute($numStack, $operStack);
$arrLen--;
}
array_push($operStack, $arr[$i]);
break;
case '*':
case '/':
case '(':
array_push($operStack, $arr[$i]);
break;
case ')':
$arrLen = count($operStack);
while ($operStack[$arrLen-1] !== '('){
compute($numStack, $operStack);
$arrLen--;
}
array_pop($operStack);
break;
default:
throw new \Exception("不支持的运算符", 1);
break;
}
}
$arrLen = count($operStack);
while ($operStack[$arrLen-1] !== NULL){
compute($numStack, $operStack);
$arrLen--;
}
echo array_pop($numStack);
}
//数字栈长度减一,运算符栈长度减一
function compute(&$numStack, &$operStack){
$num = array_pop($numStack);
switch (array_pop($operStack)) {
case '*':
array_push($numStack, array_pop($numStack) * $num);
break;
case '/':
array_push($numStack, array_pop($numStack) / $num);
break;
case '+':
array_push($numStack, array_pop($numStack) + $num);
break;
case '-':
array_push($numStack, array_pop($numStack) - $num);
break;
}
}
expression('-1+2-(1+2*3)');
echo PHP_EOL;
eval('echo -1+2-(1+2*3);');

View File

@ -7,8 +7,12 @@
"psr-4": {
"Algo_06\\": "06_linkedlist/",
"Algo_07\\": "07_linkedlist/",
<<<<<<< HEAD
"Algo_08\\": "08_stack/"
=======
"Algo_08\\": "08_stack/",
"Algo_09\\": "09_queue/"
>>>>>>> upstream/master
}
}
}

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,17 @@ if __name__ == "__main__":
for i in range(6):
a.insert_to_tail(i)
<<<<<<< HEAD
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)
>>>>>>> upstream/master

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,11 @@ class ArrayQueue:
return False
else:
for i in range(0, self._tail - self._head):
<<<<<<< HEAD
self._data[i] = self._items[i + self._head]
=======
self._items[i] = self._items[i + self._head]
>>>>>>> upstream/master
self._tail = self._tail - self._head
self._head = 0

View File

@ -11,8 +11,13 @@ from typing import List
def bubble_sort(a: List[int]):
if len(a) <= 1: return
<<<<<<< HEAD
made_swap = False
for i in range(len(a)):
=======
for i in range(len(a)):
made_swap = False
>>>>>>> upstream/master
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)

View File

@ -0,0 +1,22 @@
"""
Author: Wenru
"""
from typing import List
def bsearch(nums: List[int], target: int) -> int:
"""Binary search of a target in a sorted array
without duplicates. If such a target does not exist,
return -1, othewise, return its index.
"""
low, high = 0, len(nums) - 1
while low <= high:
mid = low + (high - low) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1

View File

@ -0,0 +1,77 @@
"""
Author: Wenru
"""
from typing import List
def bsearch_left(nums: List[int], target: int) -> int:
"""Binary search of the index of the first element
equal to a given target in the ascending sorted array.
If not found, return -1.
"""
low, high = 0, len(nums) - 1
while low <= high:
mid = low + (high - low) // 2
if nums[mid] < target:
low = mid + 1
else:
high = mid - 1
return low if nums[low] == target else -1
def bsearch_right(nums: List[int], target: int) -> int:
"""Binary search of the index of the last element
equal to a given target in the ascending sorted array.
If not found, return -1.
"""
low, high = 0, len(nums) - 1
while low <= high:
mid = low + (high - low) // 2
if nums[mid] <= target:
low = mid + 1
else:
high = mid - 1
return high if nums[high] == target else -1
def bsearch_left_not_less(nums: List[int], target: int) -> int:
"""Binary search of the index of the first element
not less than a given target in the ascending sorted array.
If not found, return -1.
"""
low, high = 0, len(nums) - 1
while low <= high:
mid = low + (high - low) // 2
if nums[mid] < target:
low = mid + 1
else:
high = mid - 1
return low if low < len(nums) else -1
def bsearch_right_not_greater(nums: List[int], target: int) -> int:
"""Binary search of the index of the last element
not greater than a given target in the ascending sorted array.
If not found, return -1.
"""
low, high = 0, len(nums) - 1
while low <= high:
mid = low + (high - low) // 2
if nums[mid] <= target:
low = mid + 1
else:
high = mid - 1
return high if high > 0 else -1
if __name__ == "__main__":
import bisect
a = [0, 1, 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 10, 10, 10]
b = [11, 12, 12, 13, 14, 14, 15, 15]
print(bisect.bisect_left(a, 10) == bsearch_left(a, 10))
print(bisect.bisect_right(a, 10))
print(bisect.bisect_right(a, 6)-1 == bsearch_right(a, 6))
print(bisect.bisect_right(b, 14)-1 == bsearch_right(b, 14))
print(bsearch_left_not_less(a, 11))
print(bsearch_right_not_greater(b, 12))
print(bsearch_right_not_greater(b, 10))
print(bsearch_right_not_greater(b, 17))

70
python/array.py Normal file
View File

@ -0,0 +1,70 @@
# 1.数组的插入、删除、按照下标随机访问操作;
# 2.数组中的数据类型是Int
#
# Author:Lee
class Array():
def __init__(self):
'''数组类初始化方法.'''
self.__data = [] # 数据存储List
def find(self, index):
'''数组的查找方法.
参数
index:将要查找的数据的下标
返回
如果查找成功则返回找到的数据
如果查找失败则返回False
'''
if index > len(self.__data) or index < 0:
return False
else:
return self.__data[index]
def delete(self, index):
'''数组的删除方法.
参数
index:将要删除的数据的下标
返回
如果删除成功则返回True
如果删除失败则返回False
'''
if index > len(self.__data) or index < 0:
return False
else:
self.__data.pop(index)
return True
def insert(self, index, value):
'''数组插入数据操作.
参数
index:将要插入的下标
value将要插入的数据
返回
如果插入成功则返回True
如果插入失败则返回False
'''
if index > len(self.__data) or index < 0:
return False
else:
self.__data.insert(index, value)
return True
def insertToTail(self, value):
'''直接在数组尾部插入数据.
参数
value:将要插入的数据
'''
self.__data.append(value)
def printAll(self):
'''打印当前数组所有数据'''
print(self.__data)

View File

@ -0,0 +1,68 @@
import scala.util.control.Breaks._
/**
* 冒泡排序插入排序选择排序
*
* Author: yangchuz
*/
object Sorts {
def main(args: Array[String]): Unit ={
// println(bubbleSort(Array(0, 6, 2, 3, 8, 5, 6, 7), 8).mkString(", "))
// println(insertSort(Array(0, 6, 2, 3, 8, 5, 6, 7), 8).mkString(", "))
println(selectionSort(Array(0, 6, 2, 3, 8, 5, 6, 7), 8).mkString(", "))
}
def bubbleSort(arr: Array[Int], n:Int): Array[Int] = {
val n = arr.length
breakable {
for(i <- (n-1) to (1, -1)){
var flag = false
for(j <- 0 until i){
if(arr(j) > arr(j+1)){
val tmp = arr(j)
arr(j) = arr(j+1)
arr(j+1) = tmp
flag = true
}
}
if(!flag){
break
}
}
}
arr
}
def insertSort(arr: Array[Int], n:Int): Array[Int] = {
for(i <- 1 until n){
val tmp = arr(i)
breakable{
for(j <- (i-1) to (0, -1)){
if(tmp < arr(j)){
arr(j+1) = arr(j)
}else{
arr(j+1) = tmp
break
}
}
}
}
arr
}
def selectionSort(arr: Array[Int], n:Int): Array[Int] = {
for(i <- 0 until n){
var min = i
for(j <- (i + 1) until n){
if(arr(j) < arr(min)){
min = j
}
}
val tmp = arr(i)
arr(i) = arr(min)
arr(min) = tmp
}
arr
}
}

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