From e121c388d3bce6e7ce29a0fc48b2586f50f85f29 Mon Sep 17 00:00:00 2001 From: Jiandan Date: Sat, 13 Oct 2018 14:50:22 +0800 Subject: [PATCH 001/141] [swift][09_queue][remove] Remove "typealias Element = T". [swift][09_queue][fix] Fix "size" in "QueueBasedOnLinkedList". --- swift/09_queue/ArrayQueue.swift | 8 ++------ swift/09_queue/CircularQueue.swift | 4 +--- swift/09_queue/QueueBasedOnLinkedList.swift | 20 +++++++------------- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/swift/09_queue/ArrayQueue.swift b/swift/09_queue/ArrayQueue.swift index 1dea014..d5c5bca 100644 --- a/swift/09_queue/ArrayQueue.swift +++ b/swift/09_queue/ArrayQueue.swift @@ -6,9 +6,7 @@ import Foundation /// 用数组实现的队列 -struct ArrayQueue: Queue { - typealias Element = T - +struct ArrayQueue: Queue { /// 数组 private var items: [Element] /// 数组最大长度 @@ -78,9 +76,7 @@ struct ArrayQueue: Queue { /// 使用2个数组实现无界队列,用到 Swift 中 Array 较多的方法 /// 来源:《iOS 面试之道》(故胤道长,唐巧) -struct ArrayQueue2: Queue { - typealias Element = T - +struct ArrayQueue2: Queue { /// 输入数组,主要负责入队 var inArray = [Element]() /// 输出数组,主要负责出队 diff --git a/swift/09_queue/CircularQueue.swift b/swift/09_queue/CircularQueue.swift index 6a58f98..c0c1e44 100644 --- a/swift/09_queue/CircularQueue.swift +++ b/swift/09_queue/CircularQueue.swift @@ -6,9 +6,7 @@ import Foundation /// 循环队列 -struct CircularQueue: Queue { - typealias Element = T - +struct CircularQueue: Queue { /// 数组 private var items: [Element] /// 数组最大长度 diff --git a/swift/09_queue/QueueBasedOnLinkedList.swift b/swift/09_queue/QueueBasedOnLinkedList.swift index be73795..be8b66c 100644 --- a/swift/09_queue/QueueBasedOnLinkedList.swift +++ b/swift/09_queue/QueueBasedOnLinkedList.swift @@ -5,18 +5,7 @@ import Foundation -class Node { - var value: T? - var next: Node? - - init(value: T) { - self.value = value - } -} - -struct QueueBasedOnLinkedList: Queue { - typealias Element = T - +struct QueueBasedOnLinkedList: Queue { /// 队首 var head: Node? /// 队尾 @@ -27,10 +16,15 @@ struct QueueBasedOnLinkedList: Queue { var isEmpty: Bool { return head == nil } var size: Int { - var count = 0 + if isEmpty { + return 0 + } + + var count = 1 // head 本身算一个 while head?.next != nil { count += 1 } + return count } From 6e177320c34b065476042d45108a33124fd124e4 Mon Sep 17 00:00:00 2001 From: Jiandan Date: Sat, 13 Oct 2018 15:37:24 +0800 Subject: [PATCH 002/141] [swift][08_statck][add] --- swift/08_stack/BrowserDemo.swift | 27 +++++++++++++++ swift/08_stack/Stack.swift | 21 ++++++++++++ swift/08_stack/StackBasedOnLinkedList.swift | 37 +++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 swift/08_stack/BrowserDemo.swift create mode 100644 swift/08_stack/Stack.swift create mode 100644 swift/08_stack/StackBasedOnLinkedList.swift diff --git a/swift/08_stack/BrowserDemo.swift b/swift/08_stack/BrowserDemo.swift new file mode 100644 index 0000000..3130305 --- /dev/null +++ b/swift/08_stack/BrowserDemo.swift @@ -0,0 +1,27 @@ +// +// Created by Jiandan on 2018/10/12. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +struct Page { + /// 存储前进 url + private var forwardArray = [String]() + /// 存储后退 url + private var backArray = [String]() + + var currentURL: String { return forwardArray.last! } + + init(url: String) { + forwardArray.append(url) + } + /// 前进 + mutating func goForward(url: String) { + forwardArray.append(url) + } + /// 后退 + mutating func goBack() { + backArray.append(forwardArray.popLast()!) + } +} diff --git a/swift/08_stack/Stack.swift b/swift/08_stack/Stack.swift new file mode 100644 index 0000000..65ddcc9 --- /dev/null +++ b/swift/08_stack/Stack.swift @@ -0,0 +1,21 @@ +// +// Created by Jiandan on 2018/10/12. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +protocol Stack { + /// 持有的数据类型 + associatedtype Element + /// 是否为空 + var isEmpty: Bool { get } + /// 队列大小 + var size: Int { get } + /// 返回队列头部元素 + var peek: Element? { get } + /// 入栈 + mutating func push(newElement: Element) -> Bool + /// 出栈 + mutating func pop() -> Element? +} diff --git a/swift/08_stack/StackBasedOnLinkedList.swift b/swift/08_stack/StackBasedOnLinkedList.swift new file mode 100644 index 0000000..0e11ce7 --- /dev/null +++ b/swift/08_stack/StackBasedOnLinkedList.swift @@ -0,0 +1,37 @@ +// +// Created by Jiandan on 2018/10/12. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +struct StackBasedOnLinkedList: Stack { + private var head = Node() // 哨兵结点,不存储内容 + + // MARK: Protocol: Stack + + var isEmpty: Bool { return head.next == nil } + + var size: Int { + var count = 0 + while head.next != nil { + count += 1 + } + return count + } + + var peek: Element? { return head.next?.value } + + func push(newElement: Element) -> Bool { + let node = Node(value: newElement) + node.next = head.next + head.next = node + return true + } + + func pop() -> Element? { + let node = head.next + head.next = node?.next + return node?.value + } +} From 9ff1092c7fd66b1c505cba5c36e87018207a17b9 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Fri, 19 Oct 2018 14:11:05 +0800 Subject: [PATCH 003/141] add by j00322883 for sort --- c-cpp/07_linkedlist/linklist_jinshaohui.c | 139 ++++++++++++++++++++++ c-cpp/12_sorts/quick_sort.c | 4 + 2 files changed, 143 insertions(+) create mode 100644 c-cpp/07_linkedlist/linklist_jinshaohui.c diff --git a/c-cpp/07_linkedlist/linklist_jinshaohui.c b/c-cpp/07_linkedlist/linklist_jinshaohui.c new file mode 100644 index 0000000..a05c6cd --- /dev/null +++ b/c-cpp/07_linkedlist/linklist_jinshaohui.c @@ -0,0 +1,139 @@ +/************************************************************************* + > File Name: lisklist.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-07 + > Desc: + ************************************************************************/ +#include + + +struct stlistNode +{ + int val; + struct listNode *next; +}listNode; + +/*反转链表*/ +listNode reverseList(listNode *head) +{ + listNode *prev = NULL; + listNode *next = NULL; + + while(head != NULL) + { + next = head->next; + head->next = prev; + prev = head; + head = next; + } + + return prev; +} + +/*判断链表是否有环*/ +int hasCycle(listNode *head) +{ + listNode * fast = head; + listNode * low = head; + + while(fast != NULL && fast->next != NULL) + { + low = low->next; + fast = fast->next->next; + if (low == fast) + { + return 1; + } + } + + return 0; +} +/*合并有序链表*/ +listNode *mergeTwoLists(listNode *l1,listNode *l2) +{ + listNode head = {0}; + listNode *pRes = &head; + + while(1) + { + if(l1 == NULL) + { + pRes->next = l2; + } + + if (l2 == NULL) + { + pRes->next = l1; + } + + if(l1->val < l2->val) + { + pRes->next = l1; + l1 = l1->next; + } + else + { + pRes->next = l2; + l2 = l2->next; + } + pRes = pRes->next; + } + + return head; +} +/* + *删除链表倒数第n个节点,并返回链表头节点 */ + +listNode * removeNthFromEnd(listNode*headi,int n) +{ + listNode *fast = head; + listNode *prev = NULL; + listNpde *next = head; + int k = n; + + /*快指针往后移动k-1*/ + while((k > 1) && (fast != NULL)) + { + fast = fast->next; + k--; + } + + /*说明链表数目不足n个*/ + if (fast == NULL) + { + return head; + } + + while (fast->next != NULL) + { + fast = fast->next; + prev = next; + next = next->next; + } + + if(prev == NULL) + { + head = head->next; + } + else + { + prev->next = prev->next->next; + } + + return head; +} +/*求链表的中间节点*/ +listNode *middleNode(listNode *head) +{ + listNode * fast = head; + listNode * low = head; + + while(fast != NULL && fast->next != NULL) + { + low = low->next; + fast = fast->next->next; + } + + return low; +} diff --git a/c-cpp/12_sorts/quick_sort.c b/c-cpp/12_sorts/quick_sort.c index 7bdc318..067d28f 100644 --- a/c-cpp/12_sorts/quick_sort.c +++ b/c-cpp/12_sorts/quick_sort.c @@ -27,7 +27,11 @@ int partition(int *arr, int p, int r) for (; j < r; j++) { if (arr[j] < arr[r]) { + if(i != j) + { swap(arr + i, arr + j); + + } i++; } } From f5895071c6c225b13f435d97800cd5c554c28b79 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Fri, 19 Oct 2018 14:12:51 +0800 Subject: [PATCH 004/141] add by j00322883 for sort --- c-cpp/10_recursive/one_two_step.c | 57 ++++++++++++++ c-cpp/11_sorts/sorts_jinshaohui.c | 124 ++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 c-cpp/10_recursive/one_two_step.c create mode 100644 c-cpp/11_sorts/sorts_jinshaohui.c diff --git a/c-cpp/10_recursive/one_two_step.c b/c-cpp/10_recursive/one_two_step.c new file mode 100644 index 0000000..02d503e --- /dev/null +++ b/c-cpp/10_recursive/one_two_step.c @@ -0,0 +1,57 @@ +/************************************************************************* + > File Name: one_two_step.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-19 + > Desc: + ************************************************************************/ +#include +#include +#include + +/*爬楼梯的问题,解决重复计算,采用数据保存方法*/ + +int helper(int n ,int *vlaue) +{ + + if(vlaue[n] != 0) + { + return vlaue[n]; + } + + vlaue[n] = helper(n - 1,vlaue) + helper(n - 2,vlaue); + + return vlaue[n]; +} + +int climbStaris(int n) +{ + int *vlaue = NULL; + int res = 0; + + vlaue = (int *)malloc(sizeof(int)*(n+1)); + if(vlaue == NULL) + { + return -1; + } + + memset(vlaue,0,sizeof(int)*(n + 1)); + vlaue[0] = 0; + vlaue[1] = 1; + vlaue[2] = 2; + res = helper(n,vlaue); + free(vlaue); + + return res; +} + +int main() +{ + + printf("\r\nnum%d ,%d",5,climbStaris(5)); + printf("\r\nnum%d ,%d",6,climbStaris(6)); + printf("\r\nnum%d ,%d",7,climbStaris(7)); + return 0; +} + + diff --git a/c-cpp/11_sorts/sorts_jinshaohui.c b/c-cpp/11_sorts/sorts_jinshaohui.c new file mode 100644 index 0000000..9e5675f --- /dev/null +++ b/c-cpp/11_sorts/sorts_jinshaohui.c @@ -0,0 +1,124 @@ +/************************************************************************* + > File Name: sorts_jinshaohui.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-19 + > Desc: + ************************************************************************/ +#include +#include +#include + +#define SWAP(a,b) \ +do{\ + (a) ^= (b);\ + (b) ^= (a);\ + (a) ^= (b);\ +}while(0) + +/*冒泡排序*/ +void bubble_sort(int a[],int size) +{ + int i = 0; + int j = 0; + int swap_flg = 0; + + if (size < 1) + { + return; + } + + for (i = size - 1; i > 0; i--)/*排序的趟数*/ + { + swap_flg = 0;/*每次设置交换标识为0*/ + for (j = 0; j < i; j++)/*本趟排序的遍历元素个数*/ + { + if (a[j] > a[j + 1]) + { + SWAP(a[j],a[j+1]); + swap_flg = 1; + } + } + /*本趟数,无数据交换的话,说明已经有序,直接退出*/ + if (swap_flg == 0) + { + break; + } + } + return; +} + +/*插入排序*/ +void insert_sort(int a[],int size) +{ + int i = 0; + int j = 0; + int key = 0; + + for (i = 1; i < size; i ++)/*需要插入的元素个数*/ + { + key = a[i];/*保存插入的元素数据*/ + j = i - 1; + /* i 之前的元素都是有序的,找到比key小的插入到他后面, + * 比key大的,需要往后挪一个位置*/ + while((j >= 0) && (a[j] > key)) + { + a[j + 1] = a[j]; + j--; + } + a[j + 1] = key; + } + + return; +} +/*选择排序*/ +void select_sort(int a[],int size) +{ + int i = 0; + int j = 0; + int min = 0; + + for (i = 0; i < size - 1; i++) + { + min = i; + for (j = i + 1; j < size; j++) + { + if (a[j] < a[min]) + { + min = j; + } + } + + if (min != i) + { + SWAP(a[i],a[min]); + } + } + return; +} + +void dump(int a[],int size) +{ + int i = 0; + + printf("\r\n"); + for (i = 0; i < size; i++ ) + { + printf("%d ",a[i]); + } + printf("\r\n"); + return; +} + +int main() +{ + int a[10] = {9,11,4,15,16,3,20,44,5,10}; + + //bubble_sort(a,sizeof(a)/sizeof(int)); + //insert_sort(a,sizeof(a)/sizeof(int)); + select_sort(a,sizeof(a)/sizeof(int)); + + dump(a,sizeof(a)/sizeof(int)); + + return 0; +} From 4fe228659052e3dc222199dcb008762048dd51a2 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Fri, 19 Oct 2018 22:03:36 +0800 Subject: [PATCH 005/141] add by jinshaohui for merge add quick sort, add find k big element value. --- c-cpp/12_sorts/my12_sorts/merge_sort.c | 108 ++++++++++++++++++ c-cpp/12_sorts/my12_sorts/quick_sort.c | 145 +++++++++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 c-cpp/12_sorts/my12_sorts/merge_sort.c create mode 100644 c-cpp/12_sorts/my12_sorts/quick_sort.c diff --git a/c-cpp/12_sorts/my12_sorts/merge_sort.c b/c-cpp/12_sorts/my12_sorts/merge_sort.c new file mode 100644 index 0000000..a762a0b --- /dev/null +++ b/c-cpp/12_sorts/my12_sorts/merge_sort.c @@ -0,0 +1,108 @@ +/************************************************************************* + > File Name: merge_sort.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-19 + > Desc: + ************************************************************************/ +#include +#include +#include +#include + + +/*两个有序数组合并*/ +void merge(int a[],int middle,int left,int right) +{ + int *tmp = NULL; + int i = 0; + int j = 0; + int k = 0; + + tmp = (int*)malloc((right - left + 1)*sizeof(int)); + assert(tmp != NULL); + + i = left; + j = middle + 1; + + while(1) + { + if((i > middle) || (j > right)) + { + break; + } + + if (a[i] > a[j]) + { + tmp[k++] = a[j++]; + } + else + { + tmp[k++] = a[i++]; + } + } + + if (i > middle) + { + while(j <= right) + { + tmp[k++] = a[j++]; + } + } + else + { + while(i <= middle) + { + tmp[k++] = a[i++]; + } + } + + memcpy((a + left),tmp,(right - left + 1)*sizeof(int)); + + free(tmp); + + return ; +} + +void merge_sort(int a[],int left,int right) +{ + int middle = 0; + + if(left >= right) + { + return; + } + + middle = (left + right)/2; + + merge_sort(a,left,middle); + merge_sort(a,middle + 1,right); + + merge(a,middle,left,right); + + return; +} + +void dump(int a[],int size) +{ + int i = 0; + + printf("\r\n"); + for (i = 0; i < size; i++ ) + { + printf("%d ",a[i]); + } + printf("\r\n"); + return; +} +int main() +{ + int a[10] = {30,20,10,15,4,8,40,80,20,9}; + + merge_sort(a,0,9); + + dump(a,10); + + return 0; +} + diff --git a/c-cpp/12_sorts/my12_sorts/quick_sort.c b/c-cpp/12_sorts/my12_sorts/quick_sort.c new file mode 100644 index 0000000..54ec480 --- /dev/null +++ b/c-cpp/12_sorts/my12_sorts/quick_sort.c @@ -0,0 +1,145 @@ +/************************************************************************* + > File Name: quick_sort.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-19 + > Desc: + ************************************************************************/ +#include +#include +#include +#include + +/* SWAP 使用必须主要,不能是同一个数据进行交换*/ +#define SWAP(a,b) \ +do{\ + (a) ^= (b);\ + (b) ^= (a);\ + (a) ^= (b);\ +}while(0) + +int partition2(int a[],int left,int right) +{ + int i = left; + int j = left; + + for(; j < right;j++) + { + if (a[j] < a[right]) + { + if(i != j) + { + SWAP(a[i],a[j]); + } + i++; + } + } + + if(i != right) + { + SWAP(a[i],a[right]); + } + + return i; +} + +int partition(int a[],int left,int right) +{ + int i = left; + int j = right; + int key = a[left]; + + while(i < j) + { + while((i < j)&& (a[j] >= key)) + { + j--; + } + if (i < j) + { + a[i] = a[j]; + } + while((i < j) && a[i] <= key) + { + i++; + } + + if (i= right) + { + return; + } + + q = partition2(a,left,right); + quick_sort(a,left,(q - 1)); + quick_sort(a,(q + 1),right); + return; +} + +void dump(int a[],int size) +{ + int i = 0; + + printf("\r\n"); + for (i = 0; i < size; i++ ) + { + printf("%d ",a[i]); + } + printf("\r\n"); + return; +} + +int helper(int a[],int left,int right,int k) +{ + int q = 0; + + q = partition(a,left,right); + + if (q > (k - 1)) + { + return helper(a,left,q-1,k); + } + else if (q < (k - 1)) + { + return helper(a,q+1,right,k); + } + + return a[q]; +} + +/*求无序数组中从小到大第K个元素的数值*/ +int findKthlagest(int a[],int size,int k) +{ + return helper(a,0,size-1,k); +} + + +int main() +{ + int a[10] = {30,20,10,15,4,8,40,80,20,9}; + int k; + + scanf("%d",&k); + + printf("\r\n从小到大排序,第%d个元素数值是%d",k,findKthlagest(a,10,k)); + + quick_sort(a,0,9); + + dump(a,10); + + return 0; +} + From a792e91a775fecc5d757980a8675901c9cd10145 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Sat, 20 Oct 2018 00:26:52 +0800 Subject: [PATCH 006/141] add by jinshaohui for merge sentry --- c-cpp/12_sorts/my12_sorts/merge_sort.c | 54 +++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/c-cpp/12_sorts/my12_sorts/merge_sort.c b/c-cpp/12_sorts/my12_sorts/merge_sort.c index a762a0b..5864351 100644 --- a/c-cpp/12_sorts/my12_sorts/merge_sort.c +++ b/c-cpp/12_sorts/my12_sorts/merge_sort.c @@ -10,6 +10,53 @@ #include #include +#define SORT_MAX (1000000) + +void dump(int a[],int size); +void merge_sentry(int a[],int middle,int left,int right) +{ + int *pleft = NULL; + int *pright = NULL; + int i = 0; + int j = 0; + int k = 0; + int left_size = middle - left + 1; + int right_size = right - middle; + + + pleft = (int *)malloc(sizeof(int)*(left_size + 1)); + assert(pleft != NULL); + pright = (int *)malloc(sizeof(int)*(right_size + 1)); + assert(pright != NULL); + + for(i = 0; i < left_size; i ++) + { + pleft[i] = a[left + i]; + } + pleft[left_size] = SORT_MAX; + for(i = 0; i < right_size; i ++) + { + pright[i] = a[middle + 1 + i]; + } + pright[right_size] = SORT_MAX; + + for (k = left,i = 0,j = 0; k <= right; k++) + { + if (pleft[i] <= pright[j]) + { + a[k] = pleft[i++]; + } + else + { + a[k] = pright[j++]; + } + } + + free(pleft); + free(pright); + + return; +} /*两个有序数组合并*/ void merge(int a[],int middle,int left,int right) @@ -78,7 +125,7 @@ void merge_sort(int a[],int left,int right) merge_sort(a,left,middle); merge_sort(a,middle + 1,right); - merge(a,middle,left,right); + merge_sentry(a,middle,left,right); return; } @@ -87,6 +134,11 @@ void dump(int a[],int size) { int i = 0; + if(size == 0) + { + return; + } + printf("\r\n"); for (i = 0; i < size; i++ ) { From b6856524e7cab42df7a9078d9040579416a9af00 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Sat, 20 Oct 2018 12:20:40 +0800 Subject: [PATCH 007/141] add by jinshaohui for count sort add radix sort --- c-cpp/13_sorts/sort.c | 168 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 c-cpp/13_sorts/sort.c diff --git a/c-cpp/13_sorts/sort.c b/c-cpp/13_sorts/sort.c new file mode 100644 index 0000000..41e13cc --- /dev/null +++ b/c-cpp/13_sorts/sort.c @@ -0,0 +1,168 @@ +/************************************************************************* + > File Name: sort.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-20 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include + +void dump(int a[],int size) +{ + int i = 0; + + printf("\r\n"); + + for(i = 0; i max) + { + max = a[i]; + } + } + + count = (int *)malloc(sizeof(int)*(max + 1)); + assert(count != NULL); + + memset(count,0,sizeof(int)*(max + 1)); + + /*计数*/ + for (i = 0; i < size;i++) + { + count[a[i]]++; + } + + /*依次累加*/ + for(i = 1 ;i <= max; i ++) + { + count[i] += count[i-1]; + } + + res = (int *)malloc(sizeof(int)*(size)); + assert(res != NULL); + /*核心代码,count[a[i] - 1]就是排序好的下标*/ + for (i = size-1;i >= 0; i--) + { + res[count[a[i]] -1] = a[i]; + count[a[i]]--; + } + + memcpy(a,res,size*(sizeof(int))); + + free(res); + free(count); + return; +} + + +int count_sort_test() +{ + int a [10]={1,5,6,8,10,9,3,1,2,1}; + printf("\r\n conunt sort test ...."); + count_sort(a,10); + dump(a,10); + + return 0; +} + +#define NUM_OF_POS(a,pval) ((a)/pval)%10 +void radix_sort(int a[],int size,int num_count) +{ + int count[10] = {0}; /*计数*/ + int *pres = NULL; + int i = 0; + int j = 0; + int pval = 10; + int index = 0; + int break_flg = 0; + + pres = (int *)malloc(sizeof(int)*size); + assert(pres != NULL); + + for (i = 0; i < num_count; i ++) + { + memset(count,0,sizeof(int)*10); + + /*求当前的基数*/ + pval = pow(10,i); + + /*计数*/ + for (j = 0; j < size; j++) + { + index = NUM_OF_POS(a[j],pval); + count[index]++; + } + + /*小的优化,可能位数最大的就1,其他的位数差很多*/ + if(count[0] == 9) + { + break_flg++; + } + + if(break_flg >=2) + { + printf("\r\n %i",i); + break; + } + + /*累加*/ + for(j = 1; j < 10; j ++) + { + count[j] += count[j-1]; + } + + /*排序必须从后往前,否则不是稳定排序*/ + for(j = size -1; j >= 0; j--) + { + index = NUM_OF_POS(a[j],pval); + pres[count[index] - 1] = a[j]; + count[index]--; + } + /*本轮排序好的,拷贝到a中*/ + memcpy(a,pres,sizeof(int)*size); + } + + return; +} + +void radix_sort_test() +{ + int a[10] = {123,12341,1232134,124,236,128,1112313129,98,9,8989}; + printf("\r\n radix sort test....."); + radix_sort(a,10,10); + dump(a,10); + return; +} + + +int main() +{ + count_sort_test(); + + radix_sort_test(); + return 0; +} From 1acc7044839dceb98712d871bd4099387a7f904f Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Sat, 20 Oct 2018 12:39:54 +0800 Subject: [PATCH 008/141] add by jinshaohui for bucket sort --- c-cpp/13_sorts/sort.c | 100 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) mode change 100644 => 100755 c-cpp/13_sorts/sort.c diff --git a/c-cpp/13_sorts/sort.c b/c-cpp/13_sorts/sort.c old mode 100644 new mode 100755 index 41e13cc..50cb463 --- a/c-cpp/13_sorts/sort.c +++ b/c-cpp/13_sorts/sort.c @@ -158,11 +158,111 @@ void radix_sort_test() return; } +struct barrel { + int node[10]; + int count;/* the num of node */ +}; +int partition(int a[],int left,int right) +{ + int i = left; + int j = right; + int key = a[left]; + + while(i < j) + { + while((i < j)&& (a[j] >= key)) + { + j--; + } + if (i < j) + { + a[i] = a[j]; + } + while((i < j) && a[i] <= key) + { + i++; + } + + if (i= right) + { + return; + } + + q = partition(a,left,right); + quick_sort(a,left,(q - 1)); + quick_sort(a,(q + 1),right); + return; +} + +void bucket_sort(int data[], int size) +{ + int max, min, num, pos; + int i, j, k; + struct barrel *pBarrel; + + max = min = data[0]; + for (i = 1; i < size; i++) { + if (data[i] > max) { + max = data[i]; + } else if (data[i] < min) { + min = data[i]; + } + } + num = (max - min + 1) / 10 + 1; + pBarrel = (struct barrel*)malloc(sizeof(struct barrel) * num); + memset(pBarrel, 0, sizeof(struct barrel) * num); + + /* put data[i] into barrel which it belong to */ + for (i = 0; i < size; i++) { + k = (data[i] - min + 1) / 10;/* calculate the index of data[i] in barrel */ + (pBarrel + k)->node[(pBarrel + k)->count] = data[i]; + (pBarrel + k)->count++; + } + + pos = 0; + for (i = 0; i < num; i++) { + if ((pBarrel + i)->count != 0) + { + quick_sort((pBarrel+i)->node, 0, ((pBarrel+i)->count)-1);/* sort node in every barrel */ + + for (j = 0; j < (pBarrel+i)->count; j++) { + data[pos++] = (pBarrel+i)->node[j]; + } + } + } + free(pBarrel); +} + +void bucket_sort_test() +{ + int a[] = {78, 17, 39, 26, 72, 94, 21, 12, 23, 91}; + int size = sizeof(a) / sizeof(int); + printf("\r\n bucket sort test ..."); + bucket_sort(a, size); + dump(a,size); + +} int main() { count_sort_test(); radix_sort_test(); + + bucket_sort_test(); return 0; } From 3b86c3dc28684b695359d71c9b4454e4f79d74a7 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Sun, 21 Oct 2018 04:09:45 +0800 Subject: [PATCH 009/141] add by jinshaohui for bsearch --- c-cpp/15_bsearch/bsearch_c/bsearch.c | 88 ++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 c-cpp/15_bsearch/bsearch_c/bsearch.c diff --git a/c-cpp/15_bsearch/bsearch_c/bsearch.c b/c-cpp/15_bsearch/bsearch_c/bsearch.c new file mode 100644 index 0000000..898c583 --- /dev/null +++ b/c-cpp/15_bsearch/bsearch_c/bsearch.c @@ -0,0 +1,88 @@ +/************************************************************************* + > File Name: bsearch.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-21 + > Desc: + ************************************************************************/ +#include +#include +#include + + +int mybsearch(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] == value) + { + return mid; + } + else if (a[mid] < value) + { + left = mid + 1; + } + else + { + right = mid - 1; + } + } + + return -1; +} + +int helper(int a[], int left,int right,int value) +{ + int mid = 0; + + if (left > right) + { + return -1; + } + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + if (a[mid] == value) + { + return mid; + } + else if (a[mid] < value) + { + return helper(a,mid + 1,right,value); + } + else + { + return helper(a,left,mid - 1,value); + } + return -1; +} +/*递归实现*/ +int mybsearch_2(int a[],int size,int value) +{ + + return helper(a,0,size-1,value); +} + +int main() +{ + int a[10] = {5,6,8,9,10,11,23,42,53,123}; + int data = 0; + int res = 0; + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch(a,10,data); + printf("data[%d] %s 在数据中,下标是%d",data,(res != -1)?"":"不",res); + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_2(a,10,data); + printf("data[%d] %s 在数据中,下标是%d",data,(res != -1)?"":"不",res); + return; +} From 0e4dd110905c65ada4f65d4e511d8865f1662467 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 24 Oct 2018 16:17:37 +0800 Subject: [PATCH 010/141] [notes][12_sorts] init. --- notes/12_sorts/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 notes/12_sorts/.gitkeep diff --git a/notes/12_sorts/.gitkeep b/notes/12_sorts/.gitkeep new file mode 100644 index 0000000..e69de29 From dea598a4665a18ef3602030652f7214db6e71505 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 24 Oct 2018 16:17:44 +0800 Subject: [PATCH 011/141] [notes][13_sorts] init. --- notes/13_sorts/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 notes/13_sorts/.gitkeep diff --git a/notes/13_sorts/.gitkeep b/notes/13_sorts/.gitkeep new file mode 100644 index 0000000..e69de29 From 3d99e6745ae6b41a015ccee6ce71d89125dbb585 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 24 Oct 2018 16:17:50 +0800 Subject: [PATCH 012/141] [notes][14_sorts] init. --- notes/14_sorts/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 notes/14_sorts/.gitkeep diff --git a/notes/14_sorts/.gitkeep b/notes/14_sorts/.gitkeep new file mode 100644 index 0000000..e69de29 From da137764b4d3b7c9499d85e446c872cbde12308d Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 24 Oct 2018 16:18:00 +0800 Subject: [PATCH 013/141] [notes][15_bsearch] init. --- notes/15_bsearch/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 notes/15_bsearch/.gitkeep diff --git a/notes/15_bsearch/.gitkeep b/notes/15_bsearch/.gitkeep new file mode 100644 index 0000000..e69de29 From e12b9ad927ffd0962b91caf1a14b7bfa8ee4c10d Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 24 Oct 2018 17:42:29 +0800 Subject: [PATCH 014/141] [notes][11_sorts] revise the title. --- notes/11_sorts/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes/11_sorts/readme.md b/notes/11_sorts/readme.md index 576668f..68f6edc 100644 --- a/notes/11_sorts/readme.md +++ b/notes/11_sorts/readme.md @@ -1,4 +1,4 @@ -# 排序(上) +# 排序(平方时间复杂度排序算法) | 排序算法 | 时间复杂度 | 是否基于比较 | |---------|----|----| From 1516e7dee6bb15d424f8effe8e8f1b643541a53f Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 24 Oct 2018 18:43:15 +0800 Subject: [PATCH 015/141] [notes][12_sorts] merge sort, done. --- notes/12_sorts/readme.md | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 notes/12_sorts/readme.md diff --git a/notes/12_sorts/readme.md b/notes/12_sorts/readme.md new file mode 100644 index 0000000..3b3d8f3 --- /dev/null +++ b/notes/12_sorts/readme.md @@ -0,0 +1,80 @@ +# 排序(线性对数时间复杂度排序算法) + +开篇问题:如何在 $O(n)$ 时间复杂度内寻找一个无序数组中第 K 大的元素? + +## 归并排序 + +* 归并排序使用了「分治」思想(Divide and Conquer) + * 分:把数组分成前后两部分,分别排序 + * 合:将有序的两部分合并 + +![归并排序分解图](https://static001.geekbang.org/resource/image/db/2b/db7f892d3355ef74da9cd64aa926dc2b.jpg) + +* 分治与递归 + * 分治:解决问题的处理办法 + * 递归:实现算法的手段 + * ——分治算法经常用递归来实现 +* 递归实现: + * 终止条件:区间 `[first, last)` 内不足 2 个元素 + * 递归公式:`merge_sort(first, last) = merge(merge_sort(first, mid), merge_sort(mid, last))`,其中 `mid = first + (last - first) / 2` + +C++ 实现: + +```cpp +template ::value_type, + typename BinaryPred = std::less> +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 tmp; + tmp.reserve(len); + detail::merge(first, cut, cut, last, std::back_inserter(tmp), comp); + std::copy(tmp.begin(), tmp.end(), first); +} +``` + +这里涉及到一个 `merge` 的过程,它的实现大致是: + +```cpp +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 +``` + +![`merge` 的过程](https://static001.geekbang.org/resource/image/95/2f/95897ade4f7ad5d10af057b1d144a22f.jpg) + +### 算法分析 + +* 稳定性 + * 由于 `comp` 是严格偏序,所以 `!comp(*first2, *first1)` 时,取用 `first1` 的元素放入 `d_first` 保证了算法稳定性 +* 时间复杂度 + * 定义 $T(n)$ 表示问题规模为 $n$ 时算法的耗时, + * 有递推公式:$T(n) = 2T(1/2) + n$ + * 展开得 $T(n) = 2^{k}T(1) + k * n$ + * 考虑 $k$ 是递归深度,它的值是 $\log_2 n$,因此 $T(n) = n + n\log_2 n$ + * 因此,归并排序的时间复杂度为 $\Theta(n\log n)$ +* 空间复杂度 + * 一般来说,空间复杂度是 $\Theta(n)$ From 72dc27730da131f8cef01212dd39c4e25a273ef3 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 11:14:50 +0800 Subject: [PATCH 016/141] [notes][12_sorts] quick_sort, done. --- notes/12_sorts/readme.md | 91 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/notes/12_sorts/readme.md b/notes/12_sorts/readme.md index 3b3d8f3..de58cc5 100644 --- a/notes/12_sorts/readme.md +++ b/notes/12_sorts/readme.md @@ -72,9 +72,98 @@ OutputIt merge(InputIt1 first1, InputIt1 last1, * 由于 `comp` 是严格偏序,所以 `!comp(*first2, *first1)` 时,取用 `first1` 的元素放入 `d_first` 保证了算法稳定性 * 时间复杂度 * 定义 $T(n)$ 表示问题规模为 $n$ 时算法的耗时, - * 有递推公式:$T(n) = 2T(1/2) + n$ + * 有递推公式:$T(n) = 2T(n/2) + n$ * 展开得 $T(n) = 2^{k}T(1) + k * n$ * 考虑 $k$ 是递归深度,它的值是 $\log_2 n$,因此 $T(n) = n + n\log_2 n$ * 因此,归并排序的时间复杂度为 $\Theta(n\log n)$ * 空间复杂度 * 一般来说,空间复杂度是 $\Theta(n)$ + +## 快速排序(quick sort,快排) + +原理: + +* 在待排序区间 `[first, last)` 中选取一个元素,称为主元(pivot,枢轴) +* 对待排序区间进行划分,使得 `[first, cut)` 中的元素满足 `comp(element, pivot)` 而 `[cut, last)` 中的元素不满足 `comp(element, pivot)` +* 对划分的两个区间,继续划分,直到区间 `[first, last)` 内不足 2 个元素 + +![快排分区示例](https://static001.geekbang.org/resource/image/4d/81/4d892c3a2e08a17f16097d07ea088a81.jpg) + +显然,这又是一个递归: + +* 终止条件:区间 `[first, last)` 内不足 2 个元素 +* 递归公式:`quick_sort(first, last) = quick_sort(first, cut) + quick_sort(cut, last)` + +```cpp +template ::value_type> +void quick_sort(IterT first, IterT last) { + if (std::distance(first, last) > 1) { + IterT prev_last = std::prev(last); + IterT cut = std::partition(first, prev_last, [prev_last](T v) { return v < *prev_last; }); + std::iter_swap(cut, prev_last); + quick_sort(first, cut); + quick_sort(cut, last); + } +} +``` + +> 一点优化(Liam Huang):通过将 `if` 改为 `while` 同时修改 `last` 迭代器的值,可以节省一半递归调用的开销。 + +```cpp +template ::value_type> +void quick_sort(IterT first, IterT last) { + while (std::distance(first, last) > 1) { + IterT prev_last = std::prev(last); + IterT cut = std::partition(first, prev_last, [prev_last](T v) { return v < *prev_last; }); + std::iter_swap(cut, prev_last); + quick_sort(cut, last); + last = cut; + } +} +``` + +如果不要求空间复杂度,分区函数实现起来很容易。 + +![非原地分区](https://static001.geekbang.org/resource/image/66/dc/6643bc3cef766f5b3e4526c332c60adc.jpg) + +若要求原地分区,则不那么容易了。下面的实现实现了原地分区函数,并且能将所有相等的主元排在一起。 + +```cpp +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}; +} +``` + +### 算法分析 + +* 稳定性 + * 由于 `inplace_partition` 使用了大量 `std::iter_swap` 操作,所以不是稳定排序 +* 时间复杂度 + * 定义 $T(n)$ 表示问题规模为 $n$ 时算法的耗时, + * 有递推公式:$T(n) = 2T(n/2) + n$(假定每次分割都是均衡分割) + * 展开得 $T(n) = 2^{k}T(1) + k * n$ + * 考虑 $k$ 是递归深度,它的值是 $\log_2 n$,因此 $T(n) = n + n\log_2 n$ + * 因此,快速排序的时间复杂度为 $\Theta(n\log n)$ +* 空间复杂度 + * 一般来说,空间复杂度是 $\Theta(1)$,因此是原地排序算法 From 04e3d8efef1451f02b7203800d8829810ea0b650 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 11:23:58 +0800 Subject: [PATCH 017/141] [notes][12_sorts] opening question, done. --- notes/12_sorts/readme.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/notes/12_sorts/readme.md b/notes/12_sorts/readme.md index de58cc5..57066e4 100644 --- a/notes/12_sorts/readme.md +++ b/notes/12_sorts/readme.md @@ -167,3 +167,10 @@ std::pair inplace_partition(BidirIt first, * 因此,快速排序的时间复杂度为 $\Theta(n\log n)$ * 空间复杂度 * 一般来说,空间复杂度是 $\Theta(1)$,因此是原地排序算法 + +## 开篇问题 + +* 分区,看前半段元素数量 + * 前半段元素数量 < K,对后半段进行分区 + * 前半段元素数量 > K,对前半段进行分区 + * 前半段元素数量 = K,前半段末位元素即是所求 From 1197723214377758def05186547299398e2650f4 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 11:34:44 +0800 Subject: [PATCH 018/141] [notes][13_sorts] bucket sort, done. --- notes/13_sorts/readme.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 notes/13_sorts/readme.md diff --git a/notes/13_sorts/readme.md b/notes/13_sorts/readme.md new file mode 100644 index 0000000..182beab --- /dev/null +++ b/notes/13_sorts/readme.md @@ -0,0 +1,26 @@ +# 线性排序 + +## 开篇问题 + +如何按年龄给 100 万用户排序? + +## 桶排序(Bucket Sort) + +算法思想: + +* 按待排序数据的 key 分有序桶 +* 桶内排序 +* 有序桶依次输出 + +![桶排序示例](https://static001.geekbang.org/resource/image/98/ae/987564607b864255f81686829503abae.jpg) + +### 算法分析 + +* 时间复杂度 $O(n)$ + * $n$ 个元素,分 $m$ 个有序桶,每个桶里平均 $k = n / m$ 个元素 + * 桶内快排,复杂度 $O(k \log k)$,$m$ 个桶一共 $O(n \log k)$ + * 当 $m$ 接近 $n$,例如当 $k = 4$ 时,这个复杂度近似 $O(n)$ +* 使用条件 + * 数据易于分如有序桶 + * 数据在各个有序桶之间分布均匀 + * 适合外部排序——数据不全部载入磁盘 From ce87aa2973040ee2e498d134b98e562c84536cb6 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 11:36:36 +0800 Subject: [PATCH 019/141] [cpp][13_sorts] init. --- c-cpp/13_sorts/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c-cpp/13_sorts/.gitkeep diff --git a/c-cpp/13_sorts/.gitkeep b/c-cpp/13_sorts/.gitkeep new file mode 100644 index 0000000..e69de29 From 558bd0ddb1c622e2394b601191c191fede099d6f Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 12:31:31 +0800 Subject: [PATCH 020/141] [cpp][13_sorts] bucket_sort, done. --- c-cpp/13_sorts/bucket_sort.hpp | 43 ++++++++++++++++++++++++++++++ c-cpp/13_sorts/bucket_sort_test.cc | 33 +++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 c-cpp/13_sorts/bucket_sort.hpp create mode 100644 c-cpp/13_sorts/bucket_sort_test.cc diff --git a/c-cpp/13_sorts/bucket_sort.hpp b/c-cpp/13_sorts/bucket_sort.hpp new file mode 100644 index 0000000..41133ff --- /dev/null +++ b/c-cpp/13_sorts/bucket_sort.hpp @@ -0,0 +1,43 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/26. + */ + +#ifndef SORTS_BUCKET_SORT_HPP_ +#define SORTS_BUCKET_SORT_HPP_ + +#include +#include +#include +#include + +template ::value_type, + typename Compare = std::less> +void bucket_sort(IterT first, IterT last, Compare comp = Compare()) { + const T min = *std::min_element(first, last), max = *std::max_element(first, last); + const T range = max + 1 - min; + const size_t bucket_num = (range - 1) / BucketSize + 1; + + std::vector> buckets(bucket_num); + for (auto b : buckets) { + b.reserve(2 * BucketSize); + } + + for (IterT i = first; i != last; ++i) { + size_t idx = (*i - min) / BucketSize; + buckets[idx].emplace_back(*i); + } + + IterT dest = first; + for (auto b : buckets) { + std::sort(b.begin(), b.end(), comp); + std::copy(b.begin(), b.end(), dest); + dest += b.size(); + } + + return; +} + +#endif // SORTS_BUCKET_SORT_HPP_ + diff --git a/c-cpp/13_sorts/bucket_sort_test.cc b/c-cpp/13_sorts/bucket_sort_test.cc new file mode 100644 index 0000000..3199e8a --- /dev/null +++ b/c-cpp/13_sorts/bucket_sort_test.cc @@ -0,0 +1,33 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/26. + */ + +#include +#include +#include + +#include "bucket_sort.hpp" + +template > +void test_bucket_sort(Container cont, Compare comp = Compare()) { + bucket_sort(cont.begin(), cont.end(), comp); + std::transform(cont.begin(), cont.end(), std::ostream_iterator(std::cout, " "), + [](T i){ return i; }); + std::cout << std::endl; +} + +int main() { + std::vector test{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9}; + + test_bucket_sort<2>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9 + test_bucket_sort<3>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9 + test_bucket_sort<4>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9 + test_bucket_sort<5>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9 + test_bucket_sort<6>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9 + + return 0; +} + From a67fb10a7bc96561d41effe2355578de3e74b041 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Fri, 26 Oct 2018 15:26:40 +0800 Subject: [PATCH 021/141] binary search in c --- c-cpp/15_bsearch/binary_search.c | 96 ++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 c-cpp/15_bsearch/binary_search.c diff --git a/c-cpp/15_bsearch/binary_search.c b/c-cpp/15_bsearch/binary_search.c new file mode 100644 index 0000000..1125fb5 --- /dev/null +++ b/c-cpp/15_bsearch/binary_search.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +typedef int(*bs)(int *arr, int size, int val); + +int binary_search_r(int *arr, int size, int val) +{ + int mid = size / 2; + int idx; + + if (arr[mid] == val) + return mid; + + // mid == 0 means size == 1 + // so the only element in array doesn't equal to val + if (!mid) + return -1; + + if (arr[mid] < val) { + idx = binary_search_r(arr + mid + 1, size - mid - 1, val); + if (idx != -1) + idx += mid + 1; + } else { + idx = binary_search_r(arr, mid, val); + } + + return idx; +} + +int binary_search_i(int *arr, int size, int val) +{ + int low = 0, high = size - 1, mid; + + while (low <= high) { + mid = (low + high) / 2; + if (arr[mid] == val) + return mid; + + if (arr[mid] < val) + low = mid + 1; + else + high = mid - 1; + } + + return -1; +} + +void iteratioin_test(bs binary_search) +{ + int arr[10] = {1, 4, 5, 9, 12, 19, 21, 28, 31, 36}; + int idx; + + idx = binary_search(arr, 10, 12); + if (idx != -1) + printf("find 12 at %d\n", idx); + else + printf("12 not in arr \n"); + + idx = binary_search(arr, 10, 13); + if (idx != -1) + printf("find 13 at %d\n", idx); + else + printf("13 not in arr \n"); + + idx = binary_search(arr, 10, 1); + if (idx != -1) + printf("find 1 at %d\n", idx); + else + printf("1 not in arr \n"); + + idx = binary_search(arr, 10, 36); + if (idx != -1) + printf("find 36 at %d\n", idx); + else + printf("36 not in arr \n"); + + idx = binary_search(arr, 10, 31); + if (idx != -1) + printf("find 31 at %d\n", idx); + else + printf("31 not in arr \n"); + +} + +int main() +{ + printf("=== Test iteration version:\n"); + iteratioin_test(binary_search_i); + + printf("=== Test recursive version:\n"); + iteratioin_test(binary_search_r); + + return 0; +} From ce4ec5117ab1eb4ac04732e7ef04f3e92b4ebbed Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 15:48:44 +0800 Subject: [PATCH 022/141] [cpp][13_sorts] counting_sort, done. --- c-cpp/13_sorts/counting_sort.hpp | 40 ++++++++++++++++++++++++++++ c-cpp/13_sorts/counting_sort_test.cc | 36 +++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 c-cpp/13_sorts/counting_sort.hpp create mode 100644 c-cpp/13_sorts/counting_sort_test.cc diff --git a/c-cpp/13_sorts/counting_sort.hpp b/c-cpp/13_sorts/counting_sort.hpp new file mode 100644 index 0000000..5e7f782 --- /dev/null +++ b/c-cpp/13_sorts/counting_sort.hpp @@ -0,0 +1,40 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/26. + */ + +#ifndef SORTS_COUNTING_SORT_HPP_ +#define SORTS_COUNTING_SORT_HPP_ + +#include +#include +#include +#include + +template ::value_type> +void counting_sort(IterT first, IterT last) { + const auto len = std::distance(first, last); + if (len < 2) { return; } + + const T max = *std::max_element(first, last); + if (max == 0) { return; } + + std::vector counter(max + 1); + for (IterT i = first; i != last; ++i) { + ++counter[*i]; + } + for (size_t i = 1; i != max + 1; ++i) { + const size_t j = max - i; + counter[j] += counter[j + 1]; // Liam Huang: count of numbers that is not less than j. + } + + std::vector temp(len); + for (IterT i = first; i != last; ++i) { + temp[len - counter[*i]] = *i; + --counter[*i]; // Liam Huang: stable for relative position. + } + std::copy(temp.begin(), temp.end(), first); +} + +#endif // SORTS_COUNTING_SORT_HPP_ + diff --git a/c-cpp/13_sorts/counting_sort_test.cc b/c-cpp/13_sorts/counting_sort_test.cc new file mode 100644 index 0000000..4e0814a --- /dev/null +++ b/c-cpp/13_sorts/counting_sort_test.cc @@ -0,0 +1,36 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/26. + */ + +#include +#include +#include + +#include "counting_sort.hpp" + +template +void test_counting_sort(Container cont) { + counting_sort(cont.begin(), cont.end()); + std::transform(cont.begin(), cont.end(), std::ostream_iterator(std::cout, " "), + [](T i){ return i; }); + std::cout << std::endl; +} + +int main() { + // Liam Huang: pi for test + const std::vector test1{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3}; + const std::vector test2{2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9}; + const std::vector test3{5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9}; + const std::vector test4{3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4}; + const std::vector test5{5, 9, 2, 3, 0, 7, 8, 1, 6, 4, 0, 6, 2, 8, 6}; + + test_counting_sort(test1); // 1 1 2 3 3 3 4 5 5 5 6 7 8 9 9 9 + test_counting_sort(test2); // 2 2 2 3 3 3 3 4 4 6 6 7 8 8 9 + test_counting_sort(test3); // 0 1 1 2 3 4 5 6 7 8 8 9 9 9 9 + test_counting_sort(test4); // 0 0 1 2 3 4 4 4 5 5 7 7 8 9 9 + test_counting_sort(test5); // 0 0 1 2 2 3 4 5 6 6 6 7 8 8 9 + + return 0; +} + From 528fbe131b97116a65397c30ef71f836b4e781b2 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:03:43 +0800 Subject: [PATCH 023/141] [notes][13_sorts] counting sort, done. --- notes/13_sorts/readme.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/notes/13_sorts/readme.md b/notes/13_sorts/readme.md index 182beab..c632ec9 100644 --- a/notes/13_sorts/readme.md +++ b/notes/13_sorts/readme.md @@ -24,3 +24,33 @@ * 数据易于分如有序桶 * 数据在各个有序桶之间分布均匀 * 适合外部排序——数据不全部载入磁盘 + +## 计数排序(Counting Sort) + +计数排序可以视作是桶排序的一个特殊情况: + +* 数据的取值范围很小 +* 每个分桶内的元素 key 值都一样 + +此时,由于分桶内的元素 key 值都一样,所以桶内的排序操作可以省略,以及桶的编号本身就能记录桶内元素的值。因此,算法只需遍历一遍所有的数据,统计每个取值上有多少元素即可。这个过程时间复杂度是 $O(n)$。 + +* 假设待排序的数组 `A = {2, 5, 3, 0, 2, 3, 0, 3}`,我们有计数数组 `C = {2, 0, 2, 3, 0, 1}` + +接下来,我们要对 `C` 进行计数操作,具体来说,对从下标为 1 的元素开始累加 `C[i] += C[i - 1]`。 + +* 计数累加 `C = {2, 2, 4, 7, 7, 8}` + +此时,`C` 中的元素表示「小于等于下标的元素的个数」。接下来,我们从尾至头扫描待排序数组 `A`,将其中元素依次拷贝到输出数组 `R` 的相应位置。我们注意到,`A[7] = 3` 而 `C[3] == 4` 。这意味着,待排序的数组中,包括 3 本身在内,不超过 3 的元素共有 4 个。因此,我们可以将这个 3 放置在 `R[C[3] - 1]` 的位置,而后将 `C[3]` 的计数减一——这是由于待排序数组中未处理的部分,不超过 3 的元素现在只剩下 3 个了。如此遍历整个待排序数组 `A`,即可得到排序后的结果 `R`。 + +![计数排序示例](https://static001.geekbang.org/resource/image/1d/84/1d730cb17249f8e92ef5cab53ae65784.jpg) + +### 算法分析 + +* 时间复杂度 + * $n$ 个元素,最大值是 $k$,分 $k$ 个「桶」;时间复杂度 $O(n)$ + * 桶内计数累加;时间复杂度 $O(k)$ + * 摆放元素;时间复杂度 $O(n)$ + * 当 $k < n$ 时,总体时间复杂度是 $O(n)$ +* 使用条件 + * $k < n$ + * 待排序数据的 key 是非负整数 From b4d060e8c5405c98428d18c06639df7518d9ae97 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:10:55 +0800 Subject: [PATCH 024/141] [notes][13_sorts] radix sort, done. --- notes/13_sorts/readme.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/notes/13_sorts/readme.md b/notes/13_sorts/readme.md index c632ec9..9b97e12 100644 --- a/notes/13_sorts/readme.md +++ b/notes/13_sorts/readme.md @@ -54,3 +54,20 @@ * 使用条件 * $k < n$ * 待排序数据的 key 是非负整数 + +## 基数排序(Radix Sort) + +基数排序适用于等长数据的排序。对于不等长数据,可以在较短的数据后面做 padding,使得数据等长。 + +* 先就 least significant digit 进行稳定排序——通常可以用桶排序或者计数排序;时间复杂度 $O(n)$ +* 而后依次向 greatest significant digit 移动,进行稳定排序 + +![基数排序示例](https://static001.geekbang.org/resource/image/df/0c/df0cdbb73bd19a2d69a52c54d8b9fc0c.jpg) + +### 算法分析 + +* 时间复杂度 + * 对每一位的排序时间复杂度是 $O(n)$ + * 总共 $k$ 位,因此总的时间复杂度是 $O(kn)$;考虑到 $k$ 是常数,因此总的时间复杂度是 $O(n)$ +* 使用条件 + * 等长数据 From 094c5e78e5596b5e793aaa4d221f5c43cbc1a24f Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:15:18 +0800 Subject: [PATCH 025/141] [notes][13_sorts] solution to the opening question, done. --- notes/13_sorts/readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/notes/13_sorts/readme.md b/notes/13_sorts/readme.md index 9b97e12..aa38c89 100644 --- a/notes/13_sorts/readme.md +++ b/notes/13_sorts/readme.md @@ -71,3 +71,7 @@ * 总共 $k$ 位,因此总的时间复杂度是 $O(kn)$;考虑到 $k$ 是常数,因此总的时间复杂度是 $O(n)$ * 使用条件 * 等长数据 + +## 解答开篇 + +桶排序。 From d01c14fb20762e05275bd5b047c27720dcfc5d55 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:18:44 +0800 Subject: [PATCH 026/141] [notes][14_sorts] done. --- notes/14_sorts/readme.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 notes/14_sorts/readme.md diff --git a/notes/14_sorts/readme.md b/notes/14_sorts/readme.md new file mode 100644 index 0000000..49e8d94 --- /dev/null +++ b/notes/14_sorts/readme.md @@ -0,0 +1,10 @@ +# 排序优化 + +## 如何取舍排序算法? + +* 排序规模小 —— $O(n^2)$ 的算法(通常是插排) +* 排序规模大 —— $O(n\log n)$ 的算法(通常不用归并排序) + +## 如何优化快速排序? + +参考:[谈谈内省式排序算法](https://liam.page/2018/08/29/introspective-sort/) From e7188a3134e0cd16892ea3e0a58d089779e5d035 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:24:57 +0800 Subject: [PATCH 027/141] [notes][15_bsearch] done. --- notes/15_bsearch/readme.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 notes/15_bsearch/readme.md diff --git a/notes/15_bsearch/readme.md b/notes/15_bsearch/readme.md new file mode 100644 index 0000000..4947b03 --- /dev/null +++ b/notes/15_bsearch/readme.md @@ -0,0 +1,23 @@ +# 二分查找(上) + +## 算法描述 + +二分查找(Binary Search)也叫折半查找,是针对有序数据集合的查找算法。其描述十分简单: + +* 折半取中,判断元素与目标元素的大小关系 + * 小于——往前继续折半 + * 大于——往后继续折半 + * 等于——返回 + +关于它的复杂度分析,参见[谈谈基于比较的排序算法的复杂度下界](https://liam.page/2018/08/28/lower-bound-of-comparation-based-sort-algorithm/)中的相关信息。它的复杂度是 $O(\log n)$。 + +## $O(\log n)$ 的惊人之处 + +在 42 亿个数据中用二分查找一个数据,最多需要比较 32 次。 + +## 适用场景 + +* 依赖顺序表结构 +* 数据本身必须有序 +* 数据量相对比较元素的开销要足够大——不然遍历即可 +* 数据量相对内存空间不能太大——不然顺序表装不下 From c15b4b851558961bc2e6c6a2f22da8632771f4c9 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:25:36 +0800 Subject: [PATCH 028/141] [notes][16_bsearch] init. --- notes/16_bsearch/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 notes/16_bsearch/.gitkeep diff --git a/notes/16_bsearch/.gitkeep b/notes/16_bsearch/.gitkeep new file mode 100644 index 0000000..e69de29 From 561561246eaa55b00a38462e190f71d424b2bd63 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:28:03 +0800 Subject: [PATCH 029/141] [cpp][16_bsearch] init. --- c-cpp/16_bsearch/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c-cpp/16_bsearch/.gitkeep diff --git a/c-cpp/16_bsearch/.gitkeep b/c-cpp/16_bsearch/.gitkeep new file mode 100644 index 0000000..e69de29 From 6ced9eb2b809e3bf49cdd2ffd1d452f6f29bd0b5 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:32:43 +0800 Subject: [PATCH 030/141] [cpp][15_bsearch] remove varients of bsearch in 15_bsearch. --- c-cpp/15_bsearch/bsearch.hpp | 37 ++++---------------------------- c-cpp/15_bsearch/bsearch_test.cc | 14 ++---------- 2 files changed, 6 insertions(+), 45 deletions(-) diff --git a/c-cpp/15_bsearch/bsearch.hpp b/c-cpp/15_bsearch/bsearch.hpp index e05f063..d55a086 100644 --- a/c-cpp/15_bsearch/bsearch.hpp +++ b/c-cpp/15_bsearch/bsearch.hpp @@ -8,19 +8,16 @@ #include #include -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 ::value_type, - typename Compare> + typename Compare = std::less> IterT bsearch(IterT first, IterT last, ValueT target, - Compare comp, - BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) { + Compare comp = Compare()) { IterT result = last; while (std::distance(first, last) > 0) { IterT mid = first + std::distance(first, last) / 2; @@ -29,38 +26,12 @@ IterT bsearch(IterT first, } 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; - } + result = mid; + break; } } return result; } -template ::value_type, - typename Compare = std::less> -IterT bsearch(IterT first, - IterT last, - ValueT target, - BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) { - return bsearch(first, last, target, Compare(), policy); -} - #endif // BSEARCH_BSEARCH_HPP_ diff --git a/c-cpp/15_bsearch/bsearch_test.cc b/c-cpp/15_bsearch/bsearch_test.cc index b862f63..e552991 100644 --- a/c-cpp/15_bsearch/bsearch_test.cc +++ b/c-cpp/15_bsearch/bsearch_test.cc @@ -8,10 +8,8 @@ #include "bsearch.hpp" template -void test_bsearch(const VecT& test, - T target, - BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) { - auto it = bsearch(test.begin(), test.end(), target, policy); +void test_bsearch(const VecT& test, T target) { + auto it = bsearch(test.begin(), test.end(), target); std::cout << std::distance(test.begin(), it) << std::endl; } @@ -21,17 +19,9 @@ int main() { 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; } From 7346e456e6851f34e8db4818a7c3c98381b9316c Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:52:26 +0800 Subject: [PATCH 031/141] [cpp][16_bsearch] all varients done. --- c-cpp/16_bsearch/bsearch_varients.hpp | 90 +++++++++++++++++++++++ c-cpp/16_bsearch/bsearch_varients_test.cc | 41 +++++++++++ 2 files changed, 131 insertions(+) create mode 100644 c-cpp/16_bsearch/bsearch_varients.hpp create mode 100644 c-cpp/16_bsearch/bsearch_varients_test.cc diff --git a/c-cpp/16_bsearch/bsearch_varients.hpp b/c-cpp/16_bsearch/bsearch_varients.hpp new file mode 100644 index 0000000..35cf091 --- /dev/null +++ b/c-cpp/16_bsearch/bsearch_varients.hpp @@ -0,0 +1,90 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/24. + */ + +#ifndef BSEARCH_BSEARCH_VARIENTS_HPP_ +#define BSEARCH_BSEARCH_VARIENTS_HPP_ + +#include +#include + +enum class BsearchPolicy { UNSPECIFIED, FIRST, LAST, FIRST_NOT_LESS, LAST_NOT_LARGER }; + +// 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 ::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 (policy == BsearchPolicy::FIRST_NOT_LESS) { + if (!comp(*mid, target)) { + if (mid == first or comp(*(mid - 1), target)) { + result = mid; + break; + } else { + last = mid; + } + } else { + first = mid + 1; + } + } else if (policy == BsearchPolicy::LAST_NOT_LARGER) { + if (comp(target, *mid)) { + last = mid; + } else { + if (std::distance(mid, last) == 1 or comp(target, *(mid + 1))) { + result = mid; + break; + } else { + first = mid + 1; + } + } + } else { // policy == UNSPECIFIED or FIRST or LAST + 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 ::value_type, + typename Compare = std::less> +IterT bsearch(IterT first, + IterT last, + ValueT target, + BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) { + return bsearch(first, last, target, Compare(), policy); +} + +#endif // BSEARCH_BSEARCH_VARIENTS_HPP_ + diff --git a/c-cpp/16_bsearch/bsearch_varients_test.cc b/c-cpp/16_bsearch/bsearch_varients_test.cc new file mode 100644 index 0000000..36c2b1a --- /dev/null +++ b/c-cpp/16_bsearch/bsearch_varients_test.cc @@ -0,0 +1,41 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/24. + */ + +#include +#include + +#include "bsearch_varients.hpp" + +template +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 test{0, 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 5, 6, 8}; // std::less() + + 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, BsearchPolicy::FIRST_NOT_LESS); // 13 + test_bsearch(test, 7, BsearchPolicy::LAST_NOT_LARGER); // 12 + test_bsearch(test, 7, BsearchPolicy::FIRST); // 14 + test_bsearch(test, 8); // 13 + test_bsearch(test, 8, BsearchPolicy::FIRST); // 13 + test_bsearch(test, 8, BsearchPolicy::LAST); // 13 + + return 0; +} + From 3e73b9ec3fd0c74a442bd0ba947bde5d1a4ad886 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:54:49 +0800 Subject: [PATCH 032/141] [cpp][16_bsearch] modification expression. --- c-cpp/16_bsearch/bsearch_varients.hpp | 4 +-- c-cpp/16_bsearch/bsearch_varients_test.cc | 34 +++++++++++------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/c-cpp/16_bsearch/bsearch_varients.hpp b/c-cpp/16_bsearch/bsearch_varients.hpp index 35cf091..f59d719 100644 --- a/c-cpp/16_bsearch/bsearch_varients.hpp +++ b/c-cpp/16_bsearch/bsearch_varients.hpp @@ -8,7 +8,7 @@ #include #include -enum class BsearchPolicy { UNSPECIFIED, FIRST, LAST, FIRST_NOT_LESS, LAST_NOT_LARGER }; +enum class BsearchPolicy { UNSPECIFIED, FIRST, LAST, FIRST_NOT_LESS, LAST_NOT_GREATER }; // 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 @@ -35,7 +35,7 @@ IterT bsearch(IterT first, } else { first = mid + 1; } - } else if (policy == BsearchPolicy::LAST_NOT_LARGER) { + } else if (policy == BsearchPolicy::LAST_NOT_GREATER) { if (comp(target, *mid)) { last = mid; } else { diff --git a/c-cpp/16_bsearch/bsearch_varients_test.cc b/c-cpp/16_bsearch/bsearch_varients_test.cc index 36c2b1a..b83d87b 100644 --- a/c-cpp/16_bsearch/bsearch_varients_test.cc +++ b/c-cpp/16_bsearch/bsearch_varients_test.cc @@ -18,23 +18,23 @@ void test_bsearch(const VecT& test, int main() { std::vector test{0, 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 5, 6, 8}; // std::less() - 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, BsearchPolicy::FIRST_NOT_LESS); // 13 - test_bsearch(test, 7, BsearchPolicy::LAST_NOT_LARGER); // 12 - test_bsearch(test, 7, BsearchPolicy::FIRST); // 14 - test_bsearch(test, 8); // 13 - test_bsearch(test, 8, BsearchPolicy::FIRST); // 13 - test_bsearch(test, 8, BsearchPolicy::LAST); // 13 + 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, BsearchPolicy::FIRST_NOT_LESS); // 13 + test_bsearch(test, 7, BsearchPolicy::LAST_NOT_GREATER); // 12 + test_bsearch(test, 7, BsearchPolicy::FIRST); // 14 + test_bsearch(test, 8); // 13 + test_bsearch(test, 8, BsearchPolicy::FIRST); // 13 + test_bsearch(test, 8, BsearchPolicy::LAST); // 13 return 0; } From 592238436b25bbee753c728d6e82c5c27250c6ba Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:56:01 +0800 Subject: [PATCH 033/141] [cpp][16_bsearch] correct date of files. --- c-cpp/16_bsearch/bsearch_varients.hpp | 2 +- c-cpp/16_bsearch/bsearch_varients_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c-cpp/16_bsearch/bsearch_varients.hpp b/c-cpp/16_bsearch/bsearch_varients.hpp index f59d719..4ea5336 100644 --- a/c-cpp/16_bsearch/bsearch_varients.hpp +++ b/c-cpp/16_bsearch/bsearch_varients.hpp @@ -1,5 +1,5 @@ /** - * Created by Liam Huang (Liam0205) on 2018/10/24. + * Created by Liam Huang (Liam0205) on 2018/10/26. */ #ifndef BSEARCH_BSEARCH_VARIENTS_HPP_ diff --git a/c-cpp/16_bsearch/bsearch_varients_test.cc b/c-cpp/16_bsearch/bsearch_varients_test.cc index b83d87b..34a2252 100644 --- a/c-cpp/16_bsearch/bsearch_varients_test.cc +++ b/c-cpp/16_bsearch/bsearch_varients_test.cc @@ -1,5 +1,5 @@ /** - * Created by Liam Huang (Liam0205) on 2018/10/24. + * Created by Liam Huang (Liam0205) on 2018/10/26. */ #include From 880469a63ab100dd13883c9f52cef577f0b395d9 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 26 Oct 2018 16:59:29 +0800 Subject: [PATCH 034/141] [notes][16_bsearch] done. --- notes/16_bsearch/readme.md | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 notes/16_bsearch/readme.md diff --git a/notes/16_bsearch/readme.md b/notes/16_bsearch/readme.md new file mode 100644 index 0000000..541b35f --- /dev/null +++ b/notes/16_bsearch/readme.md @@ -0,0 +1,100 @@ +# 二分查找(下) + +本节课讨论二分的各种变体。实际上在针对上一节的代码中,已经实现了两个变体。本次实现四个变体: + +* 第一个等于给定值的元素 +* 最后一个等于给定值的元素 +* 第一个不小于给定值的元素 +* 最后一个不大于给定值的元素 + +```cpp +/** + * Created by Liam Huang (Liam0205) on 2018/10/26. + */ + +#ifndef BSEARCH_BSEARCH_VARIENTS_HPP_ +#define BSEARCH_BSEARCH_VARIENTS_HPP_ + +#include +#include + +enum class BsearchPolicy { UNSPECIFIED, FIRST, LAST, FIRST_NOT_LESS, LAST_NOT_GREATER }; + +// 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 ::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 (policy == BsearchPolicy::FIRST_NOT_LESS) { + if (!comp(*mid, target)) { + if (mid == first or comp(*(mid - 1), target)) { + result = mid; + break; + } else { + last = mid; + } + } else { + first = mid + 1; + } + } else if (policy == BsearchPolicy::LAST_NOT_GREATER) { + if (comp(target, *mid)) { + last = mid; + } else { + if (std::distance(mid, last) == 1 or comp(target, *(mid + 1))) { + result = mid; + break; + } else { + first = mid + 1; + } + } + } else { // policy == UNSPECIFIED or FIRST or LAST + 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 ::value_type, + typename Compare = std::less> +IterT bsearch(IterT first, + IterT last, + ValueT target, + BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) { + return bsearch(first, last, target, Compare(), policy); +} + +#endif // BSEARCH_BSEARCH_VARIENTS_HPP_ +``` From 364d2486439fa310969222191d26176f7a184a29 Mon Sep 17 00:00:00 2001 From: Shanto Kundu Date: Fri, 26 Oct 2018 22:07:43 +0600 Subject: [PATCH 035/141] add shan-ku to contributors list --- python/.vs/slnx.sqlite | Bin 0 -> 73728 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 python/.vs/slnx.sqlite diff --git a/python/.vs/slnx.sqlite b/python/.vs/slnx.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..482c4f834044219c4240a8540b34bcab3ad63308 GIT binary patch literal 73728 zcmeHQ3y>p6d6rJkku=lVr*>~&x;vkD<-6IHMsJ@DUTbx>?7iLfKF+=z>t&>A-6`JH zt|jfAHwC2b&c+x_NEM_C;wti}fTm)AW0ufQ4xQqIVWgMW`0HIx? zuFv3VtzK)@HtTEZ&-xjHQb}1WbrRw=!!OOv6z_?izM?X~6{wNzl3tBYoVHfF8oSUF z^hFAwWTCT?bMgl6tXk*=R5Nm3Rv{v`YU_yDL*algB8tvOmgpd1Z?^q9XdNExY}43a zXPGVf3WfyDQFTW*=e{N*f(nk!aJBKthM7Ky9N%7F-??jBUawVaSm{(iXD_)E`rl;2 z`XH#ac)C)-&1S7!TZeIUZ!w#7wMW~I;MhlpYcpWXZdPRCZi}1e_tsk%Dr~NAZ`60o z5pT|MzDQAYUJO!4u`9o}Aj9O&ElSLRB0trP(i>dSU1a|vyau?rCw?&L8? zVfLX4*fWqJ_d<`~?BjM3sf=-u6WiqDc9z*oufWIkY2V&hb1}b&JzFN-tDcWvwxP#1rP;=V<=O^rw&abi z)hJm|ESFBetgB6XN4&nsR7`giU13t*8cB45x@z%t^bK96ovCeJI!9acfIH|ERbkuU z*5;nXjV6o&yJnh;PLD4Vi#addOs!BaOfBAe<+WO%m1(j+onbbZtFSvgyV@RO?2p5m z1Emj7CObddrORSyHs(YfX4<2WGj`#2 zr!O)zmZ>SAeeJW9aaz~T*ez<5m(Mg$%In);Yld&CyAjwNhXXvMZccQd|3Xiq z$KeP2Fa#I^3;~7!Lx3T`5MT%x2t0b;?QtA?SAne1OUB{pl6or8jB6i}eA^O(CnuDA zE}Ig|sZ>r(z=c>=(o|f@C(9X}N>;=~HlI)7N>0p_6N)M%SCTR*6NJ*ayj;zQiL#uP zGMSv1jb|YXDM`*tIjfMAj%PATMKYC?SJGvhP)158$_Yz#RmCm@3g;E5*U*XRXe}v; zaV4ISK%G=3DWM$q6y3050XK zEGa2POqbJAJWujxm9&_`iMW_c=Oi&9rz$xBAgAE8n90j>JfFylu9G zr<{|aPqUevELSoK2?|gYP)RNWju_NQC4f|pr?MhAP&J*7!*G&LfDp!V5(AiqPGxWz zt4`Gl_(38M5JDxXa;gGDPbw`YGHFFBSE`w6CL!W@yqu8;PVJKNW#~mqNjRRxl~fXj zo^lqPGnLGO-#|MQIiIQ|a0bhOG0x=DsZ<wT=Nf=4XBCh6hxD3u)uI9;DfWgFI z3;{=o$EA3@l9w|Xu_`5%a=Hu-sDPEIR*;SB)oG(|HLKuE0)~+?zzWVOf%ztq0GlMi zC<(?7!+}`Mr7M+ef)0n8735`Trv;~Ku9~h^%iw5n@Moy5D#F+g)me0^g8!w#`3=O& zxm?mxQoqaXm_l^UfipL9XQZ&XU2i4E_qiQnve3YC3oG-Dl`Vz*NW`b4%#;*Qd~;?EgLJ-466U^cD0O^ltPaW4dF%7y=9dh5$o= zA;1t|2rvW~0t^9$07HNwzz}$e5$JWhL??at!t{(;M`F0w1ETilN^j|Mxni9DK#uwx zP47OvOw+?PV?n2D$f-Sq;0{1D+~|D{^e^a>=zZurFLA3_aSQ>507HNwzz|>vFa#I^ z3;~7!Lx3T`5MT&g1p-5^W6nJuJ9GEBrkuMT4RH0s-rxRUz`n3+oU=RxK<@vKh2BA) z|NjE|1o}gC3EhX5&@prf1%>YlUlN`a-YdLCXb8)~q|nEIm;W69LH>978eih$e0S*k zp??m26tc4qLx3T`5MT%}1Q-Gg0fqoWfFZyTcu@!(9P>JoPRy~e)45!mJEU?qFa&Yh#f|LuIz}KbDU&GV*RzcddL2iAv0kg+hm|#Wy?h%3->35r z4|pAU;43@u8hNdu}ZB`*`}mIpG6M{nNhh9 z^ziC>9PCxW)%0AiHCt=)`k76T@#r#<9<`B^XKJncFy3l2uIu(XvQT#uU|ru?GnE0^ z-Fo)nE)~Ho2nkeI8k-vgh&DG8wie!I3?j8lH+E>#AdgEgF#@672k-Q|a-%+Ij7A zyc#{XMteo44|xDCs5hR~0406WX1XvFa#I^3;~7!Lx3T`5MT%}1Q-Ggfmc2PNqEJ7<PK$jc@SV9h5$o=A;1t|2rvW~ z0t^9$07HNwzz|>vyn+!3!`lW<&gmVauM726yk0CwR=5KtQLm5_{!e(#E7$;-Y77B}07HNw zzz|>vFa#I^3;~7!Lx3URh`5r@4lx$S1lIwb4zJXYl0b6ySPCOuu5qU&e!?)JSYjp& zg@9@i14EjGg7eplYvIUd3QiD|bh212CU6?0nS9`u{a)ngs>k%pOK6X@{` zdWk}M2!WnKSJv4vjzKqRi6wSHmpNmYz+=QHKxUpmF7)UHJP|Yk5QOMuJL*7?i0YvR z0`x+QFTl|YJ*WV=&?5=>=!F(O05 zpziFbne>I2S$3_<4)_Yo*Sk#%f6l)65J!s_RikFzt4TdsqeSjaSsQF z-FfF8yL;b2#61NH?22(1>2=4PwjI8&-(0@F$M^Qp=62ZSdwQvQ`Ucn2Gvv;KwjCoD zcGK2b_WJHFOLljdf@kdaUC6?B3A}s6VeI*l`+&o|=~u6fT|bp>Z~N6Nec!KM=^KA~ z)!zB5SNhh!+db~E?fq4fW%IA*(RcrTcaMW^|3jc~d;d?K|G&jI;XvO+|A77sy&auL z^Jofn!!!S%75-HC9YGOJ2qOP8{@?fy@o(Vo;0Hqg9(p2lF|-^?g+_uu4SqHFkHPl^ zF9j>XJA>(9ci{QJ=K~)Oyfv^9m=BC{KjXf}{T=sy?k!xEJI+mT0slArAN4=#KkJwL z{l4dYf9-pxukKp_1=xonzz|>vFa#I^uRsK@za`+{4j*>+B&Yb^!q2|H#g?< z48I!WhK9^?ng}=Q^Gv)7xZ~rLYq_Ojx!^_uo`W}oXs(UcqN z@uc#mT8)LFUd7sO5;p|x$r-g862>oX$mh8s3o@}7t+k2QafLRS-a)clar-AcH)IUi zTD^$@Ab^L+TCceM!=CHXAbaQ#Ew{W~F0ZR$y-h#4{Xx%g3Z%52Q!rh}YG2&o2sfNG zxVTQa+7~z2$BjzB9T`#aTC3G-tu^?l-`rpqcL?Gvfd(A0o>>|o{4Nq7-1Ku0`9|ZH zD7bEAhZqeOp*J8&KF4;-LM7>zZ4^#^>thd`vKhj#bY<`(?p`i8mwgFx-; zQ>oj{vs>`T^+mYR1DC0=ua`R%1-`{NmPpWc)i~(SzAoSB*yRcdaebq-a*J{F1$@IJ zK-P?-fzROvc#8VP^+r6S!3lsCMR~N z-)mpU?;G_QnYX|WTGQ+6`ZveVaMyc*uPqbQ-do;WmTS;pGDWGsIsPVYzX#;B30CE) zDaRk-_PY(9>H=!Y@k3m{3wYWXLwcM1aeRmy-3Ro&I-2)$5hw5?5o1uJ?c%-A9N7Pd z<{jukxby!GR6qxWyM!sB8}9Z$!T&aY7oS4sg)^ZKg`Nz(A@o-CL;m^DYeVyVi2rzK z9eq)FlhERy=FjlM{GsGs0uS4~4G@9}N8neGHxAr-iZ5m*Aa( z1>s)dCjMT*i9R53q4%KsgktDF(c~*|$;VV;2rvW~0t^9$07HNwzz|>vFa$1-K-hJ- zeG8f#iQW=)4e5kelgE=S2c54Xk3<`1nm3c@wmY0!-bBQV1Il9o*Pv59X1tN+FisKm zL&!YIVUTm=xpC`>VwRA!otJiSm_e>XPSc@an&_^bE~UtC?JOxt9;(()_au@@-89pa zs)U&t_q+O>rm~8N&E)0c#OblIT)KT)iQ3%cD*^##34iQz!iPb@~@ByQB^dKr~W{&Bt8zpsV$4Vn+iD6xWz6zip5z$uxjI$kj zBr-_4!=RBvkb!F~`o zy@{sBNIG;QP4hI(k#v8SrWu;1NjjLKX_BTAO%pVY({zfY1CulrX?m2VM@SmEfu=E< zPLQ;JoTk^)^e|1YBWd3unjWO-0h&f>I!4n`lJ<_!beN_?B<)uE7;7CvfFZyTU|6g|tVC`oJFa#I^3;~7! zLx3T`5MT%}1Q-GgfnNs%$o@az@jFl&;`ld0=YoyEC;iX)Px>D7_}vZH(~f5y&s+l> zyzpNxlFvhDcwZ!$yaqKGMQU|8-@M(DA@PfATX8YEuvj`Vy?82mXYo{YdS!XO zGzV3jD9$ZM=jP#WWp?&xR4Z?xv3ahh;D$N7E)-oX9xpBy=L*H8=xJS0t!;IpO@N#+ zwJ@UK{9JUVI9r6~6sDI7(=)}RT17K>3)dC7-XiUL!P*QE+V$BeKOrp^(Zl2#;Z(XRcxxT$o z-z`VHImh`TMbUXNNFBwl{Mv#HlUHkv0B+|6H1k}UE8VqH1W>3i+ojAUv^~ZyL|nL& z#~g*(hbmytK!)54J$|!~+eN6(s*l@QoYlweY*Wsw);M-)#YcVojjP5&pd#1nxKWTR zXH^hQ*M6&yQ&miClaJe3W-q-0AJ?aSdt=ST{37;jnRKsuK7QGT9@~^=8xNLi8@Sn$ zH?~%zWI?f9Isvn;Htikp`XW;?-BEOfNqK7|(Fy9R#n;g{beVRhwt49sZOsGjpi@+Z zZG&5zdlG`}!6>k6rn%_!_#zPR?$XWF3iZO&;;mO+s|8w_Ci~MFW`ns3yVJ9)?J>sw zIILMNKlJN4+iks)%rLZF+Hq4)eE6{8iF8S>qF{Ffj}-?y+k}Lj^&%1JG>N?s6nhPZ z#*{>s_}c7NY7$LXqqmk!%YThGD>qy7Wr!Dd4#WIt7`xsTGsWZ6E3?bd%65ZJ04?1! zw8D?iFBVI;&C!hp80%honf3?fErlJymv)YXzTb5DB8egAg)w#chg%S_^^9p;Us5S< ztwTJwHbPeA-v65thfezr@O#n5cbi8{=*M;D*Bun$9kA;1t|2)t4dcw;#1>k~!)Tkbwr!{^D4o18?^)lv;N?bq52bh1>uJ8I`e z{e9HkXj7MDsVi@Rl}m$aiza)`GCM~8*wsC{8jQlisK(Oc!FcABa#-Ac;Q z=w3?>B41D!Evkr-g)F!%?AF=n@x}QQyJ|J|GO)LupEE91EsblU`NCue^{gVtmnN@X z-Cadc^u-S}NNf_#xvG3N!@c04j8x8$|mIMA)2K_*h&)-|S;xmOYGb*ELFEI$p34)N;I z({xuAdvHsjyS_(;Y&#yJhmnt5A?pIt%Ivt;A-P`Ua?&Wht+KIU(RUm#-~K?~AL$!Q zbF11LFta+kpsM}V-vPP$J@1Ry8)^&i_H6^bmDlh-0r)n%@5SzWky#Kv0K`?F`&sV8 zvHM=u8x88=b$cqX-{kq_x$i~d|FQS~Un$FcrUyfSA;1t|2rvW~0t^9$07HNwzz|>v KFa)j*0{;*3XB!Rx literal 0 HcmV?d00001 From e1a34399ea38d5eb379b847dddd0375adf2ecc2c Mon Sep 17 00:00:00 2001 From: abd171256 <44517978+abd171256@users.noreply.github.com> Date: Sat, 27 Oct 2018 11:48:28 +0530 Subject: [PATCH 036/141] Create f21 --- f21 | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 f21 diff --git a/f21 b/f21 new file mode 100644 index 0000000..72ef739 --- /dev/null +++ b/f21 @@ -0,0 +1,63 @@ +// A Stack based C++ program to find next +// greater element for all array elements +// in same order as input. +#include + +using namespace std; + +/* prints element and NGE pair for all +elements of arr[] of size n */ +void printNGE(int arr[], int n) +{ + stack s; + unordered_map mp; + + /* push the first element to stack */ + s.push(arr[0]); + + + // iterate for rest of the elements + for (int i = 1; i < n; i++) { + + if (s.empty()) { + s.push(arr[i]); + continue; + } + + /* if stack is not empty, then + pop an element from stack. + If the popped element is smaller + than next, then + a) print the pair + b) keep popping while elements are + smaller and stack is not empty */ + while (s.empty() == false && s.top() < arr[i]) { + mp[s.top()] = arr[i]; + s.pop(); + } + + /* push next to stack so that we can find + next smaller for it */ + s.push(arr[i]); + } + + /* After iterating over the loop, the remaining +elements in stack do not have the next smaller +element, so print -1 for them */ + while (s.empty() == false) { + mp[s.top()] = -1; + s.pop(); + } + + for (int i=0; i " << mp[arr[i]] << endl; +} + +/* Driver program to test above functions */ +int main() +{ + int arr[] = { 11, 13, 21, 3 }; + int n = sizeof(arr) / sizeof(arr[0]); + printNGE(arr, n); + return 0; +} From 25ac6701262a776cd8d58c7642b2479a89ed1513 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Sun, 28 Oct 2018 10:26:37 +0800 Subject: [PATCH 037/141] bsearch variant in c --- c-cpp/16_bsearch/bsearch_variant.c | 283 +++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 c-cpp/16_bsearch/bsearch_variant.c diff --git a/c-cpp/16_bsearch/bsearch_variant.c b/c-cpp/16_bsearch/bsearch_variant.c new file mode 100644 index 0000000..8827127 --- /dev/null +++ b/c-cpp/16_bsearch/bsearch_variant.c @@ -0,0 +1,283 @@ +#include +#include +#include +#include + + +int binary_search(int *arr, int size, int val) +{ + int low = 0, high = size - 1, mid; + + while (low <= high) { + mid = (low + high) / 2; + if (arr[mid] == val) + return mid; + + if (arr[mid] < val) + low = mid + 1; + else + high = mid - 1; + } + + return -1; +} + +/* + * find the first index with *val* + * + * This is a little tricky because the calculation of mid is integer based, it + * will be cast to the lower bound of an integer. + * + * In case the [low, high] range is of size 1 or 2 and arr[mid] >= val, we will + * have: + * + * mid = (low + high) / 2 = low + * high = mid - 1 = low - 1 < low, which break the loop + * + */ +int binary_search_first(int *arr, int size, int val) +{ + int low = 0, high = size - 1, mid; + + while (low <= high) { + mid = (low + high) / 2; + //printf("[%d-%d] %d\n", low, high, mid); + + if (arr[mid] >= val) + high = mid - 1; + else + low = mid + 1; + } + + //printf("[%d-%d] %d\n", low, high, mid); + if (arr[low] == val) + return low; + else + return -1; +} + +int binary_search_last(int *arr, int size, int val) +{ + int low = 0, high = size - 1, mid; + + while (low <= high) { + mid = (low + high) / 2; + + if (arr[mid] <= val) + low = mid + 1; + else + high = mid - 1; + } + + if (arr[high] == val) + return high; + else + return -1; +} + +int binary_search_first_r(int *arr, int size, int val) +{ + int mid = size / 2; + int idx; + + if (size <= 0) + return -1; + + // we find *val* at mid, try first half + if (arr[mid] == val) { + idx = binary_search_first_r(arr, mid, val); + return idx != -1 ? idx : mid; + } + + // mid == 0 means size == 1 + // so the only element in array doesn't equal to val + if (!mid) + return -1; + + if (arr[mid] < val) { + idx = binary_search_first_r(arr + mid + 1, size - mid - 1, val); + if (idx != -1) + idx += mid + 1; + } else { + idx = binary_search_first_r(arr, mid, val); + } + + return idx; +} + +int binary_search_last_r(int *arr, int size, int val) +{ + int mid = size / 2; + int idx; + + if (size <= 0) + return -1; + + // we find *val* at mid, try last half + if (arr[mid] == val) { + idx = binary_search_last_r(arr+mid+1, size-mid-1, val); + if (idx != -1) + mid += idx + 1; + return mid; + } + + // mid == 0 means size == 1 + // so the only element in array doesn't equal to val + if (!mid) + return -1; + + if (arr[mid] < val) { + idx = binary_search_last_r(arr + mid + 1, size - mid - 1, val); + if (idx != -1) + idx += mid + 1; + } else { + idx = binary_search_last_r(arr, mid, val); + } + + return idx; +} + +int binary_search_first_bigger(int *arr, int size, int val) +{ + int low = 0, high = size - 1, mid; + + while (low <= high) { + mid = (low + high) / 2; + + if (arr[mid] >= val) { + if (mid == 0 || arr[mid-1] < val) + return mid; + high = mid - 1; + } else { + low = mid + 1; + } + } + + return -1; +} + +int binary_search_first_bigger_r(int *arr, int size, int val) +{ + int mid = size / 2; + int idx; + + if (size <= 0) + return -1; + + if (arr[mid] >= val) { + // find one bigger than val, try first half + idx = binary_search_first_bigger_r(arr, mid, val); + if (idx == -1) + idx = mid; + } else { + // the bigger one may sit in second half + idx = binary_search_first_bigger_r(arr + mid + 1, size - mid - 1, val); + if (idx != -1) + idx += mid + 1; + } + + return idx; +} + +int binary_search_last_smaller(int *arr, int size, int val) +{ + int low = 0, high = size - 1, mid; + + while (low <= high) { + mid = (low + high) / 2; + + if (arr[mid] <= val) { + if (mid == 0 || arr[mid+1] > val) + return mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + + return -1; +} + +int binary_search_last_smaller_r(int *arr, int size, int val) +{ + int mid = size / 2; + int idx; + + if (size <= 0) + return -1; + + if (arr[mid] <= val) { + // find one smaller than val, try second half + idx = binary_search_last_smaller_r(arr + mid + 1, size - mid - 1, val); + if (idx != -1) + idx += mid + 1; + else + idx = mid; + } else { + // the smaller one may sit in first half + idx = binary_search_last_smaller_r(arr, mid, val); + } + + return idx; +} + +int main() +{ + int arr[10] = {1, 4, 5, 9, 12, 14, 19, 19, 31, 36}; + int idx; + + printf("Test Array:\n"); + for (idx = 0; idx < 10; idx++) + printf("%8d", arr[idx]); + printf("\n"); + + idx = binary_search_first(arr, 10, 19); + if (idx != -1) + printf("first 19 at %d\n", idx); + else + printf("19 not in arr \n"); + + idx = binary_search_first_r(arr, 10, 19); + if (idx != -1) + printf("first 19 at %d\n", idx); + else + printf("19 not in arr \n"); + + idx = binary_search_last(arr, 10, 19); + if (idx != -1) + printf("last 19 at %d\n", idx); + else + printf("19 not in arr \n"); + + idx = binary_search_last_r(arr, 10, 19); + if (idx != -1) + printf("last 19 at %d\n", idx); + else + printf("19 not in arr \n"); + + idx = binary_search_first_bigger(arr, 10, 12); + if (idx != -1) + printf("first bigger 12 at %d\n", idx); + else + printf("12 not in arr \n"); + + idx = binary_search_first_bigger_r(arr, 10, 12); + if (idx != -1) + printf("first bigger 12 at %d\n", idx); + else + printf("12 not in arr \n"); + + idx = binary_search_last_smaller(arr, 10, 12); + if (idx != -1) + printf("last smaller 12 at %d\n", idx); + else + printf("12 not in arr \n"); + + idx = binary_search_last_smaller_r(arr, 10, 12); + if (idx != -1) + printf("last smaller 12 at %d\n", idx); + else + printf("12 not in arr \n"); + + return 0; +} From f92c2ee6bc0453b30cc438e8e9314eb1730457ec Mon Sep 17 00:00:00 2001 From: Wenru Dong Date: Sun, 28 Oct 2018 20:46:23 +0000 Subject: [PATCH 038/141] Implementation of SkipList in python --- python/17_skiplist/skip_list.py | 91 +++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 python/17_skiplist/skip_list.py diff --git a/python/17_skiplist/skip_list.py b/python/17_skiplist/skip_list.py new file mode 100644 index 0000000..52069eb --- /dev/null +++ b/python/17_skiplist/skip_list.py @@ -0,0 +1,91 @@ +""" + An implementation of skip list. + The list stores positive integers without duplicates. + + 跳表的一种实现方法。 + 跳表中储存的是正整数,并且储存的是不重复的。 + + Author: Wenru +""" + +from typing import Optional +import random + +class ListNode: + + def __init__(self, data: Optional[int] = None): + self._data = data + self._forwards = [] # Forward pointers + +class SkipList: + + _MAX_LEVEL = 16 + + def __init__(self): + self._level_count = 1 + self._head = ListNode() + self._head._forwards = [None] * type(self)._MAX_LEVEL + + def find(self, value: int) -> Optional[ListNode]: + p = self._head + for i in range(self._level_count - 1, -1, -1): # Move down a level + while p._forwards[i] and p._forwards[i]._data < value: + p = p._forwards[i] # Move along level + + return p._forwards[0] if p._forwards[0] and p._forwards[0]._data == value else None + + def insert(self, value: int): + level = self._random_level() + if self._level_count < level: self._level_count = level + new_node = ListNode(value) + new_node._forwards = [None] * level + update = [self._head] * level # update is like a list of prevs + + p = self._head + for i in range(level - 1, -1, -1): + while p._forwards[i] and p._forwards[i]._data < value: + p = p._forwards[i] + + update[i] = p # Found a prev + + for i in range(level): + new_node._forwards[i] = update[i]._forwards[i] # new_node.next = prev.next + update[i]._forwards[i] = new_node # prev.next = new_node + + def delete(self, value): + update = [None] * self._level_count + p = self._head + for i in range(self._level_count - 1, -1, -1): + while p._forwards[i] and p._forwards[i]._data < value: + p = p._forwards[i] + update[i] = p + + if p._forwards[0] and p._forwards[0]._data == value: + for i in range(self._level_count - 1, -1, -1): + if update[i]._forwards[i] and update[i]._forwards[i]._data == value: + update[i]._forwards[i] = update[i]._forwards[i]._forwards[i] # Similar to prev.next = prev.next.next + + def _random_level(self, p: float = 0.5) -> int: + level = 1 + while random.random() < p and level < type(self)._MAX_LEVEL: + level += 1 + return level + + def __repr__(self) -> str: + values = [] + p = self._head + while p._forwards[0]: + values.append(str(p._forwards[0]._data)) + p = p._forwards[0] + return "->".join(values) + + +if __name__ == "__main__": + l = SkipList() + for i in range(10): + l.insert(i) + print(l) + p = l.find(7) + print(p._data) + l.delete(3) + print(l) \ No newline at end of file From 69f7def80beb0b57a94c1739dddaa58d666cebaa Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 10:10:26 +0800 Subject: [PATCH 039/141] [cpp][17_skiplist] init. --- c-cpp/17_skiplist/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c-cpp/17_skiplist/.gitkeep diff --git a/c-cpp/17_skiplist/.gitkeep b/c-cpp/17_skiplist/.gitkeep new file mode 100644 index 0000000..e69de29 From fafbccecf729cf4641587793104f876bee38eadf Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 10:15:06 +0800 Subject: [PATCH 040/141] [note][17_skiplist] init. --- notes/17_skiplist/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 notes/17_skiplist/.gitkeep diff --git a/notes/17_skiplist/.gitkeep b/notes/17_skiplist/.gitkeep new file mode 100644 index 0000000..e69de29 From ee613a3631f93fb243d6eb76c266738f00a3ef59 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 10:19:46 +0800 Subject: [PATCH 041/141] [notes][17_skiplist] introduction. --- notes/17_skiplist/readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 notes/17_skiplist/readme.md diff --git a/notes/17_skiplist/readme.md b/notes/17_skiplist/readme.md new file mode 100644 index 0000000..38c0e0c --- /dev/null +++ b/notes/17_skiplist/readme.md @@ -0,0 +1,9 @@ +# 跳表(Skip List) + +支持快速地: + +* 插入 +* 删除 +* 查找 + +某些情况下,跳表甚至可以替代红黑树(Red-Black tree)。Redis 当中的有序集合(Sorted Set)是用跳表实现的。 From 4038c72fe3854b8158176950d9179e119c1eebc3 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 10:26:50 +0800 Subject: [PATCH 042/141] [notes][17_skiplist] structure of skiplist. --- notes/17_skiplist/readme.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/notes/17_skiplist/readme.md b/notes/17_skiplist/readme.md index 38c0e0c..c2c7711 100644 --- a/notes/17_skiplist/readme.md +++ b/notes/17_skiplist/readme.md @@ -7,3 +7,17 @@ * 查找 某些情况下,跳表甚至可以替代红黑树(Red-Black tree)。Redis 当中的有序集合(Sorted Set)是用跳表实现的。 + +## 跳表的结构 + +跳表是对链表的改进。对于单链表来说,即使内容是有序的,查找具体某个元素的时间复杂度也要达到 $O(n)$。对于二分查找来说,由于链表不支持随机访问,根据 `first` 和 `last` 确定 `cut` 时,必须沿着链表依次迭代 `std::distance(first, last) / 2` 步;特别地,计算 `std::(first, last)` 本身,就必须沿着链表迭代才行。此时,二分查找的效率甚至退化到了 $O(n \log n)$,甚至还不如顺序遍历。 + +![单链表查找示例](https://static001.geekbang.org/resource/image/e1/6d/e18303fcedc068e5a168de04df956f6d.jpg) + +跳表的核心思想是用空间换时间,构建足够多级数的索引,来缩短查找具体值的时间开销。 + +![具有二级索引的跳表示例](https://static001.geekbang.org/resource/image/49/65/492206afe5e2fef9f683c7cff83afa65.jpg) + +例如对于一个具有 64 个有序元素的五级跳表,查找起来的过程大约如下图所示。 + +![五级跳表示例](https://static001.geekbang.org/resource/image/46/a9/46d283cd82c987153b3fe0c76dfba8a9.jpg) From 9a3e148b11e7aab1f9f596953b24279d03296d6a Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 10:46:55 +0800 Subject: [PATCH 043/141] [notes][17_skiplist] complexity analytics. --- notes/17_skiplist/readme.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/notes/17_skiplist/readme.md b/notes/17_skiplist/readme.md index c2c7711..e0bf0d8 100644 --- a/notes/17_skiplist/readme.md +++ b/notes/17_skiplist/readme.md @@ -21,3 +21,12 @@ 例如对于一个具有 64 个有序元素的五级跳表,查找起来的过程大约如下图所示。 ![五级跳表示例](https://static001.geekbang.org/resource/image/46/a9/46d283cd82c987153b3fe0c76dfba8a9.jpg) + +## 复杂度分析 + +对于一个每一级索引的跨度是下一级索引 $k$ 倍的跳表,每一次 `down` 操作,相当于将搜索范围缩小到「剩余的可能性的 $1 / k$」。因此,查找具体某个元素的时间复杂度大约需要 $\lfloor \log_k n\rfloor + 1$ 次操作;也就是说时间复杂度是 $O(\log n)$。 + +![跳表查询过程示例](https://static001.geekbang.org/resource/image/d0/0c/d03bef9a64a0368e6a0d23ace8bd450c.jpg) + +前面说了,跳表是一种用空间换时间的数据结构。因此它的空间复杂度一定不小。我们考虑原链表有 $n$ 个元素,那么第一级索引就有 $n / k$ 个元素,剩余的索引依次有 $n / k^2$, $n / k^3$, ..., $1$ 个元素。总共的元素个数是一个等比数列求和问题,它的值是 $\frac{n - 1}{k - 1}$。可见,不论 $k$ 是多少,跳表的空间复杂度都是 $O(n)$;但随着 $k$ 的增加,实际需要的额外节点数会下降。 + From f9e32832bf34d3543591794ec9553cb9f4700715 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 10:59:12 +0800 Subject: [PATCH 044/141] [notes][17_skiplist] UD operations. --- notes/17_skiplist/readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/notes/17_skiplist/readme.md b/notes/17_skiplist/readme.md index e0bf0d8..5dbd5da 100644 --- a/notes/17_skiplist/readme.md +++ b/notes/17_skiplist/readme.md @@ -30,3 +30,8 @@ 前面说了,跳表是一种用空间换时间的数据结构。因此它的空间复杂度一定不小。我们考虑原链表有 $n$ 个元素,那么第一级索引就有 $n / k$ 个元素,剩余的索引依次有 $n / k^2$, $n / k^3$, ..., $1$ 个元素。总共的元素个数是一个等比数列求和问题,它的值是 $\frac{n - 1}{k - 1}$。可见,不论 $k$ 是多少,跳表的空间复杂度都是 $O(n)$;但随着 $k$ 的增加,实际需要的额外节点数会下降。 +## 高效地插入和删除 + +对于链表来说,插入或删除一个给定结点的时间复杂度是 $O(1)$。因此,对于跳表来说,插入或删除某个结点,其时间复杂度完全依赖于查找这类结点的耗时。而我们知道,在跳表中查找某个元素的时间复杂度是 $O(\log n)$。因此,在跳表中插入或删除某个结点的时间复杂度是 $O(\log n)$。 + +![在跳表中插入一个元素](https://static001.geekbang.org/resource/image/65/6c/65379f0651bc3a7cfd13ab8694c4d26c.jpg) From 7feb6101fb8e467994e46937907b5c273648aafd Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 11:03:50 +0800 Subject: [PATCH 045/141] [notes][17_skiplist] dynamic update the index levels of skiplist. --- notes/17_skiplist/readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/notes/17_skiplist/readme.md b/notes/17_skiplist/readme.md index 5dbd5da..9d9f87a 100644 --- a/notes/17_skiplist/readme.md +++ b/notes/17_skiplist/readme.md @@ -35,3 +35,9 @@ 对于链表来说,插入或删除一个给定结点的时间复杂度是 $O(1)$。因此,对于跳表来说,插入或删除某个结点,其时间复杂度完全依赖于查找这类结点的耗时。而我们知道,在跳表中查找某个元素的时间复杂度是 $O(\log n)$。因此,在跳表中插入或删除某个结点的时间复杂度是 $O(\log n)$。 ![在跳表中插入一个元素](https://static001.geekbang.org/resource/image/65/6c/65379f0651bc3a7cfd13ab8694c4d26c.jpg) + +## 跳表索引的动态更新 + +为了维护跳表的结构,在不断插入数据的过程中,有必要动态维护跳表的索引结构。一般来说,可以采用随机层级法。具体来说是引入一个输出整数的随机函数。当随机函数输出 $K$,则更新从第 $1$ 级至第 $K$ 级的索引。为了保证索引结构和数据规模大小的匹配,一般采用二项分布的随机函数。 + +![在跳表中插入一个元素并更新索引](https://static001.geekbang.org/resource/image/a8/a7/a861445d0b53fc842f38919365b004a7.jpg) From 9e6982b75ed7098019a2d4604587fe326b2d70fd Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 11:54:47 +0800 Subject: [PATCH 046/141] [cpp][17_skiplist] constructors, destructor, and assignments. --- c-cpp/17_skiplist/skiplist.hpp | 60 ++++++++++++++++++++++++++++++ c-cpp/17_skiplist/skiplist_test.cc | 12 ++++++ 2 files changed, 72 insertions(+) create mode 100644 c-cpp/17_skiplist/skiplist.hpp create mode 100644 c-cpp/17_skiplist/skiplist_test.cc diff --git a/c-cpp/17_skiplist/skiplist.hpp b/c-cpp/17_skiplist/skiplist.hpp new file mode 100644 index 0000000..bb4c80c --- /dev/null +++ b/c-cpp/17_skiplist/skiplist.hpp @@ -0,0 +1,60 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/29. + */ + +#ifndef SKIPLIST_SKIPLIST_HPP_ +#define SKIPLIST_SKIPLIST_HPP_ + +#include +#include +#include +#include +#include + +template > +class skiplist : public std::list { + public: + using container_type = std::list; + using value_type = typename container_type::value_type; + using allocator_type = typename container_type::allocator_type; + using size_type = typename container_type::size_type; + using difference_type = typename container_type::difference_type; + using reference = typename container_type::reference; + using const_reference = typename container_type::const_reference; + using pointer = typename container_type::pointer; + using const_pointer = typename container_type::const_pointer; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + using reverse_iterator = typename container_type::reverse_iterator; + using const_reverse_iterator = typename container_type::const_reverse_iterator; + + public: + skiplist() : container_type() {} + explicit skiplist(const allocator_type& alloc) : container_type(alloc) {} + skiplist( size_type count, + const_reference value, + const allocator_type& alloc = allocator_type()) : + container_type(count, value, alloc) {} + explicit skiplist(size_type count, const allocator_type& alloc = allocator_type()) : + container_type(count, alloc) {} + template + skiplist(InputIt first, InputIt last, const allocator_type& alloc = allocator_type()) : + container_type(first, last, alloc) {} + skiplist(const skiplist& other); + skiplist(const skiplist& other, const allocator_type& alloc); + skiplist(skiplist&& other); + skiplist(skiplist&& other, const allocator_type& alloc); + skiplist(std::initializer_list init, + const allocator_type& alloc = allocator_type()) : + container_type(std::forward>(init), alloc) {} + ~skiplist(); + + public: + skiplist& operator=(const skiplist& other); + skiplist& operator=(skiplist&& other); +}; + +#endif // SKIPLIST_SKIPLIST_HPP_ + + diff --git a/c-cpp/17_skiplist/skiplist_test.cc b/c-cpp/17_skiplist/skiplist_test.cc new file mode 100644 index 0000000..71f5ef8 --- /dev/null +++ b/c-cpp/17_skiplist/skiplist_test.cc @@ -0,0 +1,12 @@ +#include +#include "skiplist.hpp" + +int main() { + skiplist test{1, 2, 3, 4}; + for (auto i : test) { + std::cout << i << " "; + } + std::cout << std::endl; + + return 0; +} From 2c6e0bce70d5810ba23edba4e8563e2892583010 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Mon, 29 Oct 2018 12:07:27 +0800 Subject: [PATCH 047/141] [cpp][17_skiplist] impl of IndexNode type. --- c-cpp/17_skiplist/skiplist.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/c-cpp/17_skiplist/skiplist.hpp b/c-cpp/17_skiplist/skiplist.hpp index bb4c80c..6558cf6 100644 --- a/c-cpp/17_skiplist/skiplist.hpp +++ b/c-cpp/17_skiplist/skiplist.hpp @@ -29,6 +29,14 @@ class skiplist : public std::list { using reverse_iterator = typename container_type::reverse_iterator; using const_reverse_iterator = typename container_type::const_reverse_iterator; + private: + template + struct IndexNode { + IndexNode(const T& data_, Iter down_) : data(data_), down(down_) {} + const T data; + const Iter down; + }; + public: skiplist() : container_type() {} explicit skiplist(const allocator_type& alloc) : container_type(alloc) {} From 587f438b0739758e59c4ed681f4dd887c3985cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?leotyliu=28=E5=88=98=E5=A4=A9=E4=B8=80=29?= Date: Mon, 29 Oct 2018 15:37:49 +0800 Subject: [PATCH 048/141] =?UTF-8?q?=E4=BA=8C=E5=88=86=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E7=9A=84=E5=8F=98=E4=BD=93=20by=20golang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go/15_binarysearch/binarysearch.go | 108 ++++++++++++++++++++++++ go/15_binarysearch/binarysearch_test.go | 76 +++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/go/15_binarysearch/binarysearch.go b/go/15_binarysearch/binarysearch.go index fdd1763..f9c8ff5 100644 --- a/go/15_binarysearch/binarysearch.go +++ b/go/15_binarysearch/binarysearch.go @@ -45,3 +45,111 @@ func bs(a []int, v int, low, high int) int { return bs(a, v, mid+1, high) } } + +//查找第一个等于给定值的元素 +func BinarySearchFirst(a []int, v int) int { + n := len(a) + if n == 0 { + return -1 + } + + low := 0 + high := n - 1 + for low <= high { + mid := (low + high) >> 1 + if a[mid] > v { + high = mid - 1 + } else if a[mid] < v { + low = mid + 1 + } else { + if mid == 0 || a[mid-1] != v { + return mid + } else { + high = mid - 1 + } + } + } + + return -1 +} + +//查找最后一个值等于给定值的元素 +func BinarySearchLast(a []int, v int) int { + n := len(a) + if n == 0 { + return -1 + } + + low := 0 + high := n - 1 + for low <= high { + mid := (low + high) >> 1 + if a[mid] > v { + high = mid - 1 + } else if a[mid] < v { + low = mid + 1 + } else { + if mid == n-1 || a[mid+1] != v { + return mid + } else { + low = mid + 1 + } + } + } + + return -1 +} + +//查找第一个大于等于给定值的元素 +func BinarySearchFirstGT(a []int, v int) int { + n := len(a) + if n == 0 { + return -1 + } + + low := 0 + high := n - 1 + for low <= high { + mid := (high + low) >> 1 + if a[mid] > v { + high = mid - 1 + } else if a[mid] < v { + low = mid + 1 + } else { + if mid != n-1 && a[mid+1] > v { + return mid + 1 + } else { + low = mid + 1 + } + } + } + + return -1 +} + +//查找最后一个小于等于给定值的元素 +func BinarySearchLastLT(a []int, v int) int { + n := len(a) + if n == 0 { + return -1 + } + + low := 0 + high := n - 1 + for low <= high { + mid := (low + high) >> 1 + if a[mid] > v { + high = mid - 1 + } else if a[mid] < v { + low = mid + 1 + } else { + if mid == 0 || a[mid-1] < v { + return mid - 1 + } else { + high = mid - 1 + } + } + } + + return -1 +} diff --git a/go/15_binarysearch/binarysearch_test.go b/go/15_binarysearch/binarysearch_test.go index 755fc56..2ac76a1 100644 --- a/go/15_binarysearch/binarysearch_test.go +++ b/go/15_binarysearch/binarysearch_test.go @@ -25,3 +25,79 @@ func TestBinarySearchRecursive(t *testing.T) { t.Fatal(BinarySearch(a, 4)) } } + +func TestBinarySearchFirst(t *testing.T) { + var a []int + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchFirst(a, 2) != 1 { + t.Fatal(BinarySearchFirst(a, 2)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchFirst(a, 3) != 4 { + t.Fatal(BinarySearchFirst(a, 3)) + } +} + +func TestBinarySearchLast(t *testing.T) { + var a []int + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchLast(a, 2) != 3 { + t.Fatal(BinarySearchLast(a, 2)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchLast(a, 3) != 4 { + t.Fatal(BinarySearchLast(a, 3)) + } +} + +func TestBinarySearchFirstGT(t *testing.T) { + var a []int + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchFirstGT(a, 2) != 4 { + t.Fatal(BinarySearchFirstGT(a, 2)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchFirstGT(a, 1) != 1 { + t.Fatal(BinarySearchFirstGT(a, 1)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchFirstGT(a, 3) != 5 { + t.Fatal(BinarySearchFirstGT(a, 3)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchFirstGT(a, 4) != -1 { + t.Fatal(BinarySearchFirstGT(a, 4)) + } +} + +func TestBinarySearchLastLT(t *testing.T) { + var a []int + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchLastLT(a, 2) != 0 { + t.Fatal(BinarySearchLastLT(a, 2)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchLastLT(a, 1) != -1 { + t.Fatal(BinarySearchLastLT(a, 1)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchLastLT(a, 3) != 3 { + t.Fatal(BinarySearchLastLT(a, 3)) + } + + a = []int{1, 2, 2, 2, 3, 4} + if BinarySearchLastLT(a, 4) != 4 { + t.Fatal(BinarySearchLastLT(a, 4)) + } +} From d4f700beface6100f58c8a098f092c3e94682316 Mon Sep 17 00:00:00 2001 From: HuaQiang Date: Mon, 29 Oct 2018 15:44:49 +0800 Subject: [PATCH 049/141] Add files via upload --- c-cpp/07_linkedlist/SingleList.cpp | 133 ++++++++++++++++------------- 1 file changed, 75 insertions(+), 58 deletions(-) diff --git a/c-cpp/07_linkedlist/SingleList.cpp b/c-cpp/07_linkedlist/SingleList.cpp index a43079c..5f07863 100644 --- a/c-cpp/07_linkedlist/SingleList.cpp +++ b/c-cpp/07_linkedlist/SingleList.cpp @@ -6,7 +6,7 @@ using namespace std; class CElement; /*** - * @brief 单链表容器 + * @brief */ class CSingleList { @@ -15,61 +15,61 @@ public: ~CSingleList(); /** - * @brief 插入..链表末尾插入 - * @return 成功返回非空指针,否则失败 + * @brief ..ĩβ + * @return ɹطǿָ,ʧ */ CElement* Insert(void* lpData, int iDataSize); /** - * @brief 插入..链表指定位置插入 - * @return 成功返回非空指针,否则失败 + * @brief ..ָλò + * @return ɹطǿָ,ʧ */ CElement* Insert(CElement* lpElement, void* lpData, int iDataSize); /** - * @brief 删除 + * @brief ɾ */ void Delete(CElement*); /** - * @brief 链首 + * @brief */ CElement* Begin(); /** - * @brief 下一个元素 + * @brief һԪ */ CElement* Next(); /*** - * @brief 链尾 + * @brief β */ CElement* End(); /** - * @brief 是否是空链表 - * @return 空返回TRUE,否则返回FALSE + * @brief Ƿǿ + * @return շTRUE򷵻FALSE */ bool Empty(); /** - * @brief 反转 + * @brief ת */ void Reverse(); /** - * @brief 检测环 - * @return 返回TRUE时表示链表存在环,否则不存在环. + * @brief ⻷ + * @return TRUEʱʾڻ,򲻴ڻ. */ bool CheckCircle(); /** - * @brief 合并2个有序的链表 + * @brief ϲ2 */ void Merge(CSingleList& lst, std::function); /** - * @brief 删除倒数第K个结点 + * @brief ɾK */ void DeleteLastKth(int k); /** - * @brief 求中间节点 + * @brief мڵ */ CElement* Center(); private: @@ -80,18 +80,18 @@ private: CSingleList(CSingleList const & rhs); CSingleList& operator= (CSingleList const& rhs); private: - /**头结点*/ + /**ͷ*/ CElement* m_lpHead; - /**哨兵*/ + /**ڱ*/ CElement* m_lpSentinel; - /**空结点,用于End()返回 */ + /**ս㣬End() */ CElement* m_lpNull; - /**当前结点. 枚举时使用. */ + /**ǰ. öʱʹ. */ CElement* m_lpCur; }; /*** - * @brief 单链表结点元素. + * @brief Ԫ. */ class CElement { @@ -101,11 +101,11 @@ protected: ~CElement(); public: /*** - * @brief 获取数据指针 + * @brief ȡָ */ void* GetDataPtr(); protected: - /**下一个结点*/ + /**һ*/ CElement* m_lpNext; void* m_lpData; }; @@ -113,7 +113,7 @@ protected: void CreateList(CSingleList& lst) { - //循环插入元素到链表尾 + //ѭԪصβ for(int i=1; i<10;i++) { int* p = new int(); @@ -134,15 +134,15 @@ void PrintList(CSingleList& lst) int main() { { - /// 链表的基本操作,插入/枚举/删除 + /// Ļ/ö/ɾ CSingleList lst; CElement* lpElement = NULL; CreateList(lst); - std::cout<<"枚举链表当前的元素"<GetDataPtr())<GetDataPtr())<GetDataPtr())<GetDataPtr())<GetDataPtr())<GetDataPtr())<m_lpNext = lpCurElement->m_lpNext; lpCurElement->m_lpNext = lpNewElement; - }else{//插入到指定元素的前面 + }else{//뵽ָԪصǰ CElement* lpIter = m_lpSentinel; while(NULL != lpIter) { @@ -443,11 +443,13 @@ bool CSingleList::CheckCircle() return false; } +/** + * ϲ2 +*/ void CSingleList::Merge(CSingleList& lst, std::function fnCompare) { CElement* lpL1 = Begin(); CElement* lpL2 = lst.Begin(); - CElement* lpTail = NULL; if(!fnCompare) { @@ -458,7 +460,26 @@ void CSingleList::Merge(CSingleList& lst, std::function { if(lpL1 != End()) { + /** + * Ҫȷλ + * + * 1,2; 1 <- 2, 2ϲ1 + * + * 1ԪС2еԪأѭ1д2еĵǰԪصԪ + * 1ҵĵԪλ[A]ʱ2еĵǰԪز뵽Ԫλ[A]ǰ; + * 1вλ1ĩλԪ + */ iRet = fnCompare(lpL1->GetDataPtr(), lpL2->GetDataPtr()); + if(iRet < 0){ + lpL1 = Next(); + while(lpL1 != End()){ + iRet = fnCompare(lpL1->GetDataPtr(), lpL2->GetDataPtr()); + if(iRet > 0){ + break; + } + lpL1 = Next(); + } + } }else{ iRet = -1; } @@ -468,17 +489,13 @@ void CSingleList::Merge(CSingleList& lst, std::function lpNewElement->m_lpData = lpL2->GetDataPtr(); if(lpL1 != End()) { - Insert(lpNewElement,lpL1, iRet <= 0); + Insert(lpNewElement,lpL1, iRet < 0); }else{ - if(NULL == lpTail) - { - lpTail = Tail(); - } + CElement* lpTail = Tail(); Insert(lpNewElement,lpTail); } } lpL2 = lst.Next(); - lpL1 = Next(); } } From 9e4d062f3097207db702117867fca7c23ed59d8f Mon Sep 17 00:00:00 2001 From: zhenchaozhu <1025360135@qq.com> Date: Mon, 29 Oct 2018 17:09:05 +0800 Subject: [PATCH 050/141] add python stack simple browser --- python/08_stack/simple_browser.py | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 python/08_stack/simple_browser.py diff --git a/python/08_stack/simple_browser.py b/python/08_stack/simple_browser.py new file mode 100644 index 0000000..ff7edfe --- /dev/null +++ b/python/08_stack/simple_browser.py @@ -0,0 +1,75 @@ +""" + a simple browser realize + Author: zhenchao.zhu + 解答:我们使用两个栈,X 和 Y,我们把首次浏览的页面依次压入栈 X,当点击后退按钮时,再依次从栈 X 中出栈, + 并将出栈的数据依次放入栈 Y。当我们点击前进按钮时,我们依次从栈 Y 中取出数据,放入栈 X 中。 + 当栈 X 中没有数据时,那就说明没有页面可以继续后退浏览了。当栈 Y 中没有数据, + 那就说明没有页面可以点击前进按钮浏览了。 +""" + +import sys +# 引用当前文件夹下的single_linked_list +sys.path.append('linked_stack.py') +from linked_stack import LinkedStack +#from .linked_stack import LinkedStack + +class NewLinkedStack(LinkedStack): + + def is_empty(self): + return not self._top + + +class Browser(): + + def __init__(self): + self.forward_stack = NewLinkedStack() + self.back_stack = NewLinkedStack() + + def can_forward(self): + if self.back_stack.is_empty(): + return False + + return True + + def can_back(self): + if self.forward_stack.is_empty(): + return False + + return True + + def open(self, url): + print("Open new url %s" % url, end="\n") + self.forward_stack.push(url) + + def back(self): + if self.forward_stack.is_empty(): + return + + top = self.forward_stack.pop() + self.back_stack.push(top) + print("back to %s" % top, end="\n") + + def forward(self): + if self.back_stack.is_empty(): + return + + top = self.back_stack.pop() + self.forward_stack.push(top) + print("forward to %s" % top, end="\n") + + +if __name__ == '__main__': + + browser = Browser() + browser.open('a') + browser.open('b') + browser.open('c') + if browser.can_back(): + browser.back() + + if browser.can_forward(): + browser.forward() + + browser.back() + browser.back() + browser.back() From 55690465e4dc81dab727137da50e5d8a65ce466a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?leotyliu=28=E5=88=98=E5=A4=A9=E4=B8=80=29?= Date: Mon, 29 Oct 2018 19:31:16 +0800 Subject: [PATCH 051/141] =?UTF-8?q?=E8=B7=B3=E8=A1=A8=20by=20golang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go/17_skiplist/skiplist.go | 177 ++++++++++++++++++++++++++++++++ go/17_skiplist/skiplist_test.go | 38 +++++++ 2 files changed, 215 insertions(+) create mode 100644 go/17_skiplist/skiplist.go create mode 100644 go/17_skiplist/skiplist_test.go diff --git a/go/17_skiplist/skiplist.go b/go/17_skiplist/skiplist.go new file mode 100644 index 0000000..0938ada --- /dev/null +++ b/go/17_skiplist/skiplist.go @@ -0,0 +1,177 @@ +package _7_skiplist + +import ( + "fmt" + "math" + "math/rand" +) + +const ( + //最高层数 + MAX_LEVEL = 16 +) + +//跳表节点结构体 +type skipListNode struct { + //跳表保存的值 + v interface{} + //用于排序的分值 + score int + //层高 + level int + //每层前进指针 + forwards []*skipListNode +} + +//新建跳表节点 +func newSkipListNode(v interface{}, score, level int) *skipListNode { + return &skipListNode{v: v, score: score, forwards: make([]*skipListNode, level, level), level: level} +} + +//跳表结构体 +type SkipList struct { + //跳表头结点 + head *skipListNode + //跳表当前层数 + level int + //跳表长度 + length int +} + +//实例化跳表对象 +func NewSkipList() *SkipList { + //头结点,便于操作 + head := newSkipListNode(0, math.MinInt32, MAX_LEVEL) + return &SkipList{head, 1, 0} +} + +//获取跳表长度 +func (sl *SkipList) Length() int { + return sl.length +} + +//获取跳表层级 +func (sl *SkipList) Level() int { + return sl.level +} + +//插入节点到跳表中 +func (sl *SkipList) Insert(v interface{}, score int) int { + if nil == v { + return 1 + } + + //查找插入位置 + cur := sl.head + //记录每层的路径 + update := [MAX_LEVEL]*skipListNode{} + i := MAX_LEVEL - 1 + for ; i >= 0; i-- { + for nil != cur.forwards[i] { + if cur.forwards[i].v == v { + return 2 + } + if cur.forwards[i].score > score { + update[i] = cur + break + } + cur = cur.forwards[i] + } + if nil == cur.forwards[i] { + update[i] = cur + } + } + + //通过随机算法获取该节点层数 + level := 1 + for i := 1; i < MAX_LEVEL; i++ { + if rand.Int31()%7 == 1 { + level++ + } + } + + //创建一个新的跳表节点 + newNode := newSkipListNode(v, score, level) + + //原有节点连接 + for i := 0; i <= level-1; i++ { + next := update[i].forwards[i] + update[i].forwards[i] = newNode + newNode.forwards[i] = next + } + + //如果当前节点的层数大于之前跳表的层数 + //更新当前跳表层数 + if level > sl.level { + sl.level = level + } + + //更新跳表长度 + sl.length++ + + return 0 +} + +//查找 +func (sl *SkipList) Find(v interface{}, score int) *skipListNode { + if nil == v || sl.length == 0 { + return nil + } + + cur := sl.head + for i := sl.level - 1; i >= 0; i-- { + for nil != cur.forwards[i] { + if cur.forwards[i].score == score && cur.forwards[i].v == v { + return cur.forwards[i] + } else if cur.forwards[i].score > score { + break + } + cur = cur.forwards[i] + } + } + + return nil +} + +//删除节点 +func (sl *SkipList) Delete(v interface{}, score int) int { + if nil == v { + return 1 + } + + //查找前驱节点 + cur := sl.head + //记录前驱路径 + update := [MAX_LEVEL]*skipListNode{} + for i := sl.level - 1; i >= 0; i-- { + update[i] = sl.head + for nil != cur.forwards[i] { + if cur.forwards[i].score == score && cur.forwards[i].v == v { + update[i] = cur + break + } + cur = cur.forwards[i] + } + } + + cur = update[0].forwards[0] + for i := cur.level - 1; i >= 0; i-- { + if update[i] == sl.head && cur.forwards[i] == nil { + sl.level = i + } + + if nil == update[i].forwards[i] { + update[i].forwards[i] = nil + } else { + update[i].forwards[i] = update[i].forwards[i].forwards[i] + } + } + + sl.length-- + + return 0 +} + +func (sl *SkipList) String() string { + return fmt.Sprintf("level:%+v, length:%+v", sl.level, sl.length) +} diff --git a/go/17_skiplist/skiplist_test.go b/go/17_skiplist/skiplist_test.go new file mode 100644 index 0000000..3c04f36 --- /dev/null +++ b/go/17_skiplist/skiplist_test.go @@ -0,0 +1,38 @@ +package _7_skiplist + +import "testing" + +func TestSkipList(t *testing.T) { + sl := NewSkipList() + + sl.Insert("leo", 95) + t.Log(sl.head.forwards[0]) + t.Log(sl.head.forwards[0].forwards[0]) + t.Log(sl) + t.Log("-----------------------------") + + sl.Insert("jack", 88) + t.Log(sl.head.forwards[0]) + t.Log(sl.head.forwards[0].forwards[0]) + t.Log(sl.head.forwards[0].forwards[0].forwards[0]) + t.Log(sl) + t.Log("-----------------------------") + + sl.Insert("lily", 100) + t.Log(sl.head.forwards[0]) + t.Log(sl.head.forwards[0].forwards[0]) + t.Log(sl.head.forwards[0].forwards[0].forwards[0]) + t.Log(sl.head.forwards[0].forwards[0].forwards[0].forwards[0]) + t.Log(sl) + t.Log("-----------------------------") + + t.Log(sl.Find("jack", 88)) + t.Log("-----------------------------") + + sl.Delete("leo", 95) + t.Log(sl.head.forwards[0]) + t.Log(sl.head.forwards[0].forwards[0]) + t.Log(sl.head.forwards[0].forwards[0].forwards[0]) + t.Log(sl) + t.Log("-----------------------------") +} From 980fa06605e73c5a47d690c6f70852d1d5498b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=9F=8F=E6=9E=97?= <37291290+luckydog612@users.noreply.github.com> Date: Tue, 30 Oct 2018 11:03:47 +0800 Subject: [PATCH 052/141] Create binarysearch2.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 16 | 二分查找(下) --- go/binarysearch2.go | 90 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 go/binarysearch2.go diff --git a/go/binarysearch2.go b/go/binarysearch2.go new file mode 100644 index 0000000..ef2549e --- /dev/null +++ b/go/binarysearch2.go @@ -0,0 +1,90 @@ +package binarySearch + +//查找第一个值等于给定值得元素 +func BinarySearch2(nums []int, value int) int { + length := len(nums) + start := 0 + end := length - 1 + for start <= end { + mid := (start + end) / 2 + if nums[mid] > value { + end = mid - 1 + } else if nums[mid] < value { + start = mid + 1 + } else { + for mid >= 0 { + if nums[mid-1] == value { + mid-- + } else { + return mid + } + } + } + } + return -1 +} + +// 查找最后一个值等于给定值的元素 +func BinarySearch3(nums []int, value int) int { + start := 0 + end := len(nums) - 1 + for start <= end { + mid := (start + end) / 2 + if nums[mid] > value { + end = mid - 1 + } else if nums[mid] < value { + start = mid + 1 + } else { + for mid < len(nums) { + if nums[mid+1] == value { + mid++ + } else { + return mid + } + } + } + } + return -1 +} + +// 查找第一个大于等于给定值的元素 +func BinarySearch4(nums []int, value int) int { + start := 0 + end := len(nums) - 1 + for start <= end { + mid := (start + end) >> 1 + if nums[mid] < value { + start = mid + 1 + } else { + for mid >= 0 { + if nums[mid-1] >= value { + mid-- + } else { + return mid + } + } + } + } + return -1 +} + +// 查找最后一个小于等于给定值的元素 +func BinarySearch5(nums []int, value int) int { + start := 0 + end := len(nums) - 1 + for start <= end { + mid := (start + end) >> 1 + if nums[mid] > value { + end = mid - 1 + } else { + for mid < len(nums) { + if nums[mid+1] <= value { + mid++ + } else { + return mid + } + } + } + } + return -1 +} From 435b76b903c7d02a20f3c66362d9a9cb730d5dca Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 11:06:35 +0800 Subject: [PATCH 053/141] [cpp][17_skiplist] get random level. --- c-cpp/17_skiplist/skiplist.hpp | 28 +++++++++++++++++++++++----- c-cpp/17_skiplist/skiplist_test.cc | 3 +++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist.hpp b/c-cpp/17_skiplist/skiplist.hpp index 6558cf6..b48b8b9 100644 --- a/c-cpp/17_skiplist/skiplist.hpp +++ b/c-cpp/17_skiplist/skiplist.hpp @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include template > @@ -30,11 +33,18 @@ class skiplist : public std::list { using const_reverse_iterator = typename container_type::const_reverse_iterator; private: - template + static const size_type MAX_LEVEL = 16; + mutable size_type level_count = 1; + const unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::default_random_engine generator = std::default_random_engine(seed); + std::binomial_distribution distribution = std::binomial_distribution(MAX_LEVEL, 0.5); + + private: + template struct IndexNode { - IndexNode(const T& data_, Iter down_) : data(data_), down(down_) {} - const T data; - const Iter down; + IndexNode(const Value& data_, Iter down_) : data(data_), down(down_) {} + const Value data; + const Iter down; }; public: @@ -56,11 +66,19 @@ class skiplist : public std::list { skiplist(std::initializer_list init, const allocator_type& alloc = allocator_type()) : container_type(std::forward>(init), alloc) {} - ~skiplist(); + ~skiplist() {} public: skiplist& operator=(const skiplist& other); skiplist& operator=(skiplist&& other); + + private: + inline size_type get_random_level() { return distribution(generator); } + + public: + iterator find(const value_type& target); + iterator insert(const value_type& value); + iterator erase(const value_type& value); }; #endif // SKIPLIST_SKIPLIST_HPP_ diff --git a/c-cpp/17_skiplist/skiplist_test.cc b/c-cpp/17_skiplist/skiplist_test.cc index 71f5ef8..fa41266 100644 --- a/c-cpp/17_skiplist/skiplist_test.cc +++ b/c-cpp/17_skiplist/skiplist_test.cc @@ -8,5 +8,8 @@ int main() { } std::cout << std::endl; + for (size_t i = 0; i != 20; ++i) + std::cout << test.get_random_level() << std::endl; + return 0; } From 42426ba5a8f0e0b75126f678f031e820bdc06453 Mon Sep 17 00:00:00 2001 From: Jiandan Date: Tue, 30 Oct 2018 11:07:29 +0800 Subject: [PATCH 054/141] [swift][06_linkedlist][add] [swift][07_linkedlist][add] [swift][08_stack][add] --- swift/06_linkedlist/SinglyLinkedList.swift | 128 +++++++++++++++++++++ swift/07_linkedlist/LinkedListAlgo.swift | 111 ++++++++++++++++++ swift/08_stack/Browser.swift | 27 +++++ 3 files changed, 266 insertions(+) create mode 100644 swift/06_linkedlist/SinglyLinkedList.swift create mode 100644 swift/07_linkedlist/LinkedListAlgo.swift create mode 100644 swift/08_stack/Browser.swift diff --git a/swift/06_linkedlist/SinglyLinkedList.swift b/swift/06_linkedlist/SinglyLinkedList.swift new file mode 100644 index 0000000..a9af410 --- /dev/null +++ b/swift/06_linkedlist/SinglyLinkedList.swift @@ -0,0 +1,128 @@ +// +// Created by Jiandan on 2018/10/12. +// Copyright © 2018 Jiandan. All rights reserved. +// + +import Foundation + +class Node { + var value: T? + var next: Node? + + init(){} + + init(value: T) { + self.value = value + } +} + +/// 单链表 +/// 实现插入、删除、查找操作 +class List { + private var dummy = Node() // 哨兵结点,不存储数据 + var size: Int { + var num = 0 + var tmpNode = dummy.next + while tmpNode != nil { + num += 1 + tmpNode = tmpNode!.next + } + return num + } + var isEmpty: Bool { return size > 0 } + + /// find node with value + func node(with value: Element) -> Node? { + var node = dummy.next + while node != nil { + if node!.value == value { + return node + } + node = node!.next + } + + return nil + } + // 约定:链表的 index 从 1 开始 + func node(at index: Int) -> Node? { + var num = 1 + var node = dummy.next + while node != nil { + if num == index { + return node + } + node = node!.next + num += 1 + } + return nil + } + + func insertToHead(value: Element) { + let newNode = Node(value: value) + return insertToHead(node: newNode) + } + + func insertToHead(node: Node) { + node.next = dummy.next + dummy.next = node + } + + func insert(after node: Node, newValue: Element) { + let newNode = Node(value: newValue) + return insert(after: node, newNode: newNode) + } + + func insert(after node: Node, newNode: Node) { + newNode.next = node.next + node.next = newNode + } + + func insert(before node: Node, newValue: Element) { + let newNode = Node(value: newValue) + return insert(before: node, newNode: newNode) + } + + func insert(before node: Node, newNode: Node) { + var lastNode = dummy + var tmpNode = dummy.next + + while tmpNode != nil { + if tmpNode === node { + newNode.next = tmpNode + lastNode.next = newNode + break + } + lastNode = tmpNode! + tmpNode = tmpNode!.next + } + } + + func delete(node: Node) { + var lastNode = dummy + var tmpNode = dummy.next + + while tmpNode != nil { + if tmpNode === node { + lastNode.next = tmpNode!.next + break + } + + lastNode = tmpNode! + tmpNode = tmpNode!.next + } + } + /// 删除首个 value 符合要求的结点 + func delete(value: Element) { + var lastNode = dummy + var tmpNode = dummy.next + while tmpNode != nil { + if tmpNode!.value == value { + lastNode.next = tmpNode!.next + break + } + + lastNode = tmpNode! + tmpNode = tmpNode!.next + } + } +} diff --git a/swift/07_linkedlist/LinkedListAlgo.swift b/swift/07_linkedlist/LinkedListAlgo.swift new file mode 100644 index 0000000..979b8f6 --- /dev/null +++ b/swift/07_linkedlist/LinkedListAlgo.swift @@ -0,0 +1,111 @@ +// +// Created by Jiandan on 2018/10/13. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +/** + * 1) 单链表反转 + * 2) 链表中环的检测 + * 3) 两个有序的链表合并 + * 4) 删除链表倒数第n个结点 + * 5) 求链表的中间结点 + */ +import Foundation +/// 单链表反转 +func reverseSinglyLinkedList(head: Node) -> Node? { + var reverseHead: Node?, currentNode: Node?, prevNode: Node? + currentNode = head + while currentNode != nil { + let nextNode = currentNode!.next + if nextNode == nil { + reverseHead = currentNode + } + currentNode!.next = prevNode + prevNode = currentNode + currentNode = nextNode + } + return reverseHead +} +/// 检测环 +func hasCircle(head: Node) -> Bool { + var fast = head.next + var slow: Node? = head + while fast != nil { + if fast === slow { + return true + } + fast = fast!.next?.next + slow = slow!.next + } + return false +} +/// 两个有序的链表合并 +func mergeSortedLists(headA: Node?, headB: Node?) -> Node? { + guard let headA = headA else { + return headB + } + guard let headB = headB else { + return headA + } + + var head: Node?, tail: Node? + var nodeA: Node? = headA, nodeB: Node? = headB + if nodeA!.value! < nodeB!.value! { + head = nodeA + nodeA = nodeA!.next + } else { + head = nodeB + nodeB = nodeB!.next + } + tail = head + + while nodeA != nil, nodeB != nil { + if nodeA!.value! < nodeB!.value! { + tail!.next = nodeA + nodeA = nodeA!.next + } else { + tail!.next = nodeB + nodeB = nodeB!.next + } + tail = tail!.next + } + + if nodeA != nil { + tail?.next = nodeA + } else { + tail?.next = nodeB + } + + return head +} + +/// 删除倒数第n个结点 +func deleteNode(at lastNum: Int, in head: Node) { + var slow: Node? = head + var fast: Node? = head + var num = 1 + while fast != nil, num < lastNum { + fast = fast!.next + num += 1 + } + + var prevNode: Node? + while fast != nil { + prevNode = slow + fast = fast!.next + slow = slow!.next + } + prevNode?.next = slow?.next +} + +/// 求链表的中间结点 +func halfNode(in head: Node) -> Node? { + var slow: Node? = head + var fast: Node? = head + + while fast?.next != nil, fast?.next?.next != nil { + fast = fast!.next?.next + slow = slow!.next + } + return slow +} diff --git a/swift/08_stack/Browser.swift b/swift/08_stack/Browser.swift new file mode 100644 index 0000000..2b740d7 --- /dev/null +++ b/swift/08_stack/Browser.swift @@ -0,0 +1,27 @@ +// +// Created by Jiandan on 2018/10/12. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +struct Page { + /// 存储前进 url + private var forwardArray = [String]() + /// 存储后退 url + private var backArray = [String]() + + var currentURL: String? { return forwardArray.last } + + init(url: String) { + forwardArray.append(url) + } + /// 前进 + mutating func goForward(url: String) { + forwardArray.append(url) + } + /// 后退 + mutating func goBack() { + backArray.append(forwardArray.popLast()!) + } +} From e484fe890ebb7b01f01a8ce54bfa8464fad00816 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 14:29:17 +0800 Subject: [PATCH 055/141] [java][17_skiplist] typo fix [forwords -> forwards] --- java/17_skiplist/SkipList.java | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/java/17_skiplist/SkipList.java b/java/17_skiplist/SkipList.java index f6bcd70..8e62c20 100644 --- a/java/17_skiplist/SkipList.java +++ b/java/17_skiplist/SkipList.java @@ -21,13 +21,13 @@ public class SkipList { public Node find(int value) { Node p = head; for (int i = levelCount - 1; i >= 0; --i) { - while (p.forwords[i] != null && p.forwords[i].data < value) { - p = p.forwords[i]; + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; } } - if (p.forwords[0] != null && p.forwords[0].data == value) { - return p.forwords[0]; + if (p.forwards[0] != null && p.forwards[0].data == value) { + return p.forwards[0]; } else { return null; } @@ -45,15 +45,15 @@ public class SkipList { Node p = head; for (int i = level - 1; i >= 0; --i) { - while (p.forwords[i] != null && p.forwords[i].data < value) { - p = p.forwords[i]; + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; } update[i] = p; } for (int i = 0; i < level; ++i) { - newNode.forwords[i] = update[i].forwords[i]; - update[i].forwords[i] = newNode; + newNode.forwards[i] = update[i].forwards[i]; + update[i].forwards[i] = newNode; } if (levelCount < level) levelCount = level; @@ -63,16 +63,16 @@ public class SkipList { Node[] update = new Node[levelCount]; Node p = head; for (int i = levelCount - 1; i >= 0; --i) { - while (p.forwords[i] != null && p.forwords[i].data < value) { - p = p.forwords[i]; + while (p.forwards[i] != null && p.forwards[i].data < value) { + p = p.forwards[i]; } update[i] = p; } - if (p.forwords[0] != null && p.forwords[0].data == value) { + if (p.forwards[0] != null && p.forwards[0].data == value) { for (int i = levelCount - 1; i >= 0; --i) { - if (update[i].forwords[i] != null && update[i].forwords[i].data == value) { - update[i].forwords[i] = update[i].forwords[i].forwords[i]; + if (update[i].forwards[i] != null && update[i].forwards[i].data == value) { + update[i].forwards[i] = update[i].forwards[i].forwards[i]; } } } @@ -91,16 +91,16 @@ public class SkipList { public void printAll() { Node p = head; - while (p.forwords[0] != null) { - System.out.print(p.forwords[0] + " "); - p = p.forwords[0]; + while (p.forwards[0] != null) { + System.out.print(p.forwards[0] + " "); + p = p.forwards[0]; } System.out.println(); } public class Node { private int data = -1; - private Node forwords[] = new Node[MAX_LEVEL]; + private Node forwards[] = new Node[MAX_LEVEL]; private int maxLevel = 0; @Override From b344b9c173a7e2db05d9fcd5d6441e7ba76ef70d Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 14:57:13 +0800 Subject: [PATCH 056/141] [cpp][17_skiplist] abandon std::list. --- c-cpp/17_skiplist/skiplist.hpp | 83 ++++++++++++++-------------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist.hpp b/c-cpp/17_skiplist/skiplist.hpp index b48b8b9..b81946c 100644 --- a/c-cpp/17_skiplist/skiplist.hpp +++ b/c-cpp/17_skiplist/skiplist.hpp @@ -5,67 +5,50 @@ #ifndef SKIPLIST_SKIPLIST_HPP_ #define SKIPLIST_SKIPLIST_HPP_ -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -#include +#include +#include -template > -class skiplist : public std::list { +template +class skiplist { public: - using container_type = std::list; - using value_type = typename container_type::value_type; - using allocator_type = typename container_type::allocator_type; - using size_type = typename container_type::size_type; - using difference_type = typename container_type::difference_type; - using reference = typename container_type::reference; - using const_reference = typename container_type::const_reference; - using pointer = typename container_type::pointer; - using const_pointer = typename container_type::const_pointer; - using iterator = typename container_type::iterator; - using const_iterator = typename container_type::const_iterator; - using reverse_iterator = typename container_type::reverse_iterator; - using const_reverse_iterator = typename container_type::const_reverse_iterator; + using value_type = Value; + using hash_type = std::hash; + using key_type = std::result_of_t>; + using size_type = size_t; private: - static const size_type MAX_LEVEL = 16; - mutable size_type level_count = 1; - const unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count(); - std::default_random_engine generator = std::default_random_engine(seed); - std::binomial_distribution distribution = std::binomial_distribution(MAX_LEVEL, 0.5); + struct InternalNode { + value_type value; + const key_type key; + std::vector forwards; // pointers to successor nodes - private: - template - struct IndexNode { - IndexNode(const Value& data_, Iter down_) : data(data_), down(down_) {} - const Value data; - const Iter down; + InternalNode(value_type&& v, const size_type lv) + : value(v), key(Hash()(value)), forwards(lv, nullptr) {} }; + using node_type = InternalNode; + + private: + const size_type MAX_LEVEL = 16; + const double PROBABILITY = 0.5; + mutable size_type level_count = 1; + const unsigned int seed = + std::chrono::system_clock::now().time_since_epoch().count(); + std::default_random_engine generator = std::default_random_engine(seed); + std::binomial_distribution distribution = + std::binomial_distribution(MAX_LEVEL, PROBABILITY); public: skiplist() : container_type() {} - explicit skiplist(const allocator_type& alloc) : container_type(alloc) {} - skiplist( size_type count, - const_reference value, - const allocator_type& alloc = allocator_type()) : - container_type(count, value, alloc) {} - explicit skiplist(size_type count, const allocator_type& alloc = allocator_type()) : - container_type(count, alloc) {} - template - skiplist(InputIt first, InputIt last, const allocator_type& alloc = allocator_type()) : - container_type(first, last, alloc) {} + skiplist(size_type count, const_reference value); skiplist(const skiplist& other); skiplist(const skiplist& other, const allocator_type& alloc); skiplist(skiplist&& other); skiplist(skiplist&& other, const allocator_type& alloc); - skiplist(std::initializer_list init, - const allocator_type& alloc = allocator_type()) : - container_type(std::forward>(init), alloc) {} + skiplist(std::initializer_list init); ~skiplist() {} public: @@ -76,9 +59,9 @@ class skiplist : public std::list { inline size_type get_random_level() { return distribution(generator); } public: - iterator find(const value_type& target); - iterator insert(const value_type& value); - iterator erase(const value_type& value); + const value_type& find(const value_type& target); + void insert(const value_type& value); + void erase(const value_type& value); }; #endif // SKIPLIST_SKIPLIST_HPP_ From ca495f4ffe80b406d9097ec853b487ebe17c2e7b Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 15:55:12 +0800 Subject: [PATCH 057/141] [cpp][17_skiplist] almost done. --- c-cpp/17_skiplist/skiplist.hpp | 133 +++++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 21 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist.hpp b/c-cpp/17_skiplist/skiplist.hpp index b81946c..78b3e17 100644 --- a/c-cpp/17_skiplist/skiplist.hpp +++ b/c-cpp/17_skiplist/skiplist.hpp @@ -11,6 +11,7 @@ #include #include #include +#include template class skiplist { @@ -26,44 +27,134 @@ class skiplist { const key_type key; std::vector forwards; // pointers to successor nodes - InternalNode(value_type&& v, const size_type lv) - : value(v), key(Hash()(value)), forwards(lv, nullptr) {} + InternalNode(const key_type& k, const size_type lv) + : value(), key(k), forwards(lv, nullptr) {} + InternalNode(const value_type& v, const size_type lv) + : value(v), key(hash_type()(value)), forwards(lv, nullptr) {} }; using node_type = InternalNode; private: const size_type MAX_LEVEL = 16; const double PROBABILITY = 0.5; - mutable size_type level_count = 1; const unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator = std::default_random_engine(seed); std::binomial_distribution distribution = - std::binomial_distribution(MAX_LEVEL, PROBABILITY); + std::binomial_distribution(MAX_LEVEL - 1, PROBABILITY); + node_type* head = nullptr; + node_type* nil = nullptr; public: - skiplist() : container_type() {} - skiplist(size_type count, const_reference value); - skiplist(const skiplist& other); - skiplist(const skiplist& other, const allocator_type& alloc); - skiplist(skiplist&& other); - skiplist(skiplist&& other, const allocator_type& alloc); - skiplist(std::initializer_list init); - ~skiplist() {} - - public: - skiplist& operator=(const skiplist& other); - skiplist& operator=(skiplist&& other); + skiplist() { + key_type head_key = std::numeric_limits::min(); + key_type nil_key = std::numeric_limits::max(); + head = new node_type(head_key, MAX_LEVEL); + nil = new node_type(nilkey, MAX_LEVEL); + std::fill(head->forwards.begin(), head->forwards.end(), nil); + } + skiplist(std::initializer_list init) : skiplist() { + for (const value_type& v : init) { + insert(v); + } + } + skiplist(const skiplist& other) = delete; + skiplist(skiplist&& other) : + MAX_LEVEL(std::move(other.MAX_LEVEL)), + PROBABILITY(std::move(other.PROBABILITY)), + seed(std::move(other.seed)), + generator(std::move(other.generator)), + distribution(std::move(other.distribution)), + head(other.head), + nil(other.nil) { + other.head = nullptr; + other.nil = nullptr; + } + ~skiplist() { + node_type* node = head; + while (nullptr != node->forwards[0]) { + node_type* tmp = node; + node = node->forwards[0]; + delete tmp; + } + delete node; + } + skiplist& operator=(const skiplist& other) = delete; + skiplist& operator=(skiplist&& other) = delete; private: - inline size_type get_random_level() { return distribution(generator); } + inline size_type get_random_level() const { + return distribution(generator); + } + static size_type get_node_level(const node_type* node) { + return node->forwards.size(); + } + static node_type* make_node(value_type&& v, const size_type lv) const { + return new node_type(v, lv); + } + /** + * @brief returns a pointer to the first node such that + * node->key == hash_type()(v) and node->value == v. + */ + node_type* get_first_equal(const value_type& v) const { + const key_type target = hash_type()(v); + node_type* x = head; + for (size_type i = get_node_level(head) - 1; i > 0; --i) { + while (x->forwards[i]->key < target or + x->forwards[i]->key == target and x->forwards[i]->value != v) { + x = x->forwards[i]; + } + } + return x->forwards[0]; + } + /** + * @brief returns a collection of nodes. + * returns[i] is the pointer to the last node at level i + 1 + * such that returns[i]->key < hash_type()(v) or + * returns[i]->key == hash_type()(v) but returns[i]->value != v. + */ + std::vector get_predecessors(const value_type& v) const { + const key_type target = hash_type()(v); + std::vector results(get_node_level(head), nullptr); + node_type* x = head; + for (size_type i = get_node_level(head) - 1; i > 0; --i) { + while (x->forwards[i]->key < target or + x->forwards[i]->key == target and x->forwards[i]->value != v) { + x = x->forwards[i]; + } + results[i] = x; + } + return results; + } public: - const value_type& find(const value_type& target); - void insert(const value_type& value); - void erase(const value_type& value); + const value_type& find(const value_type& target) { + node_type* x = get_first_equal(target); + if (nullptr != x and nil != x and x->value == target) { + return x->value; + } + } + void insert(const value_type& value) { + std::vector preds = get_predecessors(value); + const size_type new_node_lv = get_random_level(); + node_type* new_node = make_node(value, new_node_lv); + for (size_type i = 0; i != new_node_lv; ++i) { + new_node->forwards[i] = preds[i]->forwards[i]; + preds[i]->forwards[i] = new_node; + } + } + void erase(const value_type& value) { + std::vector preds = get_predecessors(value); + + node_type node = preds[0]->forwards[0]; + if (node == nil or node->value != value) { return; } + + for (size_type i = 0; i != get_node_level(node); ++i) { + preds[i]->forward[i] = node->forward[i]; + } + delete node; + } }; #endif // SKIPLIST_SKIPLIST_HPP_ - From 37b619725dbb5e674bfc4dae32a96b0a41ee7d87 Mon Sep 17 00:00:00 2001 From: yangchuz Date: Tue, 30 Oct 2018 16:25:08 +0800 Subject: [PATCH 058/141] Binary search non-recursive implementation --- scala/15_bsearch/BSearch.scala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 scala/15_bsearch/BSearch.scala diff --git a/scala/15_bsearch/BSearch.scala b/scala/15_bsearch/BSearch.scala new file mode 100644 index 0000000..0c8d0b4 --- /dev/null +++ b/scala/15_bsearch/BSearch.scala @@ -0,0 +1,18 @@ +object BSearch { + def search(nums: Array[Int], target: Int): Int = { + var low = 0 + var high = nums.length - 1 + while(low <= high){ + val mid = low + ((high - low) >> 2) + if(nums(mid) > target){ + high = mid - 1 + } else if (nums(mid) < target){ + low = mid + 1 + } else { + return mid + } + } + + return -1 + } +} From 44a2376207e4dfc79e8c55e029b1048cbddaa571 Mon Sep 17 00:00:00 2001 From: yangchuz Date: Tue, 30 Oct 2018 16:27:06 +0800 Subject: [PATCH 059/141] Binary search recursive implementation --- scala/15_bsearch/BSearchRecursive.scala | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 scala/15_bsearch/BSearchRecursive.scala diff --git a/scala/15_bsearch/BSearchRecursive.scala b/scala/15_bsearch/BSearchRecursive.scala new file mode 100644 index 0000000..b14a706 --- /dev/null +++ b/scala/15_bsearch/BSearchRecursive.scala @@ -0,0 +1,20 @@ +object BSearchRecursive { + def search(nums: Array[Int], target: Int): Int = { + return searchInternal(nums, target, 0, nums.length - 1) + } + + def searchInternal(nums:Array[Int], target: Int, low: Int, high: Int): Int = { + if(low <= high){ + val mid = low + ((high - low) >> 2) + if(nums(mid) > target){ + searchInternal(nums, target, low, mid - 1) + } else if (nums(mid) < target){ + searchInternal(nums, target, mid + 1, high) + } else { + return mid + } + }else{ + return -1 + } + } +} From 72f8b26928ea9d8f7e8b29ba484694a97753faf6 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 17:42:36 +0800 Subject: [PATCH 060/141] [cpp][17_skiplist] done, with tests. --- c-cpp/17_skiplist/skiplist.hpp | 56 ++++++++++++++++++++-------- c-cpp/17_skiplist/skiplist_test.cc | 60 +++++++++++++++++++++++++++--- 2 files changed, 95 insertions(+), 21 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist.hpp b/c-cpp/17_skiplist/skiplist.hpp index 78b3e17..9cbfb45 100644 --- a/c-cpp/17_skiplist/skiplist.hpp +++ b/c-cpp/17_skiplist/skiplist.hpp @@ -12,13 +12,14 @@ #include #include #include +#include template class skiplist { public: using value_type = Value; using hash_type = std::hash; - using key_type = std::result_of_t>; + using key_type = typename hash_type::result_type; using size_type = size_t; private: @@ -39,18 +40,21 @@ class skiplist { const double PROBABILITY = 0.5; const unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count(); + mutable std::default_random_engine generator = std::default_random_engine(seed); + mutable std::binomial_distribution distribution = std::binomial_distribution(MAX_LEVEL - 1, PROBABILITY); node_type* head = nullptr; node_type* nil = nullptr; + static const value_type default_value; public: skiplist() { key_type head_key = std::numeric_limits::min(); key_type nil_key = std::numeric_limits::max(); head = new node_type(head_key, MAX_LEVEL); - nil = new node_type(nilkey, MAX_LEVEL); + nil = new node_type(nil_key, MAX_LEVEL); std::fill(head->forwards.begin(), head->forwards.end(), nil); } skiplist(std::initializer_list init) : skiplist() { @@ -72,7 +76,7 @@ class skiplist { } ~skiplist() { node_type* node = head; - while (nullptr != node->forwards[0]) { + while (nullptr != node and nullptr != node->forwards[0]) { node_type* tmp = node; node = node->forwards[0]; delete tmp; @@ -89,7 +93,7 @@ class skiplist { static size_type get_node_level(const node_type* node) { return node->forwards.size(); } - static node_type* make_node(value_type&& v, const size_type lv) const { + static node_type* make_node(const value_type& v, const size_type lv) { return new node_type(v, lv); } /** @@ -99,10 +103,10 @@ class skiplist { node_type* get_first_equal(const value_type& v) const { const key_type target = hash_type()(v); node_type* x = head; - for (size_type i = get_node_level(head) - 1; i > 0; --i) { - while (x->forwards[i]->key < target or - x->forwards[i]->key == target and x->forwards[i]->value != v) { - x = x->forwards[i]; + for (size_type i = get_node_level(head); i > 0; --i) { + while (x->forwards[i - 1]->key < target or + x->forwards[i - 1]->key == target and x->forwards[i - 1]->value != v) { + x = x->forwards[i - 1]; } } return x->forwards[0]; @@ -117,12 +121,12 @@ class skiplist { const key_type target = hash_type()(v); std::vector results(get_node_level(head), nullptr); node_type* x = head; - for (size_type i = get_node_level(head) - 1; i > 0; --i) { - while (x->forwards[i]->key < target or - x->forwards[i]->key == target and x->forwards[i]->value != v) { - x = x->forwards[i]; + for (size_type i = get_node_level(head); i > 0; --i) { + while (x->forwards[i - 1]->key < target or + x->forwards[i - 1]->key == target and x->forwards[i - 1]->value != v) { + x = x->forwards[i - 1]; } - results[i] = x; + results[i - 1] = x; } return results; } @@ -132,6 +136,8 @@ class skiplist { node_type* x = get_first_equal(target); if (nullptr != x and nil != x and x->value == target) { return x->value; + } else { + return default_value; } } void insert(const value_type& value) { @@ -146,15 +152,35 @@ class skiplist { void erase(const value_type& value) { std::vector preds = get_predecessors(value); - node_type node = preds[0]->forwards[0]; + node_type* node = preds[0]->forwards[0]; if (node == nil or node->value != value) { return; } for (size_type i = 0; i != get_node_level(node); ++i) { - preds[i]->forward[i] = node->forward[i]; + preds[i]->forwards[i] = node->forwards[i]; } delete node; } + void print(std::ostream& os) const { + node_type* list = head->forwards[0]; + os << "{"; + + while (list != nil) { + os << "key: " << list->key << " value: " << list->value + << " level: " << get_node_level(list); + + list = list->forwards[0]; + + if (list != nil) os << " : "; + + os << "\n"; + } + os << "}\n"; + } }; +template +const typename skiplist::value_type skiplist::default_value = + typename skiplist::value_type(); + #endif // SKIPLIST_SKIPLIST_HPP_ diff --git a/c-cpp/17_skiplist/skiplist_test.cc b/c-cpp/17_skiplist/skiplist_test.cc index fa41266..d72e940 100644 --- a/c-cpp/17_skiplist/skiplist_test.cc +++ b/c-cpp/17_skiplist/skiplist_test.cc @@ -1,15 +1,63 @@ #include +#include + #include "skiplist.hpp" int main() { - skiplist test{1, 2, 3, 4}; - for (auto i : test) { - std::cout << i << " "; - } + // 1. Initialize a skip list for test + // * default constructor + // * constructor with initializer list + // * insert + skiplist ss{"1", "2", "3", "4", "5"}; + + // 1a. show + // * print + ss.print(std::cout); std::cout << std::endl; - for (size_t i = 0; i != 20; ++i) - std::cout << test.get_random_level() << std::endl; + // 2. move construction + // * move constructor + skiplist s(std::move(ss)); + + // 2a. show + // * print + s.print(std::cout); + std::cout << std::endl; + + // 3.a find something doesn't exist. + // * find + auto f = s.find("0"); + if (!f.empty()) { + std::cout << "Node found!\nvalue: " << f << '\n'; + } else { + std::cout << "Node NOT found!\n"; + } + + // 3.b find something does exist. + // * find + auto ff = s.find("1"); + if (!ff.empty()) { + std::cout << "Node found!\tvalue: " << ff << '\n'; + } else { + std::cout << "Node NOT found!\n"; + } + + // 4. insert() - reassign + s.insert("TEST"); + + // 4a. print() + s.print(std::cout); + std::cout << std::endl; + + // 5. erase() + s.erase("TEST"); + + // 5a. print(); + s.print(std::cout); + std::cout << std::endl; + + std::cout << "\nDone!\n"; return 0; + // 6. destructor } From 2038b3269e6bd5867e071a34704ef2e9ce2a42e6 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 18:26:36 +0800 Subject: [PATCH 061/141] [cpp][17_sliplist] add copyright information in skiplist_test.cc --- c-cpp/17_skiplist/skiplist_test.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/c-cpp/17_skiplist/skiplist_test.cc b/c-cpp/17_skiplist/skiplist_test.cc index d72e940..ced124e 100644 --- a/c-cpp/17_skiplist/skiplist_test.cc +++ b/c-cpp/17_skiplist/skiplist_test.cc @@ -1,3 +1,7 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/30. + */ + #include #include From 2fbe612975dcf86399d9178cfcca7aa4c42749a2 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 18:30:29 +0800 Subject: [PATCH 062/141] [cpp][17_skiplist] based on std::list, init. --- c-cpp/17_skiplist/skiplist_tr.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 c-cpp/17_skiplist/skiplist_tr.hpp diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp new file mode 100644 index 0000000..a135614 --- /dev/null +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -0,0 +1,17 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/30. + */ + +#ifndef SKIPLIST_SKIPLIST_TR_HPP_ +#define SKIPLIST_SKIPLIST_TR_HPP_ + +#include + +template > +class skiplist { + +}; + +#endif // SKIPLIST_SKIPLIST_TR_HPP_ + From c8a91eec595503f4c4e45be78a5011188a29d50f Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Tue, 30 Oct 2018 18:52:29 +0800 Subject: [PATCH 063/141] [cpp][17_skiplist] based on std::list, typedef(s) and impl of InternalNode. --- c-cpp/17_skiplist/skiplist_tr.hpp | 29 +++++++++++++++++++++++++-- c-cpp/17_skiplist/skiplist_tr_test.cc | 13 ++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 c-cpp/17_skiplist/skiplist_tr_test.cc diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index a135614..027f5db 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -5,12 +5,37 @@ #ifndef SKIPLIST_SKIPLIST_TR_HPP_ #define SKIPLIST_SKIPLIST_TR_HPP_ +#include +#include +#include #include +#include + +namespace skiplist_detail { +template +struct InternalNode { + const Key key; + std::multiset values; + using iterator = typename std::list::iterator; + std::vector forwards; +}; +} // namespace skiplist_detail template > + typename Compare = std::less, + typename Hash = std::hash> class skiplist { - + public: + using value_type = Value; + using compare = Compare; + using size_type = size_t; + using hasher = Hash; + using hash_type = typename Hash::result_type; + using node_type = skiplist_detail::InternalNode; + using container = std::list; + using iterator = typename container::iterator; + static_assert(std::is_same::value, + "STATIC ASSERT FAILED! iterator type differs."); }; #endif // SKIPLIST_SKIPLIST_TR_HPP_ diff --git a/c-cpp/17_skiplist/skiplist_tr_test.cc b/c-cpp/17_skiplist/skiplist_tr_test.cc new file mode 100644 index 0000000..511829e --- /dev/null +++ b/c-cpp/17_skiplist/skiplist_tr_test.cc @@ -0,0 +1,13 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/30. + */ + +#include + +#include "skiplist_tr.hpp" + +int main() { + std::cout << "hello world" << std::endl; + return 0; +} + From fc96c46b5c6db5e7ac517b6188e921d181e9f247 Mon Sep 17 00:00:00 2001 From: ykw <729473622@qq.com> Date: Wed, 31 Oct 2018 09:24:07 +0800 Subject: [PATCH 064/141] Quick sort in php --- php/12_sort/quicksort.php | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 php/12_sort/quicksort.php diff --git a/php/12_sort/quicksort.php b/php/12_sort/quicksort.php new file mode 100644 index 0000000..95a60ca --- /dev/null +++ b/php/12_sort/quicksort.php @@ -0,0 +1,47 @@ += $r) return; + + $q = partition($a, $l, $r); + quickSortInternally($a, $l, $q-1); + quickSortInternally($a, $q+1, $r); +} + +function partition(&$a, $l, $r): int +{ + $pivot = $a[$r]; + $i = $l; + + for ($j = $l; $j < $r; ++$j) { + if ($a[$j] < $pivot) { + [$a[$j], $a[$i]] = [$a[$i], $a[$j]]; + ++$i; + } + } + + [$a[$r], $a[$i]] = [$a[$i], $a[$r]]; + + return $i; +} + +$a1 = [1,4,6,2,3,5,4]; +$a2 = [2, 2, 2, 2]; +$a3 = [4, 3, 2, 1]; +$a4 = [5, -1, 9, 3, 7, 8, 3, -2, 9]; +quickSort($a1); +print_r($a1); +quickSort($a2); +print_r($a2); +quickSort($a3); +print_r($a3); +quickSort($a4); +print_r($a4); \ No newline at end of file From de5fd9f60c54f510957068daf1948fe9f8f4fead Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 31 Oct 2018 10:36:24 +0800 Subject: [PATCH 065/141] [cpp][17_skiplist] impl of random level, and its unit test. --- c-cpp/17_skiplist/skiplist_tr.hpp | 25 +++++++++++++++++++++++-- c-cpp/17_skiplist/skiplist_tr_test.cc | 13 ++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index 027f5db..4c7c71c 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -10,15 +10,28 @@ #include #include #include +#include namespace skiplist_detail { template struct InternalNode { - const Key key; - std::multiset values; using iterator = typename std::list::iterator; + const Key key; + std::multiset values; std::vector forwards; }; + +template +class random_level { + private: + mutable std::random_device rd; + mutable std::mt19937 gen = std::mt19937(rd()); + mutable std::binomial_distribution dist; + + public: + random_level(IntType max_level, double prob) : dist(max_level - 1, prob) {} + inline IntType operator()() const { return dist(gen); } +}; } // namespace skiplist_detail template ::value, "STATIC ASSERT FAILED! iterator type differs."); + + private: + size_type max_lv_ = 16; + double prob_ = 0.5; + mutable random_level rl_; + + public: + skiplist() : rl_(max_lv_, prob_) {} }; #endif // SKIPLIST_SKIPLIST_TR_HPP_ diff --git a/c-cpp/17_skiplist/skiplist_tr_test.cc b/c-cpp/17_skiplist/skiplist_tr_test.cc index 511829e..e654fc7 100644 --- a/c-cpp/17_skiplist/skiplist_tr_test.cc +++ b/c-cpp/17_skiplist/skiplist_tr_test.cc @@ -3,11 +3,22 @@ */ #include +#include +#include #include "skiplist_tr.hpp" int main() { - std::cout << "hello world" << std::endl; + // 1. UT for skiplist_detail::random_level + skiplist_detail::random_level rl(5, 0.5); + std::map hist; + for (size_t i = 0; i != 10000; ++i) { + ++hist[rl()]; + } + for (auto p : hist) { + std::cout << p.first << ' ' << std::string(p.second / 100, '*') << '\n'; + } + return 0; } From 84602b7fd224673ea693f5a1ceb728f260c2c250 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Wed, 31 Oct 2018 11:06:01 +0800 Subject: [PATCH 066/141] =?UTF-8?q?=E4=BA=8C=E5=88=86=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E6=B1=82=E5=B9=B3=E6=96=B9=E6=A0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c-cpp/15_bsearch/bsearch_c/sqrt.c | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 c-cpp/15_bsearch/bsearch_c/sqrt.c diff --git a/c-cpp/15_bsearch/bsearch_c/sqrt.c b/c-cpp/15_bsearch/bsearch_c/sqrt.c new file mode 100644 index 0000000..7c7c3d4 --- /dev/null +++ b/c-cpp/15_bsearch/bsearch_c/sqrt.c @@ -0,0 +1,53 @@ +/************************************************************************* + > File Name: sqrt.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-31 + > Desc: + ************************************************************************/ +#include +#include +#include +#include + + +/*求解精度设置*/ +#define E 0.000001 +double mybsearch(double num) +{ + double start = 1.0; + double end = num; + double mid = 0.0; + while(1) + { + mid = (start + end)/2; + if(((mid*mid - num) <= E) && ((mid*mid - num) >= -E)) + { + return mid; + } + + if ((mid*mid - num) > E) + { + end = mid; + } + else + { + start = mid; + } + } + + return 0; +} + + +int main() +{ + double num = 0.0; + + /*这里需要注意:double的输入方式*/ + scanf("%lf",&num); + printf("\r\n num %lf的平方根是%lf",num,mybsearch(num)); + + return 0; +} + From f298cda3dc50c276fea44c691da5fec0ce3f44c4 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 31 Oct 2018 11:27:28 +0800 Subject: [PATCH 067/141] [cpp][17_skiplist] impl of constructors and destructor, and their related functions. --- c-cpp/17_skiplist/skiplist_tr.hpp | 81 +++++++++++++++++++++++++-- c-cpp/17_skiplist/skiplist_tr_test.cc | 4 ++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index 4c7c71c..bed49e8 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -5,12 +5,21 @@ #ifndef SKIPLIST_SKIPLIST_TR_HPP_ #define SKIPLIST_SKIPLIST_TR_HPP_ +#ifdef LIAM_UT_DEBUG_ +#include +#include +#endif + #include #include #include #include #include #include +#include +#include +#include +#include namespace skiplist_detail { template @@ -19,6 +28,9 @@ struct InternalNode { const Key key; std::multiset values; std::vector forwards; + + InternalNode() = delete; + explicit InternalNode(const Key& k) : key(k) {} }; template @@ -51,12 +63,73 @@ class skiplist { "STATIC ASSERT FAILED! iterator type differs."); private: - size_type max_lv_ = 16; - double prob_ = 0.5; - mutable random_level rl_; + size_type max_lv_ = 16; + double prob_ = 0.5; + mutable skiplist_detail::random_level rl_; + container cont_; public: - skiplist() : rl_(max_lv_, prob_) {} + skiplist() : rl_(max_lv_, prob_) { + init_internally(); + } + explicit skiplist(const size_type max_lv, const double prob = 0.5) + : max_lv_(max_lv), prob_(prob), rl_(max_lv_, prob_) { + init_internally(); + } + skiplist(skiplist&& other) = default; + skiplist& operator=(skiplist&& other) = default; + ~skiplist() = default; + template + skiplist(InputIt first, InputIt last) : skiplist() { + using value_type_in_iter = typename std::iterator_traits::value_type; + static_assert(std::is_same::value, + "STATIC ASSERT FAILED! Value in InputIt should be the same to value_type."); + for (InputIt i = first; i != last; ++i) { + insert(*i); + } + } + skiplist(std::initializer_list init) : skiplist(init.begin(), init.end()) {} + + private: // noncopyable + skiplist(const skiplist&) = delete; + skiplist& operator=(const skiplist&) = delete; + + private: + void init_internally() { + const hash_type tail_key = std::numeric_limits::max(); + node_type tail(tail_key); + tail.forwards.resize(max_lv_); + std::fill(tail.forwards.begin(), tail.forwards.end(), cont_.end()); + cont_.insert(cont_.begin(), std::move(tail)); + + const hash_type head_key = std::numeric_limits::min(); + node_type head(head_key); + head.forwards.resize(max_lv_); + cont_.insert(cont_.begin(), std::move(head)); + std::fill(cont_.begin()->forwards.begin(), cont_.begin()->forwards.end(), + std::next(cont_.begin())); + +#ifdef LIAM_UT_DEBUG_ + assert(cont_.begin()->key == head_key); + for (auto it : cont_.begin()->forwards) { + assert(it->key == tail_key); + } + for (auto it : std::next(cont_.begin())->forwards) { + assert(it == cont_.end()); + } + std::cerr << "all assert in init() success!\n"; +#endif + + return; + } + + public: + size_type size() const { + return cont_.size() - 2; + } + bool empty() const { + return size() == 0; + } }; #endif // SKIPLIST_SKIPLIST_TR_HPP_ diff --git a/c-cpp/17_skiplist/skiplist_tr_test.cc b/c-cpp/17_skiplist/skiplist_tr_test.cc index e654fc7..257fd98 100644 --- a/c-cpp/17_skiplist/skiplist_tr_test.cc +++ b/c-cpp/17_skiplist/skiplist_tr_test.cc @@ -1,6 +1,7 @@ /** * Created by Liam Huang (Liam0205) on 2018/10/30. */ +#include #include #include @@ -19,6 +20,9 @@ int main() { std::cout << p.first << ' ' << std::string(p.second / 100, '*') << '\n'; } + // 2. UT for skiplist(), init(), size(), empty() + skiplist sl_default; + assert(sl_default.empty()); return 0; } From 804d6f6bf674de1f2624fb051f0686c79ff70622 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Wed, 31 Oct 2018 12:10:00 +0800 Subject: [PATCH 068/141] [cpp][17_skiplist] impl of find and find_helper, and their unit test. --- c-cpp/17_skiplist/skiplist_tr.hpp | 63 ++++++++++++++++++++++----- c-cpp/17_skiplist/skiplist_tr_test.cc | 5 +++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index bed49e8..94ed69b 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -47,18 +47,18 @@ class random_level { } // namespace skiplist_detail template , typename Hash = std::hash> class skiplist { public: - using value_type = Value; - using compare = Compare; - using size_type = size_t; - using hasher = Hash; - using hash_type = typename Hash::result_type; - using node_type = skiplist_detail::InternalNode; - using container = std::list; - using iterator = typename container::iterator; + using value_type = Value; + using size_type = size_t; + using hasher = Hash; + using hash_type = typename Hash::result_type; + using compare = std::less; + using node_type = skiplist_detail::InternalNode; + using container = std::list; + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; static_assert(std::is_same::value, "STATIC ASSERT FAILED! iterator type differs."); @@ -117,11 +117,29 @@ class skiplist { for (auto it : std::next(cont_.begin())->forwards) { assert(it == cont_.end()); } - std::cerr << "all assert in init() success!\n"; + std::cerr << "UT_DEBUG: all assert in init() success!\n"; #endif return; } + /** + * @brief return a const_iterator points to the last element + * such that its hash_key <= target_hash_key + */ + const_iterator find_helper(const hash_type& key) const { + const_iterator iter = cont_.begin(); + for (size_type i = 0; i != max_lv_; ++i) { + size_type focus = max_lv_ - 1 - i; + // invariant: iter->key <= key + for (const_iterator forward = iter->forwards[focus]; + forward != cont_.end() and not compare()(forward->key, key); + forward = iter->forwards[focus]) { + iter = forward; + } + // result: iter->key <= key and iter->forwards[focus]->key > key + } + return iter; + } public: size_type size() const { @@ -130,6 +148,31 @@ class skiplist { bool empty() const { return size() == 0; } + iterator begin() { + return cont_.begin(); + } + const_iterator begin() const { + return cont_.cbegin(); + } + const_iterator cbegin() const { + return cont_.cbegin(); + } + iterator end() { + return cont_.end(); + } + const_iterator end() const { + return cont_.cend(); + } + const_iterator cend() const { + return cont_.cend(); + } + + public: + const_iterator find(const value_type& target) const { + const hash_type key = hasher()(target); + const_iterator iter = find_helper(key); + return (iter->key == key) ? iter : cont_.end(); + } }; #endif // SKIPLIST_SKIPLIST_TR_HPP_ diff --git a/c-cpp/17_skiplist/skiplist_tr_test.cc b/c-cpp/17_skiplist/skiplist_tr_test.cc index 257fd98..923022c 100644 --- a/c-cpp/17_skiplist/skiplist_tr_test.cc +++ b/c-cpp/17_skiplist/skiplist_tr_test.cc @@ -23,6 +23,11 @@ int main() { // 2. UT for skiplist(), init(), size(), empty() skiplist sl_default; assert(sl_default.empty()); + + // 3. UT for find() [nonexist element] + auto search = sl_default.find("nonexist"); + assert(search == sl_default.cend()); + assert(search == sl_default.end()); return 0; } From e713d63e3450985548a365204672ef676c8156b8 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Wed, 31 Oct 2018 12:39:35 +0800 Subject: [PATCH 069/141] =?UTF-8?q?add=20by=20jinshaohui=20for=20=E4=BA=8C?= =?UTF-8?q?=E5=88=86=E6=9F=A5=E6=89=BE=E5=8F=98=E5=BD=A2=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c-cpp/16_bsearch/bsearch.c | 190 +++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 c-cpp/16_bsearch/bsearch.c diff --git a/c-cpp/16_bsearch/bsearch.c b/c-cpp/16_bsearch/bsearch.c new file mode 100644 index 0000000..17e06fd --- /dev/null +++ b/c-cpp/16_bsearch/bsearch.c @@ -0,0 +1,190 @@ +/************************************************************************* + > File Name: bsearch.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-21 + > Desc: + ************************************************************************/ +#include +#include +#include + +/*二分查找算法的变形问题 + *1、查找第一个等于给定数值的元素 + *2、查找最后一个等于给定数值的元素 + *3、查找第一个大于等于给定数值的元素 + *4、查找第一个小于等于给定数值的元素 + * */ + + + /*1、查找第一个等于给定数值的元素*/ +int mybsearch_1(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] < value) + { + left = mid + 1; + } + else if (a[mid] > value) + { + right = mid - 1; + } + else + { + if ((mid == 0) || (a[mid - 1] != value)) + { + return mid; + } + else + { + right = mid - 1; + } + } + } + + return -1; +} + + /*2、查找最后一个等于给定数值的元素*/ +int mybsearch_2(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] < value) + { + left = mid + 1; + } + else if (a[mid] > value) + { + right = mid - 1; + } + else + { + if ((mid == (size - 1)) || (a[mid + 1] != value)) + { + return mid; + } + else + { + left = mid + 1; + } + } + } + + return -1; +} + /*3、查找第一个大于等于给定数值的元素*/ +int mybsearch_3(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] < value) + { + left = mid + 1; + } + else + { + /*a[mid] >= value 当mid==0 或者a[mid-1] > value 说明是第一个大于等于value*/ + if ((mid == 0) || (a[mid - 1] < value)) + { + return mid; + } + else + { + right = mid - 1; + } + } + } + + return -1; +} + + /*4、查找第一个小于等于给定数值的元素*/ +int mybsearch_4(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] > value) + { + right = mid - 1; + } + else + { + /*a[mid] <= value 时,当前mid == size -1 数组中最大的数值; + * 或者a[mid + 1] 大于vlaue,就是mid就第一个小于等于value*/ + if ((mid == (size - 1)) || (a[mid + 1] > value)) + { + return mid; + } + else + { + left = mid + 1; + } + } + } + + return -1; +} +int main() +{ + int a[10] = {5,6,6,9,10,11,11,22,33,33}; + int data = 0; + int i = 0; + int res =0; + + printf("\r\n"); + for(i = 0; i < 10 ; i++) + { + printf("%d ",a[i]); + } + printf("\r\n"); + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_1(a,10,data); + printf("第一个等于data[%d],下标是%d",data,res); + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_2(a,10,data); + printf("最后一个等于data[%d],下标是%d",data,res); + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_2(a,10,data); + printf("第一个大于等于data[%d],下标是%d",data,res); + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_2(a,10,data); + printf("第一个小等于data[%d],下标是%d",data,res); + return; +} From b72c72308feca3c37c8e0bb882f3c329ed0c9cba Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Thu, 1 Nov 2018 06:54:17 +0800 Subject: [PATCH 070/141] add by jinshaohui for skip list by c --- c-cpp/17_skiplist/skiplist_c/skiplist.c | 345 ++++++++++++++++++++++++ c-cpp/17_skiplist/skiplist_c/skiplist.h | 33 +++ 2 files changed, 378 insertions(+) create mode 100644 c-cpp/17_skiplist/skiplist_c/skiplist.c create mode 100644 c-cpp/17_skiplist/skiplist_c/skiplist.h diff --git a/c-cpp/17_skiplist/skiplist_c/skiplist.c b/c-cpp/17_skiplist/skiplist_c/skiplist.c new file mode 100644 index 0000000..3a171e7 --- /dev/null +++ b/c-cpp/17_skiplist/skiplist_c/skiplist.c @@ -0,0 +1,345 @@ +/************************************************************************* + > File Name: skiplist.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-31 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include"./skiplist.h" + + +/*创建node节点*/ +node* skip_list_create_node(int level,int key,int value) +{ + node * tmp = NULL; + + tmp =(node *)malloc(sizeof(node) + level*sizeof(node *)); + assert(tmp != NULL); + + memset(tmp,0,sizeof(node) + level*sizeof(node*)); + tmp->key = key; + tmp->value = value; + tmp->max_level = level; + + return tmp; +} + +/*创建跳表的表头,max_level层数*/ +skiplist * skip_list_create(int max_level) +{ + int i = 0; + skiplist * list = NULL; + + list = (skiplist *)malloc (sizeof(skiplist)); + assert(list != NULL); + + list->level = 1; + list->count = 0; + + list->head = skip_list_create_node(max_level,0,0); + if(list->head == NULL) + { + + free(list); + return NULL; + } + + return list; +} + +/*skiplist 销毁*/ +void skip_list_destory(skiplist * list) +{ + int i = 0; + node * tmp = NULL; + + if((list == NULL) || (list->head == NULL)) + { + return; + } + while(list->head->next[0] != NULL) + { + tmp = list->head->next[0]; + list->head->next[0] = tmp->next[0]; + free(tmp); + } + + free(list); + return; +} + +/*插入元素获得层数,是随机产生的*/ +int skip_list_level(skiplist * list) +{ + int i = 0; + int level = 1; + for (i = 1; i < list->head->max_level; i++) + { + if ((rand()%2) == 1) + { + level++; + } + } + + return level; +} +int skip_list_insert(skiplist *list,int key,int value) +{ + int i = 0; + int level = 0; + node **update = NULL;/*用来更新每层的指针*/ + node *tmp = NULL; + node *prev = NULL; + + if (list == NULL) + { + return 1; + } + + /*申请update空间用于保存每层的指针*/ + update = (node **)malloc(sizeof(node *)*list->head->max_level); + if (update == NULL) + { + return 2; + } + + /*逐层查询节点的*/ + prev = list->head; + for (i = (list->level -1); i >= 0; i--) + { + /*初始化每level层的头指针*/ + while(((tmp = prev->next[i]) != NULL) && (tmp->key < key)) + { + prev = tmp; + } + update[i] = prev; + } + + /*当前key已经存在,返回错误*/ + if ((tmp!= NULL) && (tmp->key == key)) + { + return 3; + } + /*获取插入元素的随机层数,并更新跳表的最大层数*/ + level = skip_list_level(list); + /*创建当前数据节点*/ + tmp = skip_list_create_node(level,key,value); + if (tmp == NULL) + { + return 4; + } + + /*更新最大层数*/ + if (level > list->level) + { + for (i = list->level;i < level; i ++) + { + update[i] = list->head; + } + list->level = level; + } + + /*逐层更新节点的指针*/ + for(i = 0; i < level; i++) + { + tmp->next[i] = update[i]->next[i]; + update[i]->next[i] = tmp; + } + + list->count++; + return 0; +} + +int skip_list_delete(skiplist * list, int key ,int *value) +{ + int i = 0; + node **update = NULL;/*用来更新每层的指针*/ + node *tmp = NULL; + node *prev = NULL; + + if ((list == NULL) && (value == NULL)&& (list->count == 0)) + { + return 1; + } + /*申请update空间用于保存每层的指针*/ + update = (node **)malloc(sizeof(node *)*list->level); + if (update == NULL) + { + return 2; + } + /*逐层查询节点的*/ + prev = list->head; + for (i = (list->level -1); i >= 0; i--) + { + /*初始化每level层的头指针*/ + while(((tmp = prev->next[i]) != NULL) && (tmp->key < key)) + { + prev = tmp; + } + update[i] = prev; + } + + if ((tmp != NULL) + && (tmp->key == key)) + { + *value = tmp->value; + /*逐层删除*/ + for(i = 0; i < list->level; i++) + { + if(update[i]->next[i] == tmp) + { + update[i]->next[i] = tmp->next[i]; + } + } + + free(tmp); + tmp = NULL; + + /*更新level的层数*/ + for (i = list->level - 1; i >= 0; i++) + { + if (list->head->next[i] == NULL ) + { + list->level--; + } + else + { + break; + } + } + + list->count--; + + } + else + { + return 3;/*未找到节点*/ + } + + return 0 ; +} + +/*查询当前key是否在跳表中,如果存在返回查询的value数值,不存在返回-1*/ +int skip_list_search(skiplist *list,int key,int *value) +{ + int i = 0; + node *prev = NULL; + node *tmp = NULL; + + if((list == NULL) || (list->count == 0) || (value == NULL)) + { + return 1; + } + prev = list->head; + for(i = list->level - 1; i >= 0; i--) + { + while(((tmp = prev->next[i]) != NULL) && (tmp->key <= key)) + { + if (tmp->key == key) + { + *value = tmp->value; + return 0; + } + prev = tmp; + } + } + + return -1; +} + +void skip_list_dump(skiplist *list) +{ + int i = 0; + node *ptmp = NULL; + printf("\r\n----------------------------------------------"); + printf("\r\n skip list level[%d],count[%d]",list->level,list->count); + for(i = list->level - 1; i >= 0; i --) + { + ptmp = list->head->next[i]; + printf("\r\n level[%d]:",i); + while(ptmp != NULL) + { + printf("%d-%d ",ptmp->key,ptmp->value); + ptmp = ptmp->next[i]; + } + } + printf("\r\n----------------------------------------------"); + return; +} + +int main() +{ + int res = 0; + int key = 0; + int value = 0; + skiplist *list = NULL; + + + list = skip_list_create(5); + assert(list != NULL); + + while(1) + { + printf("\r\n 请输入key 和 value,当key = 1000时,退出输入:"); + scanf("%d%d",&key,&value); + if (key == 1000) + { + break; + } + res = skip_list_insert(list,key,value); + if (res != 0) + { + printf("\r\n skip list insert %d,failed,res=%d.",key,res); + } + } + skip_list_dump(list); + + while(1) + { + printf("\r\n 通过key 查询value的数值,当key = 1000时,退出查询"); + scanf("%d",&key); + if(key == 1000) + { + break; + } + res = skip_list_search(list,key,&value); + if (res != 0) + { + printf("\r\n skip list search %d,failed,res=%d.",key,res); + } + else + { + printf("\r\n skip list search %d,sucessful,value=%d.",key,value); + + } + } + skip_list_dump(list); + while(1) + { + printf("\r\n 通过key 删除节点,当key = 1000时,退出删除"); + scanf("%d",&key); + if(key == 1000) + { + break; + } + res = skip_list_delete(list,key,&value); + if (res != 0) + { + printf("\r\n skip list search %d,failed,res=%d.",key,res); + } + else + { + printf("\r\n skip list search %d,sucessful,value=%d.",key,value); + + } + } + + skip_list_dump(list); + skip_list_destory(list); + + return 0; +} diff --git a/c-cpp/17_skiplist/skiplist_c/skiplist.h b/c-cpp/17_skiplist/skiplist_c/skiplist.h new file mode 100644 index 0000000..217c9df --- /dev/null +++ b/c-cpp/17_skiplist/skiplist_c/skiplist.h @@ -0,0 +1,33 @@ +/************************************************************************* + > File Name: skiplist.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-31 + > Desc: + ************************************************************************/ +#ifndef __SKIP_LIST_H__ +#define __SKIP_LIST_H__ + + +typedef struct _node +{ + int key; /*key是唯一的*/ + int value; /*存储的内容*/ + int max_level; /*当前节点最大层数*/ + struct _node *next[0];/*level层链表结构*/ +}node; + +typedef struct _skiplist +{ + int level; + int count; + node *head; +}skiplist; + +/*根据当前结构体元素的地址,获取到结构体首地址*/ +#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container(ptr,type,member) ({\ + const typeof( ((type *)0)->member) *__mptr = (ptr);\ + (type *) ( (char *)__mptr - offsetof(type,member));}) + +#endif From 289d2b374fd272dd4ff6fca2c02b911883605e7d Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Thu, 1 Nov 2018 07:08:39 +0800 Subject: [PATCH 071/141] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=85=E5=AD=98?= =?UTF-8?q?=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c-cpp/17_skiplist/skiplist_c/skiplist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/c-cpp/17_skiplist/skiplist_c/skiplist.c b/c-cpp/17_skiplist/skiplist_c/skiplist.c index 3a171e7..843d575 100644 --- a/c-cpp/17_skiplist/skiplist_c/skiplist.c +++ b/c-cpp/17_skiplist/skiplist_c/skiplist.c @@ -68,6 +68,7 @@ void skip_list_destory(skiplist * list) free(tmp); } + free(list->head); free(list); return; } From 3c3e28e5b187771963439a3dadc47179e7336b02 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Thu, 1 Nov 2018 13:04:33 +0800 Subject: [PATCH 072/141] [cpp][17_skiplist] impl of find, insert, erase. --- c-cpp/17_skiplist/skiplist_tr.hpp | 166 ++++++++++++++++++++++++-- c-cpp/17_skiplist/skiplist_tr_test.cc | 72 ++++++++++- 2 files changed, 228 insertions(+), 10 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index 94ed69b..c0a8162 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -46,6 +46,8 @@ class random_level { }; } // namespace skiplist_detail +enum class erase_policy { ALL, SINGLE }; + template > class skiplist { @@ -63,7 +65,7 @@ class skiplist { "STATIC ASSERT FAILED! iterator type differs."); private: - size_type max_lv_ = 16; + size_type max_lv_ = 8; double prob_ = 0.5; mutable skiplist_detail::random_level rl_; container cont_; @@ -117,7 +119,7 @@ class skiplist { for (auto it : std::next(cont_.begin())->forwards) { assert(it == cont_.end()); } - std::cerr << "UT_DEBUG: all assert in init() success!\n"; + std::cerr << "UT_DEBUG: all assert in init_internally() success!\n"; #endif return; @@ -127,19 +129,84 @@ class skiplist { * such that its hash_key <= target_hash_key */ const_iterator find_helper(const hash_type& key) const { - const_iterator iter = cont_.begin(); +#ifdef LIAM_UT_DEBUG_ + std::cerr << "Keys contained in the list: "; + for (auto node : cont_) { + std::cerr << node.key << ' '; + } + std::cerr << '\n'; + std::cerr << "Target key: " << key << '\n'; +#endif + const_iterator iter = begin(); for (size_type i = 0; i != max_lv_; ++i) { size_type focus = max_lv_ - 1 - i; // invariant: iter->key <= key - for (const_iterator forward = iter->forwards[focus]; - forward != cont_.end() and not compare()(forward->key, key); - forward = iter->forwards[focus]) { - iter = forward; + while (not compare()(key, iter->forwards[focus]->key)) { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "i: " << i << " focus: " << focus << ". " + << "since iter->forwards[focus]->key[" << iter->forwards[focus]->key + << "] <= key[" << key << "], "; +#endif + iter = iter->forwards[focus]; +#ifdef LIAM_UT_DEBUG_ + std::cerr << "step forward iter to [" << iter->key << "]\n"; +#endif } - // result: iter->key <= key and iter->forwards[focus]->key > key + // result: iter->key <= key < iter->forwards[focus]->key +#ifdef LIAM_UT_DEBUG_ + std::cerr << "The following fact holds at level " << focus + << ": iter->key[" << iter->key << "] <= key[" + << key << "] < iter->forwards[focus]->key[" << iter->forwards[focus]->key + <<"].\n"; +#endif } return iter; } + std::vector find_predecessors(const hash_type& key, const size_type& lv) { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "Keys contained in the list: "; + for (auto node : cont_) { + std::cerr << node.key << ' '; + } + std::cerr << '\n'; + std::cerr << "Target key: " << key << '\n'; +#endif + std::vector res; + res.resize(lv + 1); + iterator iter = begin(); + for (size_type i = 0; i != max_lv_; ++i) { + size_type focus = max_lv_ - 1 - i; +#ifdef LIAM_UT_DEBUG_ + std::cerr << "i: " << i << " focus: " << focus << ".\n"; +#endif + // invariant: iter->key < key + while (compare()(iter->forwards[focus]->key, key)) { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "since iter->forwards[focus]->key[" << iter->forwards[focus]->key + << "] < key[" << key << "], "; +#endif + iter = iter->forwards[focus]; +#ifdef LIAM_UT_DEBUG_ + std::cerr << "step forward iter to [" << iter->key << "]\n"; +#endif + } + // result: iter->key < key <= iter->forwards[focus]->key +#ifdef LIAM_UT_DEBUG_ + std::cerr << "The following fact holds at level " << focus + << ": iter->key[" << iter->key << "] < key[" << key + << "] <= iter->forwards[focus]->key[" << iter->forwards[focus]->key + <<"].\n"; +#endif + if (focus < lv + 1) { + res[focus] = iter; +#ifdef LIAM_UT_DEBUG_ + std::cerr << "predecessor at level [" << focus + << "] has been recorded, while level upper limit is " << lv <<".\n"; +#endif + } + } + return res; + } public: size_type size() const { @@ -169,10 +236,93 @@ class skiplist { public: const_iterator find(const value_type& target) const { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "finding [" << target << "]!!!!!!!!!!!!!!!!!!!!\n"; +#endif const hash_type key = hasher()(target); const_iterator iter = find_helper(key); return (iter->key == key) ? iter : cont_.end(); } + void insert(const value_type& target) { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "inserting [" << target << "]!!!!!!!!!!!!!!!!!!!!\n"; +#endif + const hash_type key = hasher()(target); + const size_type lv = rl_(); + std::vector predecessors = find_predecessors(key, lv); + if (predecessors[0]->forwards[0]->key == key) { // key already in skiplist +#ifdef LIAM_UT_DEBUG_ + std::cerr << "key [" << key << "] already in the skiplist, insert directly!\n"; +#endif + predecessors[0]->forwards[0]->values.insert(target); + return; + } else { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "key [" << key << "] not in the skiplist, insert a new node!\n"; +#endif + node_type node(key); + node.forwards.resize(lv + 1); + node.values.insert(target); + iterator inserted = cont_.insert(predecessors[0]->forwards[0], std::move(node)); + for (size_type i = 0; i != lv + 1; ++i) { + inserted->forwards[i] = predecessors[i]->forwards[i]; + predecessors[i]->forwards[i] = inserted; + } +#ifdef LIAM_UT_DEBUG_ + assert(inserted->forwards[0] == std::next(inserted)); +#endif + return; + } + } + void erase(const value_type& target, + const erase_policy policy = erase_policy::ALL) { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "erasing [" << target << "]!!!!!!!!!!!!!!!!!!!!\n"; +#endif + const hash_type key = hasher()(target); + std::vector predecessors = find_predecessors(key, max_lv_); + if (predecessors[0]->forwards[0]->key == key) { // hit +#ifdef LIAM_UT_DEBUG_ + std::cerr << "key [" << key << "] is in the skiplist!\n"; +#endif + iterator found = predecessors[0]->forwards[0]; + for (auto iter = found->values.begin(); iter != found->values.end(); ) { + if (policy == erase_policy::ALL) { + if (*iter == target) { + iter = found->values.erase(iter); + } else { + ++iter; + } + } else if (policy == erase_policy::SINGLE) { + if (*iter == target) { + found->values.erase(iter); + break; + } + } + } +#ifdef LIAM_UT_DEBUG_ + std::cerr << "target(s) removed!\n"; +#endif + if (found->values.empty()) { + const size_type lvp1 = found->forwards.size(); // lv plus 1 + for (size_type i = 0; i != lvp1; ++i) { + predecessors[i]->forwards[i] = found->forwards[i]; + } + cont_.erase(found); +#ifdef LIAM_UT_DEBUG_ + std::cerr << "empty node removed!\n"; +#endif + return; + } else { + return; + } + } else { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "key [" << key << "] is not in the skiplist, do nothing!\n"; +#endif + return; + } + } }; #endif // SKIPLIST_SKIPLIST_TR_HPP_ diff --git a/c-cpp/17_skiplist/skiplist_tr_test.cc b/c-cpp/17_skiplist/skiplist_tr_test.cc index 923022c..9945104 100644 --- a/c-cpp/17_skiplist/skiplist_tr_test.cc +++ b/c-cpp/17_skiplist/skiplist_tr_test.cc @@ -20,14 +20,82 @@ int main() { std::cout << p.first << ' ' << std::string(p.second / 100, '*') << '\n'; } - // 2. UT for skiplist(), init(), size(), empty() + // 2. UT for skiplist(), init_internally(), size(), empty() skiplist sl_default; assert(sl_default.empty()); - // 3. UT for find() [nonexist element] + // 3. UT for constructor of initializer_list and InputIt, init_internally(), insert(), + // find_predecessors() + skiplist sl{"hello", "world", "!"}; + assert(not sl.empty()); + assert(3 == sl.size()); + + // 4. UT for find() find_helper() auto search = sl_default.find("nonexist"); assert(search == sl_default.cend()); assert(search == sl_default.end()); + search = sl.find("hello"); + assert(search != sl.cend()); + assert(search != sl.end()); + search = sl.find("nonexist"); + assert(search == sl.cend()); + assert(search == sl.end()); + + // 5. UT for insert(), find_predecessors() + // 5.1. UT for insert a already-exist item + sl.insert("hello"); + search = sl.find("hello"); + assert(search != sl.cend()); + assert(search != sl.end()); + // 5.2. UT for insert a new incoming item + search = sl.find("now exist"); + assert(search == sl.cend()); + assert(search == sl.end()); + sl.insert("now exist"); + search = sl.find("now exist"); + assert(search != sl.cend()); + assert(search != sl.end()); + + // 6. UT for erase(), find_predecessors() + sl.insert("hello"); + sl.insert("hello"); + sl.insert("hello"); + sl.insert("hello"); + // 6.1. UT for erase single item + sl.erase("hello", erase_policy::SINGLE); + search = sl.find("hello"); + assert(search != sl.cend()); + assert(search != sl.end()); + // 6.2. UT for erase all items + sl.erase("hello", erase_policy::ALL); + search = sl.find("hello"); + assert(search == sl.cend()); + assert(search == sl.end()); + // 6.3 UT for erase non-exist item + sl.erase("nonexist"); + + // 7. UT for insert() behind erase() + // 7.1. different word + sl.insert("world"); + search = sl.find("world"); + assert(search != sl.cend()); + assert(search != sl.end()); + assert(search->values.count("world") == 2); + // 7.1. same word + search = sl.find("hello"); + assert(search == sl.cend()); + assert(search == sl.end()); + sl.insert("hello"); + sl.insert("hello"); + sl.insert("hello"); + sl.insert("hello"); + sl.insert("hello"); + search = sl.find("hello"); + assert(search != sl.cend()); + assert(search != sl.end()); + assert(search->values.count("hello") == 5); + return 0; + // 8. UT for ~skiplist() } From 97db79df970e2cb98e36d84a35d89a42efc5294b Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Thu, 1 Nov 2018 13:55:05 +0800 Subject: [PATCH 073/141] [cpp][17_skiplist] automatically grow within insertion. --- c-cpp/17_skiplist/skiplist_tr.hpp | 47 ++++++++++++++++++++++++--- c-cpp/17_skiplist/skiplist_tr_test.cc | 8 ++++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index c0a8162..9ea72b2 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -49,7 +49,8 @@ class random_level { enum class erase_policy { ALL, SINGLE }; template > + typename Hash = std::hash, + size_t Factor = 2> class skiplist { public: using value_type = Value; @@ -65,7 +66,7 @@ class skiplist { "STATIC ASSERT FAILED! iterator type differs."); private: - size_type max_lv_ = 8; + size_type max_lv_ = 2; double prob_ = 0.5; mutable skiplist_detail::random_level rl_; container cont_; @@ -233,11 +234,41 @@ class skiplist { const_iterator cend() const { return cont_.cend(); } + void grow(const size_type new_max_lv) { + if (max_lv_ < new_max_lv) { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "grow from [" << max_lv_ << "] to [" + << new_max_lv << "]!\n"; +#endif + max_lv_ = new_max_lv; + + iterator tail = std::prev(cont_.end()); + auto beg_tail = tail->forwards.end(); + tail->forwards.resize(max_lv_, cont_.end()); + + iterator head = cont_.begin(); + auto beg_head = head->forwards.end(); + head->forwards.resize(max_lv_, tail); + + return; + } else { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "abandon growing!\n"; +#endif + return; + } + } + void grow() { + grow(Factor * max_lv_); + } + size_type capability() const { + return std::pow(Factor, max_lv_); + } public: const_iterator find(const value_type& target) const { #ifdef LIAM_UT_DEBUG_ - std::cerr << "finding [" << target << "]!!!!!!!!!!!!!!!!!!!!\n"; + std::cerr << "finding [" << target << "]!\n"; #endif const hash_type key = hasher()(target); const_iterator iter = find_helper(key); @@ -245,8 +276,14 @@ class skiplist { } void insert(const value_type& target) { #ifdef LIAM_UT_DEBUG_ - std::cerr << "inserting [" << target << "]!!!!!!!!!!!!!!!!!!!!\n"; + std::cerr << "inserting [" << target << "]!\n"; #endif + if (size() > static_cast(Factor - 1) / Factor * capability()) { +#ifdef LIAM_UT_DEBUG_ + std::cerr << "size[" << size() << "], Factor[" << Factor << "], capability[" << capability() << "]!\n"; +#endif + grow(); + } const hash_type key = hasher()(target); const size_type lv = rl_(); std::vector predecessors = find_predecessors(key, lv); @@ -277,7 +314,7 @@ class skiplist { void erase(const value_type& target, const erase_policy policy = erase_policy::ALL) { #ifdef LIAM_UT_DEBUG_ - std::cerr << "erasing [" << target << "]!!!!!!!!!!!!!!!!!!!!\n"; + std::cerr << "erasing [" << target << "]!\n"; #endif const hash_type key = hasher()(target); std::vector predecessors = find_predecessors(key, max_lv_); diff --git a/c-cpp/17_skiplist/skiplist_tr_test.cc b/c-cpp/17_skiplist/skiplist_tr_test.cc index 9945104..15e3fa2 100644 --- a/c-cpp/17_skiplist/skiplist_tr_test.cc +++ b/c-cpp/17_skiplist/skiplist_tr_test.cc @@ -23,6 +23,12 @@ int main() { // 2. UT for skiplist(), init_internally(), size(), empty() skiplist sl_default; assert(sl_default.empty()); + // 2.1. UT for grow with abandon + sl_default.grow(1); + assert(sl_default.capability() == 4); + // 2.2. UT for grow + sl_default.grow(10); + assert(sl_default.capability() == 1024); // 3. UT for constructor of initializer_list and InputIt, init_internally(), insert(), // find_predecessors() @@ -81,7 +87,7 @@ int main() { assert(search != sl.cend()); assert(search != sl.end()); assert(search->values.count("world") == 2); - // 7.1. same word + // 7.1. same word, also UT for grow() search = sl.find("hello"); assert(search == sl.cend()); assert(search == sl.end()); From 0647c1dffdcf64f824f3e495265c18c6912817c7 Mon Sep 17 00:00:00 2001 From: MG Date: Thu, 1 Nov 2018 15:21:26 +0800 Subject: [PATCH 074/141] =?UTF-8?q?=E5=8D=95=E5=90=91=E9=93=BE=E8=A1=A8?= =?UTF-8?q?=E7=9A=84Python=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.单链表的插入、删除、查找操作; 2.链表中存储的数据类型是Int --- python/06_linkedlist/singlyLinkedList.py | 197 +++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 python/06_linkedlist/singlyLinkedList.py diff --git a/python/06_linkedlist/singlyLinkedList.py b/python/06_linkedlist/singlyLinkedList.py new file mode 100644 index 0000000..0e9663b --- /dev/null +++ b/python/06_linkedlist/singlyLinkedList.py @@ -0,0 +1,197 @@ +# 1.单链表的插入、删除、查找操作; +# 2.链表中存储的数据类型是Int +# +# Author:Lee + +class Node(): + '''链表结构的Node节点''' + + def __init__(self, data, next=None): + '''Node节点的初始化方法. + 参数: + data:存储的数据 + next:下一个Node节点的引用地址 + ''' + self.__data = data + self.__next = next + + @property + def data(self): + '''Node节点存储数据的获取. + 返回: + 当前Node节点存储的数据 + ''' + return self.__data + + @data.setter + def data(self, data): + '''Node节点存储数据的设置方法. + 参数: + data:新的存储数据 + ''' + self.__data = data + + @property + def next(self): + '''获取Node节点的next指针值. + 返回: + next指针数据 + ''' + return self.__next + + @next.setter + def next(self, next): + '''Node节点next指针的修改方法. + 参数: + next:新的下一个Node节点的引用 + ''' + self.__next = next + + +class SinglyLinkedList(): + '''单向链表''' + + def __init__(self): + '''单向列表的初始化方法.''' + self.__head = None + + def find_by_value(self, value): + '''按照数据值在单向列表中查找. + 参数: + value:查找的数据 + 返回: + Node + ''' + node = self.__head + while node != None and node.data != value: + node = node.next + return node + + def find_by_index(self, index): + '''按照索引值在列表中查找. + 参数: + index:索引值 + 返回: + Node + ''' + node = self.__head + pos = 0 + while node != None and pos != index: + node = node.next + pos += 1 + return node + + def insert_to_head(self, value): + '''在链表的头部插入一个存储value数值的Node节点. + 参数: + value:将要存储的数据 + ''' + node = Node(value) + node.next = self.__head + self.__head = node + + def insert_after(self, node, value): + '''在链表的某个指定Node节点之后插入一个存储value数据的Node节点. + 参数: + node:指定的一个Node节点 + value:将要存储在新Node节点中的数据 + ''' + if node == None: # 如果指定在一个空节点之后插入数据节点,则什么都不做 + return + + new_node = Node(value) + new_node.next = node.next + node.next = new_node + + def insert_before(self, node, value): + '''在链表的某个指定Node节点之前插入一个存储value数据的Node节点. + 参数: + node:指定的一个Node节点 + value:将要存储在新的Node节点中的数据 + ''' + if node == None or self.__head == None: # 如果指定在一个空节点之前或者空链表之前插入数据节点,则什么都不做 + return + + if node == self.__head: # 如果是在链表头之前插入数据节点,则直接插入 + self.insert_to_head(value) + return + + new_node = Node(value) + pro = self.__head + not_found = False # 如果在整个链表中都没有找到指定插入的Node节点,则该标记量设置为True + while pro.next != node: # 寻找指定Node之前的一个Node + if pro.next == None: # 如果已经到了链表的最后一个节点,则表明该链表中没有找到指定插入的Node节点 + not_found = True + break + else: + pro = pro.next + if not_found == False: + pro.next = new_node + new_node.next = node + + def delete_by_node(self, node): + '''在链表中删除指定Node的节点. + 参数: + node:指定的Node节点 + ''' + if self.__head == None: # 如果链表是空的,则什么都不做 + return + + if node == self.__head: # 如果指定删除的Node节点是链表的头节点 + self.__head = node.next + return + + pro = self.__head + not_found = False # 如果在整个链表中都没有找到指定删除的Node节点,则该标记量设置为True + while pro.next != node: + if pro.next == None: # 如果已经到链表的最后一个节点,则表明该链表中没有找到指定删除的Node节点 + not_found == True + break + else: + pro = pro.next + if not_found == False: + pro.next = node.next + + def delete_by_value(self, value): + '''在链表中删除指定存储数据的Node节点. + 参数: + value:指定的存储数据 + ''' + if self.__head == None: # 如果链表是空的,则什么都不做 + return + + if self.__head.data == value: # 如果链表的头Node节点就是指定删除的Node节点 + self.__head = self.__head.next + + pro = self.__head + node = self.__head.next + not_found = False + while node.data != value: + if node.next == None: # 如果已经到链表的最后一个节点,则表明该链表中没有找到执行Value值的Node节点 + not_found == True + break + else: + pro = node + node = node.next + if not_found == False: + pro.next = node.next + + def create_node(self, value): + '''创建一个存储value值的Node节点. + 参数: + value:将要存储在Node节点中的数据 + 返回: + 一个新的Node节点 + ''' + return Node(value) + + def print_all(self): + '''打印当前链表所有节点数据.''' + pos = self.__head + if pos == None: + print('当前链表还没有数据') + return + while pos.next != None: + print(str(pos.data) + ' --> ', end='') + pos = pos.next + print(str(pos.data)) From cb5728e3131bf5dbc6c8be59104f96c3798595d5 Mon Sep 17 00:00:00 2001 From: nameczz Date: Thu, 1 Nov 2018 23:07:55 +0800 Subject: [PATCH 075/141] add 15-16 binary find --- javascript/15_binary/binaryFind.js | 27 +++++++++ javascript/16_binary/binary-find.js | 90 +++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 javascript/15_binary/binaryFind.js create mode 100644 javascript/16_binary/binary-find.js diff --git a/javascript/15_binary/binaryFind.js b/javascript/15_binary/binaryFind.js new file mode 100644 index 0000000..86ae4ef --- /dev/null +++ b/javascript/15_binary/binaryFind.js @@ -0,0 +1,27 @@ +/** + * 二分查找 + * + * Author: nameczz + */ +// 数组必须有序 不存在重复 +const biaryFind = (sortedArr, target) => { + if (sortedArr.length === 0) return -1 + let low = 0 + let high = sortedArr.length - 1 + while (low <= high) { + const mid = Math.floor((low + high) / 2) + if (target === sortedArr[mid]) { + return mid + } else if (target < sortedArr[mid]) { + high = mid - 1 + } else { + low = mid + 1 + } + } + return -1 +} +const arr = [1, 4, 5, 6, 7, 8, 10, 11, 23, 42, 44, 54, 56, 77, 102] +console.log(biaryFind(arr, 44)) +console.log(biaryFind(arr, 1)) +console.log(biaryFind(arr, 102)) +console.log(biaryFind(arr, 1111)) \ No newline at end of file diff --git a/javascript/16_binary/binary-find.js b/javascript/16_binary/binary-find.js new file mode 100644 index 0000000..ef055fb --- /dev/null +++ b/javascript/16_binary/binary-find.js @@ -0,0 +1,90 @@ +/** + * 二分查找 + * + * Author: nameczz + */ + + +// 查找第一个等于给定值 +const biaryFindFirst = (sortedArr, target) => { + if (sortedArr.length === 0) return -1 + let low = 0 + let high = sortedArr.length - 1 + while (low <= high) { + const mid = Math.floor((low + high) / 2) + + if (target < sortedArr[mid]) { + high = mid - 1 + } else if (target > sortedArr[mid]) { + low = mid + 1 + } else { + if (mid === 0 || sortedArr[mid - 1] < target) return mid + high = mid - 1 + } + } + return -1 +} + +// 查找最后一个相等的数 +const biaryFindLast = (sortedArr, target) => { + if (sortedArr.length === 0) return -1 + let low = 0 + let high = sortedArr.length - 1 + while (low <= high) { + const mid = Math.floor((low + high) / 2) + if (target < sortedArr[mid]) { + high = mid - 1 + } else if (target > sortedArr[mid]) { + low = mid + 1 + } else { + if (mid === sortedArr.length - 1 || sortedArr[mid + 1] > target) return mid + low = mid + 1 + } + } + return -1 +} + +// 查找第一个大于等于给定值的元素 +const biaryFindFistBig = (sortedArr, target) => { + if (sortedArr.length === 0) return -1 + let low = 0 + let high = sortedArr.length - 1 + while (low <= high) { + const mid = Math.floor((low + high) / 2) + if (target <= sortedArr[mid]) { + if (mid === 0 || sortedArr[mid - 1] < target) return mid + high = mid - 1 + } else { + low = mid + 1 + } + } + return -1 +} + +// 查找最后一个小于等于给定值的元素 +const biaryFindLastSmall = (sortedArr, target) => { + if (sortedArr.length === 0) return -1 + let low = 0 + let high = sortedArr.length - 1 + while (low <= high) { + const mid = Math.floor((low + high) / 2) + if (sortedArr[mid] > target) { + high = mid - 1 + } else { + if (mid === sortedArr.length - 1 || sortedArr[mid + 1] > target) return mid + low = mid + 1 + } + } + return -1 +} + +const arr = [1, 2, 3, 4, 4, 4, 4, 4, 6, 7, 8, 8, 9] +const first = biaryFindFirst(arr, 4) +console.log(`FindFirst: ${first}`) + +const last = biaryFindLast(arr, 4) +console.log(`FindLast: ${last}`) +const FisrtBig = biaryFindFistBig(arr, 5) +console.log(`FindFisrtBig: ${FisrtBig}`) +const LastSmall = biaryFindLastSmall(arr, 4) +console.log(`FindLastSmall: ${LastSmall}`) \ No newline at end of file From bd19818762cf5b6738ee2fe2e5b3c0d339e340af Mon Sep 17 00:00:00 2001 From: westGG Date: Fri, 2 Nov 2018 16:31:12 +0800 Subject: [PATCH 076/141] fix 133 --- java/05_array/GenericArray.java | 269 ++++++++++++++++---------------- 1 file changed, 134 insertions(+), 135 deletions(-) diff --git a/java/05_array/GenericArray.java b/java/05_array/GenericArray.java index 07dc5dc..631a1ba 100644 --- a/java/05_array/GenericArray.java +++ b/java/05_array/GenericArray.java @@ -1,164 +1,163 @@ -/** - * - * 1)泛型动态数组 - * - * Author: shi - */ +public class GenericArray { + private T[] data; + private int size; - public class GenericArray { - private T[] data; - private int size; + // 根据传入容量,构造Array + public GenericArray(int capacity) { + data = (T[]) new Object[capacity]; + size = 0; + } - // 根据传入容量,构造Array - public GenericArray(int capacity) { - data = (T[]) new Object[capacity]; - size = 0; - } + // 无参构造方法,默认数组容量为10 + public GenericArray() { + this(10); + } - // 无参构造方法,默认数组容量为10 - public GenericArray() { - this(10); - } + // 获取数组容量 + public int getCapacity() { + return data.length; + } - // 获取数组容量 - public int getCapacity() { - return data.length; - } + // 获取当前元素个数 + public int count() { + return size; + } - // 获取当前元素个数 - public int count() { - return size; - } + // 判断数组是否为空 + public boolean isEmpty() { + return size == 0; + } - // 判断数组是否为空 - public boolean isEmpty() { - return size == 0; - } + // 修改 index 位置的元素 + public void set(int index, T e) { + checkIndex(index); + data[index] = e; + } - // 修改 index 位置的元素 - public void set(int index, T e) { - checkIndex(index); - data[index] = e; - } + // 获取对应 index 位置的元素 + public T get(int index) { + checkIndex(index); + return data[index]; + } - // 获取对应 index 位置的元素 - public T get(int index) { - checkIndex(index); - return data[index]; - } + // 查看数组是否包含元素e + public boolean contains(T e) { + for (int i = 0; i < size; i++) { + if (data[i].equals(e)) { + return true; + } + } + return false; + } - // 查看数组是否包含元素e - public boolean contains(T e) { - for (int i = 0; i < size; i++) { - if (data[i].equals(e)) { - return true; - } - } - return false; - } - - // 获取对应元素的下标, 未找到,返回 -1 - public int find(T e) { - for ( int i = 0; i < size; i++) { - if (data[i].equals(e)) { - return i; - } - } - return -1; - } + // 获取对应元素的下标, 未找到,返回 -1 + public int find(T e) { + for ( int i = 0; i < size; i++) { + if (data[i].equals(e)) { + return i; + } + } + return -1; + } - // 在 index 位置,插入元素e, 时间复杂度 O(m+n) - public void add(int index, T e) { - checkIndex(index); - // 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍 - if (size == data.length) { - resize(2 * data.length); - } + // 在 index 位置,插入元素e, 时间复杂度 O(m+n) + public void add(int index, T e) { + checkIndex(index); + // 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍 + if (size == data.length) { + resize(2 * data.length); + } - for (int i = size - 1; i >= index; i--) { - data[i + 1] = data[i]; - } - data[index] = e; - size++; - } + for (int i = size - 1; i >= index; i--) { + data[i + 1] = data[i]; + } + data[index] = e; + size++; + } - // 向数组头插入元素 - public void addFirst(T e) { - add(0, e); - } + // 向数组头插入元素 + public void addFirst(T e) { + add(0, e); + } - // 向数组尾插入元素 - public void addLast(T e) { - add(size, e); - } + // 向数组尾插入元素 + public void addLast(T e) { + add(size, e); + } - // 删除 index 位置的元素,并返回 - public T remove(int index) { - checkIndex(index); + // 删除 index 位置的元素,并返回 + public T remove(int index) { + checkIndexForRemove(index); - T ret = data[index]; - for (int i = index + 1; i < size; i++) { - data[i - 1] = data[i]; - } - size --; - data[size] = null; + T ret = data[index]; + for (int i = index + 1; i < size; i++) { + data[i - 1] = data[i]; + } + size --; + data[size] = null; - // 缩容 - if (size == data.length / 4 && data.length / 2 != 0) { - resize(data.length / 2); - } + // 缩容 + if (size == data.length / 4 && data.length / 2 != 0) { + resize(data.length / 2); + } - return ret; - } + return ret; + } - // 删除第一个元素 - public T removeFirst() { - return remove(0); - } + // 删除第一个元素 + public T removeFirst() { + return remove(0); + } - // 删除末尾元素 - public T removeLast() { - return remove(size - 1); - } + // 删除末尾元素 + public T removeLast() { + return remove(size - 1); + } - // 从数组中删除指定元素 - public void removeElement(T e) { - int index = find(e); - if (index != -1) { - remove(index); - } - } + // 从数组中删除指定元素 + public void removeElement(T e) { + int index = find(e); + if (index != -1) { + remove(index); + } + } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length)); - builder.append('['); - for (int i = 0; i < size; i++) { - builder.append(data[i]); - if (i != size - 1) { - builder.append(", "); - } - } - builder.append(']'); - return builder.toString(); - } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length)); + builder.append('['); + for (int i = 0; i < size; i++) { + builder.append(data[i]); + if (i != size - 1) { + builder.append(", "); + } + } + builder.append(']'); + return builder.toString(); + } - // 扩容方法,时间复杂度 O(n) - private void resize(int capacity) { - T[] newData = (T[]) new Object[capacity]; + // 扩容方法,时间复杂度 O(n) + private void resize(int capacity) { + T[] newData = (T[]) new Object[capacity]; - for (int i = 0; i < size; i++) { - newData[i] = data[i]; - } - data = newData; - } + for (int i = 0; i < size; i++) { + newData[i] = data[i]; + } + data = newData; + } - private void checkIndex(int index) { + private void checkIndex(int index) { if (index < 0 || index > size) { throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size."); } - } - } + } + + private void checkIndexForRemove(int index) { + if(index < 0 || index >= size) { + throw new IllegalArgumentException("remove failed! Require index >=0 and index < size."); + } + } +} \ No newline at end of file From 9d5a939cd0941ffaa1da667e9f0881757a7c5b4d Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 2 Nov 2018 22:43:10 +0800 Subject: [PATCH 077/141] [cpp][17_skiplist] put std::fill's work into resize. --- c-cpp/17_skiplist/skiplist_tr.hpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index 9ea72b2..8e931d7 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -101,16 +101,13 @@ class skiplist { void init_internally() { const hash_type tail_key = std::numeric_limits::max(); node_type tail(tail_key); - tail.forwards.resize(max_lv_); - std::fill(tail.forwards.begin(), tail.forwards.end(), cont_.end()); - cont_.insert(cont_.begin(), std::move(tail)); + tail.forwards.resize(max_lv_, cont_.end()); + iterator tail_iter = cont_.insert(cont_.begin(), std::move(tail)); const hash_type head_key = std::numeric_limits::min(); node_type head(head_key); - head.forwards.resize(max_lv_); + head.forwards.resize(max_lv_, tail_iter); cont_.insert(cont_.begin(), std::move(head)); - std::fill(cont_.begin()->forwards.begin(), cont_.begin()->forwards.end(), - std::next(cont_.begin())); #ifdef LIAM_UT_DEBUG_ assert(cont_.begin()->key == head_key); @@ -363,4 +360,3 @@ class skiplist { }; #endif // SKIPLIST_SKIPLIST_TR_HPP_ - From 2a3093b9f339117c5aac7c3c38762507ee1c096b Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Sun, 4 Nov 2018 06:34:54 +0800 Subject: [PATCH 078/141] skiplist in c --- c-cpp/17_skiplist/skiplist.c | 214 +++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 c-cpp/17_skiplist/skiplist.c diff --git a/c-cpp/17_skiplist/skiplist.c b/c-cpp/17_skiplist/skiplist.c new file mode 100644 index 0000000..82621c5 --- /dev/null +++ b/c-cpp/17_skiplist/skiplist.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include + +// https://www.youtube.com/watch?v=2g9OSRKJuzM&t=17s + +#define MAX_LEVEL 15 + +struct node { + int val; + int max_level; + struct node *forward[MAX_LEVEL]; +}; + +struct skip_list { + struct node head; + int max_level; + int max_level_nodes; +}; + +void node_init(struct node* node) +{ + memset(node, 0, sizeof(struct node)); +} + +void skip_list_init(struct skip_list* sl) +{ + node_init(&sl->head); + sl->max_level = 0; + sl->max_level_nodes = 0; +} + +void random_init() +{ + static bool done = false; + + if (done) + return; + + srandom(time(NULL)); + done = true; +} + +int random_level(void) +{ + int i, level = 1; + + random_init(); + + for (i = 1; i < MAX_LEVEL; i++) + if (random() % 2 == 1) + level++; + + return level; +} + +void random_level_test() +{ + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); +} + +void insert(struct skip_list *sl, int val) +{ + int level = random_level(); + struct node *update[MAX_LEVEL]; + struct node *new, *p; + int i; + + new = (struct node*)malloc(sizeof(struct node)); + if (!new) + return; + + new->max_level = level; + new->val = val; + + for (int i = 0; i < MAX_LEVEL; i++) + update[i] = &sl->head; + + p = &sl->head; + for (i = level - 1; i >= 0; i--) { + while(p->forward[i] && p->forward[i]->val < val) + p = p->forward[i]; + + update[i] = p; + } + + for (i = 0; i < level; i++) { + new->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = new; + } + + if (sl->max_level < level) { + sl->max_level = level; + sl->max_level_nodes = 1; + } else if (sl->max_level == level) + sl->max_level_nodes++; +} + +struct node *find(struct skip_list* sl, int val) +{ + struct node *node = &sl->head; + int i; + + for (i = sl->max_level - 1; i >= 0; i--) { + while (node->forward[i] && node->forward[i]->val < val) + node = node->forward[i]; + } + + if (node->forward[0] && node->forward[0]->val == val) { + return node->forward[0]; + } + else + return NULL; +} + +void delete(struct skip_list* sl, int val) +{ + struct node *update[MAX_LEVEL]; + struct node *p; + int i; + + p = &sl->head; + + for (i = sl->max_level; i >= 0; i--) { + while (p->forward[i] && p->forward[i]->val < val) + p = p->forward[i]; + + update[i] = p; + } + + if (p->forward[0] == NULL || p->forward[0]->val != val) + return; + + if (p->forward[0]->max_level == sl->max_level) + sl->max_level_nodes--; + + for (i = sl->max_level-1; i >= 0; i--) { + if (update[i]->forward[i] && update[i]->forward[i]->val == val) + update[i]->forward[i] = update[i]->forward[i]->forward[i]; + } + + // fixup max_level and max_level_nodes + if (sl->max_level_nodes == 0) { + //sl->max_level--; + p = &sl->head; + // skip (max_level - 1), direct test (max_level - 2) + // since no nodes on (max_level - 1) + for (i = sl->max_level - 2; i >= 0; i--) { + while (p->forward[i]) { + sl->max_level_nodes++; + p = p->forward[i]; + } + + if (sl->max_level_nodes) { + sl->max_level = i + 1; + break; + } else + sl->max_level = i; + } + } +} + + +void print_sl(struct skip_list* sl) +{ + struct node *node; + int level; + + printf("%d level skip list with %d nodes on top\n", + sl->max_level, sl->max_level_nodes); + + for (level = sl->max_level - 1; level >= 0; level--) { + node = &sl->head; + printf("Level[%02d]:", level); + while (node->forward[level]) { + printf("%4d", node->forward[level]->val); + node = node->forward[level]; + } + printf("\n"); + } +} + +int main() +{ + struct skip_list sl; + struct node *node = NULL; + int i; + + skip_list_init(&sl); + print_sl(&sl); + + for (i = 0; i < 10; i++) + insert(&sl, i); + print_sl(&sl); + + node = find(&sl, 8); + if (node) + printf("find 8 in sl %d\n", node->val); + else + printf("8 not in sl\n"); + + for (i = 0; i < 10; i++) { + delete(&sl, i); + print_sl(&sl); + } + + return 0; +} From 99ee504a68424f6eed1214fb54a9b373387497c7 Mon Sep 17 00:00:00 2001 From: westGG Date: Sun, 4 Nov 2018 10:19:11 +0800 Subject: [PATCH 079/141] Resovle the conflict of the 11_sorts/Sorts.java --- java/11_sorts/Sorts.java | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/java/11_sorts/Sorts.java b/java/11_sorts/Sorts.java index e55efd7..9460291 100644 --- a/java/11_sorts/Sorts.java +++ b/java/11_sorts/Sorts.java @@ -49,31 +49,16 @@ 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]; From 7119f47c9e10f4ce4866b708db5324fddc5e7f27 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Mon, 5 Nov 2018 11:29:38 +0800 Subject: [PATCH 080/141] hash table in c --- c-cpp/18_hashtable/hashtable.c | 186 +++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 c-cpp/18_hashtable/hashtable.c diff --git a/c-cpp/18_hashtable/hashtable.c b/c-cpp/18_hashtable/hashtable.c new file mode 100644 index 0000000..03f7035 --- /dev/null +++ b/c-cpp/18_hashtable/hashtable.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include + +/* One implementation of hash table with linear probing. */ + +#define HASH_SHIFT 4 +#define HASH_SIZE (1 << HASH_SHIFT) +#define HASH_MASK (HASH_SIZE - 1) + +struct hash_table { + unsigned int used; + unsigned long entry[HASH_SIZE]; +}; + +void hash_table_reset(struct hash_table *table) +{ + int i; + + table->used = 0; + for (i = 0; i < HASH_SIZE; i++) + table->entry[i] = ~0; +} + +unsigned int hash_function(unsigned long value) +{ + return value & HASH_MASK; +} + +void dump_hash_table(struct hash_table *table) +{ + int i; + + for (i = 0; i < HASH_SIZE; i++) { + if (table->entry[i] == ~0) + printf("%2u: nil \n", i); + else + printf("%2u:%10lu -> %2u\n", + i, table->entry[i], + hash_function(table->entry[i])); + } +} + +void hash_function_test() +{ + int i; + + srandom(time(NULL)); + + for (i = 0; i < 10; i++) { + unsigned long val = random(); + printf("%10lu -> %2u\n", val, hash_function(val));; + } +} + +unsigned int next_probe(unsigned int prev_key) +{ + return (prev_key + 1) & HASH_MASK; +} + +void next_probe_test() +{ + int i; + unsigned int key1, key2; + + key1 = 0; + for (i = 0; i < HASH_SIZE; i++) { + key2 = next_probe(key1); + printf("%2u -> %2u\n", key1, key2); + key1 = key2; + } +} + +void hash_table_add(struct hash_table *table, unsigned long value) +{ + unsigned int key = hash_function(value); + + if (table->used >= HASH_SIZE) + return; + + while (table->entry[key] != ~0) + key = next_probe(key); + + table->entry[key] = value; + table->used++; +} + +unsigned int hash_table_slot(struct hash_table *table, unsigned long value) +{ + int i; + unsigned int key = hash_function(value); + + for (i = 0; i < HASH_SIZE; i++) { + if (table->entry[key] == value || table->entry[key] == ~0) + break; + key = next_probe(key); + } + + return key; +} + +bool hash_table_find(struct hash_table *table, unsigned long value) +{ + return table->entry[hash_table_slot(table, value)] == value; +} + +void hash_table_del(struct hash_table *table, unsigned long value) +{ + unsigned int i, j, k; + + if (!hash_table_find(table, value)) + return; + + i = j = hash_table_slot(table, value); + + while (true) { + table->entry[i] = ~0; + + do { + j = next_probe(j); + if (table->entry[j] == ~0) + return; + k = hash_function(table->entry[j]); + } while ((i <= j) ? (i < k && k <= j) : (i < k || k <= j)); + + table->entry[i] = table->entry[j]; + i = j; + } + table->used++; +} + +void hash_table_add_test() +{ + struct hash_table table; + + hash_table_reset(&table); + hash_table_add(&table, 87645); + + printf("Table has%s 87645\n", + hash_table_find(&table, 87645) ? "":"n't"); + printf("Table has%s 87647\n", + hash_table_find(&table, 87647) ? "":"n't"); +} + +void hash_table_del_test1() +{ + struct hash_table table; + + hash_table_reset(&table); + hash_table_add(&table, 0x1ff0); + hash_table_add(&table, 0x2ff0); + hash_table_add(&table, 0x3ff0); + dump_hash_table(&table); + + printf("=== Remove 0x1ff0\n"); + hash_table_del(&table, 0x1ff0); + dump_hash_table(&table); +} + +void hash_table_del_test2() +{ + struct hash_table table; + + hash_table_reset(&table); + hash_table_add(&table, 0x1ff0); + hash_table_add(&table, 0x1ff1); + hash_table_add(&table, 0x1ff2); + hash_table_add(&table, 0x2ff0); + dump_hash_table(&table); + + printf("=== Remove 0x1ff0\n"); + hash_table_del(&table, 0x1ff0); + dump_hash_table(&table); +} + +int main() +{ + //hash_function_test(); + //next_probe_test(); + //hash_table_add_test(); + hash_table_del_test2(); + + return 0; +} From a858db3ee44810d31326e7db21ba66d827e5570f Mon Sep 17 00:00:00 2001 From: danielyan86 <516495459@qq.com> Date: Tue, 6 Nov 2018 11:17:07 +0800 Subject: [PATCH 081/141] =?UTF-8?q?1=20=E8=A7=A3=E5=86=B3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=86=B2=E7=AA=81=EF=BC=8C=E8=AE=A9=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E8=BF=90=E8=A1=8C=202=20=E6=9B=B4=E6=AD=A3?= =?UTF-8?q?=E8=8B=B1=E8=AF=AD=E5=8D=95=E8=AF=8D=E6=8B=BC=E5=86=99=E9=94=99?= =?UTF-8?q?=E8=AF=AF=203=20=E6=9B=B4=E6=AD=A3print=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E9=94=99=E8=AF=AF=204=20=E6=A0=B9=E6=8D=AEPython=20PEP8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A7=84=E8=8C=83=E8=B0=83=E6=95=B4=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/05_array/myarray.py | 58 +++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/python/05_array/myarray.py b/python/05_array/myarray.py index 6ff0562..03a07ec 100644 --- a/python/05_array/myarray.py +++ b/python/05_array/myarray.py @@ -1,4 +1,6 @@ from typing import Optional + + # # 1) Insertion, deletion and random access of array # 2) Assumes int for element type @@ -15,7 +17,7 @@ class MyArray: self._data = [] self._count = 0 self._capacity = capacity - + def __getitem__(self, position: int) -> int: """Support for subscript. @@ -25,30 +27,33 @@ class MyArray: def find(self, index: int) -> Optional[int]: - if index >= self._count or index <= -self._count: return None + 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:] + + 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) + print('delete function', self._data) return True def insert(self, index: int, value: int) -> bool: - #if index >= self._count or index <= -self._count: return False - if self._capacity == self._count: return False + # if index >= self._count or index <= -self._count: return False + if self._capacity == self._count: + return False # 如果还有空间,那么插入位置大于当前的元素个数,可以插入最后的位置 if index >= self._count: self._data.append(value) # 同上,如果位置小于0 可以插入第0个位置. if index < 0: - print (index) + print(index) self._data.insert(0, value) self._count += 1 @@ -56,14 +61,15 @@ class MyArray: def insert_to_tail(self, value: int) -> bool: - if self._count == self._capacity: return False + if self._count == self._capacity: + return False if self._count == len(self._data): - self._data.append(value) + self._data.append(value) else: self._data[self._count] = value self._count += 1 return True - + def __repr__(self) -> str: return " ".join(str(num) for num in self._data[:self._count]) @@ -71,25 +77,31 @@ class MyArray: def print_all(self): for num in self._data[:self._count]: - print("{num}", end=" ") + print(f"{num}", end=" ") print("\n", flush=True) + +def test_myarray(): + array_a = MyArray(6) + for num in range(6): + array_a.insert_to_tail(num) + assert array_a.find(0) == 0 + assert array_a[0] == 0 + array_a.delete(0) + assert array_a[0] == 1 + + if __name__ == "__main__": a = MyArray(6) 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) + print('origin', a) a.delete(4) - print ('delete ',a) + print('delete ', a) - a.insert(100,10000) - print (a) - ->>>>>>> upstream/master + a.insert(100, 10000) + print(a) From d784b1b91ab986a7ae66638509af90bf5f517066 Mon Sep 17 00:00:00 2001 From: quanxing Date: Tue, 6 Nov 2018 23:35:10 +0800 Subject: [PATCH 082/141] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B8=A6=E5=A4=B4?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E7=BF=BB=E8=BD=AC=E5=92=8C=E4=B8=8D=E5=B8=A6?= =?UTF-8?q?=E5=A4=B4=E8=8A=82=E7=82=B9=E7=BF=BB=E8=BD=AC=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E5=9B=9E=E6=96=87=E4=B8=B2=E7=9A=84=E5=AE=9E=E7=8E=B0C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- java/06_linkedlist/SinglyLinkedList.java | 405 ++++++++++++++++------- 1 file changed, 286 insertions(+), 119 deletions(-) diff --git a/java/06_linkedlist/SinglyLinkedList.java b/java/06_linkedlist/SinglyLinkedList.java index 0931d13..cf3d154 100644 --- a/java/06_linkedlist/SinglyLinkedList.java +++ b/java/06_linkedlist/SinglyLinkedList.java @@ -8,160 +8,327 @@ package linkedlist; */ public class SinglyLinkedList { - private Node head = null; + private Node head = null; - public Node findByValue(int value) { - Node p = head; - while (p != null && p.data != value) { - p = p.next; + public Node findByValue(int value) { + Node p = head; + while (p != null && p.data != value) { + p = p.next; + } + + return p; } - return p; - } + public Node findByIndex(int index) { + Node p = head; + int pos = 0; + while (p != null && pos != index) { + p = p.next; + ++pos; + } - public Node findByIndex(int index) { - Node p = head; - int pos = 0; - while (p != null && pos != index) { - p = p.next; - ++pos; + return p; } - return p; - } - - public void insertToHead(int value) { - Node newNode = new Node(value, null); - insertToHead(newNode); - } - - public void insertToHead(Node newNode) { - if (head == null) { - head = newNode; - } else { - newNode.next = head; - head = newNode; - } - } - - public void insertAfter(Node p, int value) { - Node newNode = new Node(value, null); - insertAfter(p, newNode); - } - - public void insertAfter(Node p, Node newNode) { - if (p == null) return; - - newNode.next = p.next; - p.next = newNode; - } - - public void insertBefore(Node p, int value) { - Node newNode = new Node(value, null); - insertBefore(p, newNode); - } - - public void insertBefore(Node p, Node newNode) { - if (p == null) return; - if (head == p) { - insertToHead(newNode); - return; + //无头结点 + //表头部插入 + //这种操作将于输入的顺序相反,逆序 + public void insertToHead(int value) { + Node newNode = new Node(value, null); + insertToHead(newNode); } - Node q = head; - while (q != null && q.next != p) { - q = q.next; + public void insertToHead(Node newNode) { + if (head == null) { + head = newNode; + } else { + newNode.next = head; + head = newNode; + } } - if (q == null) { - return; + //顺序插入 + //链表尾部插入 + public void insertTail(int value){ + + Node newNode = new Node(value, null); + //空链表,可以插入新节点作为head,也可以不操作 + if (head == null){ + head = newNode; + + }else{ + Node q = head; + while(q.next != null){ + q = q.next; + } + newNode.next = q.next; + q.next = newNode; + } + } + public void insertAfter(Node p, int value) { + Node newNode = new Node(value, null); + insertAfter(p, newNode); } - newNode.next = p; - q.next = newNode; + public void insertAfter(Node p, Node newNode) { + if (p == null) return; - } - - public void deleteByNode(Node p) { - if (p == null || head == null) return; - - if (p == head) { - head = head.next; - return; + newNode.next = p.next; + p.next = newNode; } - Node q = head; - while (q != null && q.next != p) { - q = q.next; + public void insertBefore(Node p, int value) { + Node newNode = new Node(value, null); + insertBefore(p, newNode); } - if (q == null) { - return; + public void insertBefore(Node p, Node newNode) { + if (p == null) return; + if (head == p) { + insertToHead(newNode); + return; + } + + Node q = head; + while (q != null && q.next != p) { + q = q.next; + } + + if (q == null) { + return; + } + + newNode.next = p; + q.next = newNode; + } - q.next = q.next.next; - } + public void deleteByNode(Node p) { + if (p == null || head == null) return; - public void deleteByValue(int value) { - if (head == null) return; + if (p == head) { + head = head.next; + return; + } - Node p = head; - Node q = null; - while (p != null && p.data != value) { - q = p; - p = p.next; + Node q = head; + while (q != null && q.next != p) { + q = q.next; + } + + if (q == null) { + return; + } + + q.next = q.next.next; } - if (p == null) return; + public void deleteByValue(int value) { + if (head == null) return; - if (q == null) { - head = head.next; - } else { - q.next = q.next.next; + Node p = head; + Node q = null; + while (p != null && p.data != value) { + q = p; + p = p.next; + } + + if (p == null) return; + + if (q == null) { + head = head.next; + } else { + q.next = q.next.next; + } + + // 可重复删除指定value的代码 + /* + if (head != null && head.data == value) { + head = head.next; + } + + Node pNode = head; + while (pNode != null) { + if (pNode.next.data == data) { + pNode.next = pNode.next.next; + continue; + } + pNode = pNode.next; + } + */ } - // 可重复删除指定value的代码 - /* - if (head != null && head.data == value) { - head = head.next; + public void printAll() { + Node p = head; + while (p != null) { + System.out.print(p.data + " "); + p = p.next; + } + System.out.println(); } - Node pNode = head; - while (pNode != null) { - if (pNode.next.data == data) { - pNode.next = pNode.next.next; - continue; - } - pNode = pNode.next; + //判断true or false + public boolean TFResult(Node left, Node right){ + Node l = left; + Node r = right; + + System.out.println("left_:"+l.data); + System.out.println("right_:"+r.data); + while(l != null && r != null){ + if (l.data == r.data){ + l = l.next; + r = r.next; + continue; + }else{ + break; + } + + } + + System.out.println("什么结果"); + if (l==null && r==null){ + System.out.println("什么结果"); + return true; + }else{ + return false; + } } - */ - } + // 判断是否为回文 - public void printAll() { - Node p = head; - while (p != null) { - System.out.print(p.data + " "); - p = p.next; - } - System.out.println(); - } + public boolean palindrome(){ + if (head == null){ + return false; + }else{ + System.out.println("开始执行找到中间节点"); + Node p = head; + Node q = head; + if (p.next == null){ + System.out.println("只有一个元素"); + return true; + } + while( q.next != null && q.next.next != null){ + p = p.next; + q = q.next.next; - public static Node createNode(int value) { - return new Node(value, null); - } + } - public static class Node { - private int data; - private Node next; + System.out.println("中间节点" + p.data); + System.out.println("开始执行奇数节点的回文判断"); + Node leftLink = null; + Node rightLink = null; + if(q.next == null){ + // p 一定为整个链表的中点,且节点数目为奇数 + leftLink = inverseLinkList(p); + System.out.println("左边第一个节点"+leftLink.data); + System.out.println("右边第一个节点"+p.next.data); + rightLink = p; - public Node(int data, Node next) { - this.data = data; - this.next = next; + }else{ + //p q 均为中点 + leftLink = inverseLinkList(p); + rightLink = q; + } + return TFResult(leftLink, rightLink); + + } } - public int getData() { - return data; + //带结点的链表翻转 + public Node inverseLinkList_head(Node p){ + // Head 为新建的一个头结点 + Node Head = new Node(9999,null); + // p 为原来整个链表的头结点,现在Head指向 整个链表 + Head.next = p; + /* + 带头结点的链表翻转等价于 + 从第二个元素开始重新头插法建立链表 + */ + Node Cur = p.next; + p.next = null; + Node next = null; + + while(Cur != null){ + next = Cur.next; + Cur.next = Head.next; + Head.next = Cur; + System.out.println("first " + Head.data); + + Cur = next; + } + + // 返回左半部分的中点之前的那个节点 + // 从此处开始同步像两边比较 + return Head; + + } + + //无头结点的链表翻转 + public Node inverseLinkList(Node p){ + + Node pre = null; + Node r = head; + System.out.println("z---" + r.data); + Node next= null; + while(r !=p){ + next = r.next; + + r.next = pre; + pre = r; + r = next; + } + + r.next = pre; + // 返回左半部分的中点之前的那个节点 + // 从此处开始同步像两边比较 + return r; + + } + + public static Node createNode(int value) { + return new Node(value, null); + } + + public static class Node { + private int data; + private Node next; + + public Node(int data, Node next) { + this.data = data; + this.next = next; + } + + public int getData() { + return data; + } + } + public static void main(String[]args){ + + SinglyLinkedList link = new SinglyLinkedList(); + System.out.println("hello"); + //int data[] = {1}; + //int data[] = {1,2,3,1}; + int data[] = {1,2,4,5}; + //int data[] = {1,2,2,1}; + //int data[] = {1,2,5,2,1}; + + for(int i =0; i < data.length; i++){ + //link.insertToHead(data[i]); + link.insertTail(data[i]); + } + link.printAll(); + Node p = link.inverseLinkList_head(link.head); + while(p != null){ + System.out.println("aa"+p.data); + p = p.next; + } + + //System.out.println("打印原始:"); + //link.printAll(); + //if (link.palindrome()){ + // System.out.println("回文"); + //}else{ + // System.out.println("不是回文"); + //} } - } } From 35b9932a33afd6f3d54a4f1fedfb256864e71ae9 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Wed, 7 Nov 2018 08:28:26 +0800 Subject: [PATCH 083/141] add by jinshaohui for list hash --- c-cpp/18_hash/listhash/listhash.c | 350 ++++++++++++++++++++++++++++++ c-cpp/18_hash/listhash/listhash.h | 53 +++++ 2 files changed, 403 insertions(+) create mode 100644 c-cpp/18_hash/listhash/listhash.c create mode 100755 c-cpp/18_hash/listhash/listhash.h diff --git a/c-cpp/18_hash/listhash/listhash.c b/c-cpp/18_hash/listhash/listhash.c new file mode 100644 index 0000000..cf36a95 --- /dev/null +++ b/c-cpp/18_hash/listhash/listhash.c @@ -0,0 +1,350 @@ +/************************************************************************* + > File Name: listhash.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-07 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include"listhash.h" + + +hashtab * hashtab_create(int size,hash_key_func hash_value, + keycmp_func keycmp,hash_node_free_func hash_node_free) +{ + hashtab * h = NULL; + int i = 0; + + if ((size < 0) || (hash_value == NULL) || (keycmp == NULL)) + { + return NULL; + } + + h = (hashtab *)malloc(sizeof(hashtab)); + if (h == NULL) + { + return NULL; + } + + h->htables = (hashtab_node **)malloc(size * sizeof(hashtab_node*)); + if (h->htables == NULL) + { + return NULL; + } + + h->size = size; + h->nel = 0; + h->hash_value = hash_value; + h->keycmp = keycmp; + h->hash_node_free = hash_node_free; + + for (i = 0; i < size; i++) + { + h->htables[i] = NULL; + } + + return h; +} + +void hashtab_destory(hashtab *h) +{ + int i = 0; + hashtab_node * cur = NULL; + hashtab_node * tmp = NULL; + + if (h == NULL) + { + return; + } + + for (i = 0; i size; i++) + { + cur = h->htables[i]; + while (cur != NULL) + { + tmp = cur; + cur = cur->next; + h->hash_node_free(tmp); + } + h->htables[i] = NULL; + } + + free(h); + return; +} + +int hashtab_insert(hashtab * h,void *key,void *data) +{ + unsigned int hvalue = 0; + int i = 0; + hashtab_node *cur = NULL; + hashtab_node *prev = NULL; + hashtab_node *newnode = NULL; + + if ((h == NULL) || (key == NULL) || (data == NULL)) + { + return 1; + } + + /*获取hash 数值*/ + hvalue = h->hash_value(h,key); + cur = h->htables[hvalue]; + /*hash桶中元素是从小到大排列的,找到要插入的位置*/ + while((cur != NULL) && (h->keycmp(h,key,cur->key) > 0)) + { + prev = cur; + cur = cur->next; + } + + /*如果key和当前key比对一致,直接返回,数据已经存在*/ + if ((cur != NULL) && (h->keycmp(h,key,cur->key) == 0)) + { + return 2; + } + + newnode = (hashtab_node *)malloc(sizeof(hashtab_node)); + if (newnode == NULL) + { + return 3; + } + + newnode->key = key; + newnode->data = data; + if (prev == NULL) + { + newnode->next = h->htables[hvalue]; + h->htables[hvalue] = newnode; + } + else + { + newnode->next = prev->next; + prev->next = newnode; + } + + h->nel++; + return 0; +} + +hashtab_node *hashtab_delete(hashtab *h, void *key) +{ + int hvalue = 0; + int i = 0; + hashtab_node *cur = NULL; + hashtab_node *prev = NULL; + + if ((h == NULL) || (key == NULL)) + { + return NULL; + } + + /*获取hash 数值*/ + hvalue = h->hash_value(h,key); + cur = h->htables[hvalue]; + /*hash桶中元素是从小到大排列的,找到要插入的位置*/ + while((cur != NULL) && (h->keycmp(h,key,cur->key) >= 0)) + { + if (h->keycmp(h,key,cur->key) == 0) + { + if (prev == NULL) + { + h->htables[hvalue] = cur->next; + } + else + { + prev->next = cur->next; + } + return cur; + } + prev = cur; + cur = cur->next; + } + + return NULL; +} + +void *hashtab_search(hashtab*h,void *key) +{ + int hvalue = 0; + int i = 0; + hashtab_node *cur = NULL; + + if ((h == NULL) || (key == NULL)) + { + return NULL; + } + + /*获取hash 数值*/ + hvalue = h->hash_value(h,key); + cur = h->htables[hvalue]; + /*hash桶中元素是从小到大排列的,找到要插入的位置*/ + while((cur != NULL) && (h->keycmp(h,key,cur->key) >= 0)) + { + if (h->keycmp(h,key,cur->key) == 0) + { + return cur->data; + } + cur = cur->next; + } + + return NULL; +} + +void hashtab_dump(hashtab *h) +{ + int i = 0; + hashtab_node * cur = NULL; + + if (h == NULL) + { + return ; + } + + printf("\r\n----开始--size[%d],nel[%d]------------",h->size,h->nel); + for( i = 0; i < h->size; i ++) + { + printf("\r\n htables[%d]:",i); + cur = h->htables[i]; + while((cur != NULL)) + { + printf("key[%s],data[%s] ",cur->key,cur->data); + cur = cur->next; + } + } + + printf("\r\n----结束--size[%d],nel[%d]------------",h->size,h->nel); +} + +struct test_node +{ + char key[80]; + char data[80]; +}; + +unsigned int siample_hash(const char *str) +{ + register unsigned int hash = 0; + register unsigned int seed = 131; + + while(*str) + { + hash = hash*seed + *str++; + } + + return hash & (0x7FFFFFFF); +} + +int hashtab_hvalue(hashtab *h,const void *key) +{ + return (siample_hash(key) % h->size); +} + +int hashtab_keycmp(hashtab *h,const void *key1,const void *key2) +{ + return strcmp(key1,key2); +} + +void hashtab_node_free(hashtab_node*node) +{ + struct test_node * ptmp = NULL; + + ptmp = container(node->key,struct test_node,key); + + free(ptmp); +} + +int main () +{ + + int i = 0; + int res = 0; + char *pres = NULL; + hashtab_node * node = NULL; + struct test_node *p = NULL; + hashtab *h = NULL; + + h = hashtab_create(5,hashtab_hvalue,hashtab_keycmp,hashtab_node_free); + assert(h!= NULL); + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 和value,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + scanf("%s",p->data); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + + res = hashtab_insert(h,p->key,p->data); + if (res != 0) + { + printf("\r\n key[%s],data[%s] insert failed %d",p->key,p->data,res); + } + else + { + printf("\r\n key[%s],data[%s] insert success %d",p->key,p->data,res); + } + } + + hashtab_dump(h); + + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 查询value的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + pres = hashtab_search(h,p->key); + if (pres == NULL) + { + printf("\r\n key[%s] search data failed",p->key); + } + else + { + printf("\r\n key[%s],search data[%s] success",p->key,pres); + } + free(p); + } + hashtab_dump(h); + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 删除节点的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + node = hashtab_delete(h,p->key); + if (node == NULL) + { + printf("\r\n key[%s] delete node failed ",p->key); + } + else + { + printf("\r\n key[%s],delete data[%s] success",node->key,node->data); + h->hash_node_free(node); + } + free(p); + hashtab_dump(h); + } + + hashtab_destory(h); + return 0; + +} diff --git a/c-cpp/18_hash/listhash/listhash.h b/c-cpp/18_hash/listhash/listhash.h new file mode 100755 index 0000000..2e42ada --- /dev/null +++ b/c-cpp/18_hash/listhash/listhash.h @@ -0,0 +1,53 @@ +/************************************************************************* + > File Name: listhash.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-06 + > Desc: 根据linux内核模块hashtab编写用户层hashtab接口 + linux-4.19.1\security\selinux\ss\hashtab.c + linux-4.19.1\security\selinux\ss\hashtab.h + ************************************************************************/ + + +#ifndef __HASHTAB_H__ +#define __HASHTAB_H__ + + +typedef struct _hashtab_node +{ + void * key; + void * data; + struct _hashtab_node *next; +}hashtab_node; + +typedef struct _hashtab +{ + hashtab_node **htables; /*哈希桶*/ + int size; /*哈希桶的最大数量*/ + int nel; /*哈希桶中元素的个数*/ + int (*hash_value)(struct _hashtab *h,const void *key); /*哈希函数*/ + int (*keycmp)(struct _hashtab *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ + void (*hash_node_free)(hashtab_node *node); +}hashtab; + + +#define HASHTAB_MAX_NODES (0xffffffff) + +typedef int (*hash_key_func)(struct _hashtab *h,const void *key); /*哈希函数*/ +typedef int (*keycmp_func)(struct _hashtab *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ +typedef void (*hash_node_free_func)(hashtab_node *node); +/*根据当前结构体元素的地址,获取到结构体首地址*/ +#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container(ptr,type,member) ({\ + const typeof( ((type *)0)->member) *__mptr = (ptr);\ + (type *) ( (char *)__mptr - offsetof(type,member));}) + + +hashtab * hashtab_create(int size,hash_key_func hash_value, + keycmp_func keycmp,hash_node_free_func hash_node_free); +void hashtab_destory(hashtab *h); +int hashtab_insert(hashtab * h,void *key,void *data); +hashtab_node *hashtab_delete(hashtab *h, void *key); +void *hashtab_search(hashtab*h,void *key); + +#endif From 5ac4ef47cd2f691bfc2201d017465c9f0b1e2609 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Wed, 7 Nov 2018 20:58:55 -0500 Subject: [PATCH 084/141] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E5=86=85=E5=AD=98=E6=B3=84=E6=BC=8F=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E3=80=82=20=E4=BD=BF=E7=94=A8mtrace=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c-cpp/18_hash/listhash/listhash.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/c-cpp/18_hash/listhash/listhash.c b/c-cpp/18_hash/listhash/listhash.c index cf36a95..395590c 100644 --- a/c-cpp/18_hash/listhash/listhash.c +++ b/c-cpp/18_hash/listhash/listhash.c @@ -11,6 +11,9 @@ #include #include"listhash.h" +#ifdef MEMORY_TEST +#include +#endif hashtab * hashtab_create(int size,hash_key_func hash_value, keycmp_func keycmp,hash_node_free_func hash_node_free) @@ -71,7 +74,8 @@ void hashtab_destory(hashtab *h) } h->htables[i] = NULL; } - + + free(h->htables); free(h); return; } @@ -92,6 +96,7 @@ int hashtab_insert(hashtab * h,void *key,void *data) /*获取hash 数值*/ hvalue = h->hash_value(h,key); cur = h->htables[hvalue]; + /*hash桶中元素是从小到大排列的,找到要插入的位置*/ while((cur != NULL) && (h->keycmp(h,key,cur->key) > 0)) { @@ -253,6 +258,7 @@ void hashtab_node_free(hashtab_node*node) ptmp = container(node->key,struct test_node,key); free(ptmp); + free(node); } int main () @@ -264,6 +270,10 @@ int main () hashtab_node * node = NULL; struct test_node *p = NULL; hashtab *h = NULL; + #ifdef MEMORY_TEST + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + #endif h = hashtab_create(5,hashtab_hvalue,hashtab_keycmp,hashtab_node_free); assert(h!= NULL); @@ -284,6 +294,7 @@ int main () res = hashtab_insert(h,p->key,p->data); if (res != 0) { + free(p); printf("\r\n key[%s],data[%s] insert failed %d",p->key,p->data,res); } else @@ -345,6 +356,9 @@ int main () } hashtab_destory(h); + #ifdef MEMORY_TEST + muntrace(); + #endif return 0; } From e53868b78d98ebcbc39960414189a4db91b4c55c Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Wed, 7 Nov 2018 23:49:16 -0500 Subject: [PATCH 085/141] =?UTF-8?q?=E5=AE=9E=E7=8E=B0hash=E8=A1=A8=20=20?= =?UTF-8?q?=E5=8F=8C=E5=90=91=E9=93=BE=E8=A1=A8=20LRU=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c-cpp/19_Dlisthash/Dlist.h | 114 +++++++++ c-cpp/19_Dlisthash/LinkedHashMap.c | 397 +++++++++++++++++++++++++++++ c-cpp/19_Dlisthash/LinkedHashMap.h | 39 +++ 3 files changed, 550 insertions(+) create mode 100755 c-cpp/19_Dlisthash/Dlist.h create mode 100644 c-cpp/19_Dlisthash/LinkedHashMap.c create mode 100644 c-cpp/19_Dlisthash/LinkedHashMap.h diff --git a/c-cpp/19_Dlisthash/Dlist.h b/c-cpp/19_Dlisthash/Dlist.h new file mode 100755 index 0000000..a95d2f3 --- /dev/null +++ b/c-cpp/19_Dlisthash/Dlist.h @@ -0,0 +1,114 @@ +/************************************************************************* + > File Name: Dlist.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-08 + > Desc: linux内核源码双向链表实现include/linux/list.h + ************************************************************************/ +#ifndef _LIST_HEAD_H +#define _LIST_HEAD_H + +// 双向链表节点 +struct list_head { + struct list_head *next, *prev; +}; + +// 初始化节点:设置name节点的前继节点和后继节点都是指向name本身。 +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +// 定义表头(节点):新建双向链表表头name,并设置name的前继节点和后继节点都是指向name本身。 +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +// 初始化节点:将list节点的前继节点和后继节点都是指向list本身。 +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +// 添加节点:将new插入到prev和next之间。 +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +// 添加new节点:将new添加到head之后,是new称为head的后继节点。 +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +// 添加new节点:将new添加到head之前,即将new添加到双链表的末尾。 +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +// 从双链表中删除entry节点。 +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +// 从双链表中删除entry节点。 +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +// 从双链表中删除entry节点。 +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +// 从双链表中删除entry节点,并将entry节点的前继节点和后继节点都指向entry本身。 +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +// 用new节点取代old节点 +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +// 双链表是否为空 +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +// 获取"MEMBER成员"在"结构体TYPE"中的位置偏移 +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +// 根据"结构体(type)变量"中的"域成员变量(member)的指针(ptr)"来获取指向整个结构体变量的指针 +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +// 遍历双向链表 +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#endif diff --git a/c-cpp/19_Dlisthash/LinkedHashMap.c b/c-cpp/19_Dlisthash/LinkedHashMap.c new file mode 100644 index 0000000..d0efbde --- /dev/null +++ b/c-cpp/19_Dlisthash/LinkedHashMap.c @@ -0,0 +1,397 @@ +/************************************************************************* + > File Name: LinkedHashMap.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-08 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include "Dlist.h" +#include "LinkedHashMap.h" + + +LinkedHashMap *LinkedHashMap_Create(int size,int nel_max, + hash_value_func hash_value,keycmp_func keycmp, + hash_node_free_func hash_node_free) +{ + int i = 0; + LinkedHashMap *h = NULL; + + if ((size <= 0) || (hash_value == NULL) || (keycmp == NULL)) + { + return NULL; + } + + h = (LinkedHashMap *)malloc(sizeof(LinkedHashMap)); + if (h == NULL) + { + return NULL; + } + + h->hTabs = (LiskedHashMapNode**)malloc(sizeof(LiskedHashMapNode*) *size); + if (h->hTabs == NULL) + { + return NULL; + } + h->size = size; + h->nel = 0; + h->nel_max = nel_max; + h->hash_value = hash_value; + h->keycmp = keycmp; + h->hash_node_free = hash_node_free; + + for (i = 0; i < size; i++) + { + h->hTabs[i] = NULL; + } + + INIT_LIST_HEAD(&(h->header)); + + return h; +} + +void LinkedHashMap_destory(LinkedHashMap *h) +{ + struct list_head * pos = NULL; + struct list_head * next = NULL; + LiskedHashMapNode * ptmp = NULL; + + if (h == NULL) + { + return; + } + + list_for_each_safe(pos,next,&h->header) + { + ptmp = container_of(pos,LiskedHashMapNode,Dlist_node); + /*从双向链表中删除*/ + list_del_init(pos); + if (h->hash_node_free != NULL) + { + h->hash_node_free(ptmp,1); + } + } + + free(h->hTabs); + free(h); + + return; +} + +int LinkedHashMap_insert(LinkedHashMap *h,void *key,void *data) +{ + int i = 0; + int hPos = 0; + struct list_head *pos = NULL; + LiskedHashMapNode *cur = NULL; + LiskedHashMapNode *prev = NULL; + + hPos = h->hash_value(h,key); + cur = h->hTabs[hPos]; + while((cur != NULL)&& (h->keycmp(h,key,cur->key) != 0)) + { + prev = cur; + cur = cur->next; + } + + if(cur == NULL) + { + /*链表节点满时,取*/ + if(h->nel_max == h->nel) + { + cur = LinkedHashMap_delete(h,list_entry(h->header.next,LiskedHashMapNode,Dlist_node)->key); + + assert(cur != NULL); + h->hash_node_free(cur,0); + } + else/*链表不满时*/ + { + cur = (LiskedHashMapNode *)malloc(sizeof(LiskedHashMapNode)); + if (cur == NULL) + { + return 1; + + } + } + /*插入到hash桶中*/ + if(prev == NULL) + { + cur->next = h->hTabs[hPos]; + h->hTabs[hPos] = cur; + } + else + { + cur->next = prev->next; + prev->next= cur; + } + h->nel++; + } + else + { + /*从双向链表中删除*/ + list_del_init(&(cur->Dlist_node)); + /*只删除key 和data的内存*/ + h->hash_node_free(cur,0); + } + + /*赋值*/ + cur->key = key; + cur->data = data; + + + /*加的双向链表尾部*/ + list_add_tail(&(cur->Dlist_node),&(h->header)); + + return 0; +} + +LiskedHashMapNode * LinkedHashMap_delete(LinkedHashMap *h,void *key) +{ + int hPos = 0; + struct list_head *pos = NULL; + LiskedHashMapNode *cur = NULL; + LiskedHashMapNode *prev = NULL; + + /*查找当前节点*/ + hPos = h->hash_value(h,key); + cur = h->hTabs[hPos]; + while((cur != NULL)&& (h->keycmp(h,key,cur->key) != 0)) + { + prev = cur; + cur = cur->next; + } + + if (cur == NULL) + { + return NULL; + } + + /*从哈希桶中删除*/ + if(prev == NULL) + { + h->hTabs[hPos] = cur->next; + } + else + { + prev->next = cur->next; + } + + /*从双向链表中删除*/ + list_del_init(&(cur->Dlist_node)); + h->nel--; + + return cur; +} + +void *LinkedHashMap_search(LinkedHashMap *h,void *key) +{ + int hPos = 0; + LiskedHashMapNode *cur = NULL; + + /*查找当前节点*/ + hPos = h->hash_value(h,key); + cur = h->hTabs[hPos]; + while((cur != NULL)&& (h->keycmp(h,key,cur->key) != 0)) + { + cur = cur->next; + } + + if (cur == NULL) + { + return NULL; + } + + /*从双向链表中删除节点,加入尾部*/ + if (h->header.prev != &(cur->Dlist_node)) + { + list_del_init(&(cur->Dlist_node)); + list_add_tail(&(cur->Dlist_node),&(h->header)); + } + + return cur->data; +} + +void LinkedHashMap__dump(LinkedHashMap *h) +{ + int i = 0; + LiskedHashMapNode * cur = NULL; + struct list_head *pos = NULL; + + if (h == NULL) + { + return ; + } + + printf("\r\n----开始--size[%d],nel[%d]------------",h->size,h->nel); + for( i = 0; i < h->size; i ++) + { + printf("\r\n htables[%d]:",i); + cur = h->hTabs[i]; + while((cur != NULL)) + { + printf("key[%s],data[%s] ",cur->key,cur->data); + cur = cur->next; + } + } + + printf("\r\n--------------------------------------------------------\r\n"); + + list_for_each(pos,&(h->header)) + { + cur = list_entry(pos,LiskedHashMapNode,Dlist_node); + printf("key[%s] ",cur->key); + + } + + printf("\r\n----结束--size[%d],nel[%d]------------",h->size,h->nel); +} + + + + + +struct test_node +{ + char key[80]; + char data[80]; +}; + +unsigned int siample_hash(const char *str) +{ + register unsigned int hash = 0; + register unsigned int seed = 131; + + while(*str) + { + hash = hash*seed + *str++; + } + + return hash & (0x7FFFFFFF); +} + +int hashtab_hvalue(LinkedHashMap *h,const void *key) +{ + return (siample_hash(key) % h->size); +} + +int hashtab_keycmp(LinkedHashMap *h,const void *key1,const void *key2) +{ + return strcmp(key1,key2); +} + +void hashtab_node_free(LiskedHashMapNode *node,int flg) +{ + struct test_node * ptmp = NULL; + + ptmp = list_entry(node->key,struct test_node,key); + + free(ptmp); + if (flg) + { + free(node); + } +} + + +int main () +{ + + int i = 0; + int res = 0; + char *pres = NULL; + LiskedHashMapNode * node = NULL; + struct test_node *p = NULL; + LinkedHashMap *h = NULL; + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + + h = LinkedHashMap_Create(3,6,hashtab_hvalue,hashtab_keycmp,hashtab_node_free); + assert(h!= NULL); + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 和value,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + scanf("%s",p->data); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + + res = LinkedHashMap_insert(h,p->key,p->data); + if (res != 0) + { + free(p); + printf("\r\n key[%s],data[%s] insert failed %d",p->key,p->data,res); + } + else + { + printf("\r\n key[%s],data[%s] insert success %d",p->key,p->data,res); + } + LinkedHashMap__dump(h); + } + + + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 查询value的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + pres = LinkedHashMap_search(h,p->key); + if (pres == NULL) + { + printf("\r\n key[%s] search data failed",p->key); + } + else + { + printf("\r\n key[%s],search data[%s] success",p->key,pres); + } + free(p); + LinkedHashMap__dump(h); + } + + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 删除节点的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + node = LinkedHashMap_delete(h,p->key); + if (node == NULL) + { + printf("\r\n key[%s] delete node failed ",p->key); + } + else + { + printf("\r\n key[%s],delete data[%s] success",node->key,node->data); + h->hash_node_free(node,1); + } + free(p); + LinkedHashMap__dump(h); + } + + LinkedHashMap_destory(h); + muntrace(); + return 0; + +} + diff --git a/c-cpp/19_Dlisthash/LinkedHashMap.h b/c-cpp/19_Dlisthash/LinkedHashMap.h new file mode 100644 index 0000000..9c2622c --- /dev/null +++ b/c-cpp/19_Dlisthash/LinkedHashMap.h @@ -0,0 +1,39 @@ +/************************************************************************* + > File Name: LinkedHashMap.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-08 + > Desc: + ************************************************************************/ + + +#ifndef __LINKED_HASH_MAP__ +#define __LINKED_HASH_MAP__ + +typedef struct _lisked_hash_map_node +{ + void *key; + void *data; + struct _lisked_hash_map_node *next; + struct list_head Dlist_node; +}LiskedHashMapNode; + +typedef struct _lisked_hash_map +{ + LiskedHashMapNode **hTabs;/*哈希桶*/ + struct list_head header;/*双向循环链表头*/ + int size; + int nel_max; + int nel; + int (*hash_value)(struct _lisked_hash_map *h,const void *key); /*哈希函数*/ + int (*keycmp)(struct _lisked_hash_map *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ + void (*hash_node_free)(LiskedHashMapNode *node,int flg); + +}LinkedHashMap; + +typedef int (*hash_value_func)(struct _lisked_hash_map *h,const void *key); /*哈希函数*/ +typedef int (*keycmp_func)(struct _lisked_hash_map *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ +typedef void (*hash_node_free_func)(LiskedHashMapNode *node,int flg); + +LiskedHashMapNode * LinkedHashMap_delete(LinkedHashMap *h,void *key); +#endif From 2eb9a2708665da692596a7d4fef6b635e2ac3672 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Thu, 8 Nov 2018 07:37:44 -0500 Subject: [PATCH 086/141] 111 --- c-cpp/19_Dlisthash/LinkedHashMap.c | 5 +++-- c-cpp/19_Dlisthash/LinkedHashMap.h | 17 +++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) mode change 100644 => 100755 c-cpp/19_Dlisthash/LinkedHashMap.c mode change 100644 => 100755 c-cpp/19_Dlisthash/LinkedHashMap.h diff --git a/c-cpp/19_Dlisthash/LinkedHashMap.c b/c-cpp/19_Dlisthash/LinkedHashMap.c old mode 100644 new mode 100755 index d0efbde..e1ec182 --- a/c-cpp/19_Dlisthash/LinkedHashMap.c +++ b/c-cpp/19_Dlisthash/LinkedHashMap.c @@ -99,15 +99,16 @@ int LinkedHashMap_insert(LinkedHashMap *h,void *key,void *data) if(cur == NULL) { - /*链表节点满时,取*/ + /*链表节点满时,取表头节点,从当前哈希表和双向链表中都删除*/ if(h->nel_max == h->nel) { cur = LinkedHashMap_delete(h,list_entry(h->header.next,LiskedHashMapNode,Dlist_node)->key); assert(cur != NULL); + /*释放节点key 和data的内容*/ h->hash_node_free(cur,0); } - else/*链表不满时*/ + else/*链表不满时,创建新的节点*/ { cur = (LiskedHashMapNode *)malloc(sizeof(LiskedHashMapNode)); if (cur == NULL) diff --git a/c-cpp/19_Dlisthash/LinkedHashMap.h b/c-cpp/19_Dlisthash/LinkedHashMap.h old mode 100644 new mode 100755 index 9c2622c..e61b8fc --- a/c-cpp/19_Dlisthash/LinkedHashMap.h +++ b/c-cpp/19_Dlisthash/LinkedHashMap.h @@ -10,24 +10,25 @@ #ifndef __LINKED_HASH_MAP__ #define __LINKED_HASH_MAP__ +/*数据存放节点*/ typedef struct _lisked_hash_map_node { - void *key; - void *data; - struct _lisked_hash_map_node *next; - struct list_head Dlist_node; + void *key; /*键*/ + void *data; /*数据*/ZZ + struct _lisked_hash_map_node *next; /*哈希冲突时,用来挂接后续节点*/ + struct list_head Dlist_node;/*用来挂接双向链表*/ }LiskedHashMapNode; typedef struct _lisked_hash_map { LiskedHashMapNode **hTabs;/*哈希桶*/ struct list_head header;/*双向循环链表头*/ - int size; - int nel_max; - int nel; + int size; /**/ + int nel_max; /*支持最大节点数*/ + int nel; /*当前节点数*/ int (*hash_value)(struct _lisked_hash_map *h,const void *key); /*哈希函数*/ int (*keycmp)(struct _lisked_hash_map *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ - void (*hash_node_free)(LiskedHashMapNode *node,int flg); + void (*hash_node_free)(LiskedHashMapNode *node,int flg);/*用来释放节点内存*/ }LinkedHashMap; From 671084417f819e30fb6a9ddea6c641a0b94577b9 Mon Sep 17 00:00:00 2001 From: puhuaqiang Date: Fri, 9 Nov 2018 11:07:10 +0800 Subject: [PATCH 087/141] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=B7=B3=E8=A1=A8C++?= =?UTF-8?q?=E7=89=88=E6=9C=AC.=E7=BF=BB=E8=AF=91=E6=9D=A5=E6=BA=90JAVA?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c-cpp/17_skiplist/SkipList.cpp | 363 +++++++++++++++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 c-cpp/17_skiplist/SkipList.cpp diff --git a/c-cpp/17_skiplist/SkipList.cpp b/c-cpp/17_skiplist/SkipList.cpp new file mode 100644 index 0000000..ffef260 --- /dev/null +++ b/c-cpp/17_skiplist/SkipList.cpp @@ -0,0 +1,363 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +/** + * һʵַ + * д洢Ҵ洢Dzظġ + * + * C++汾. + * JAVA汾 ԭ AuthorZHENG + * + * Authorpuhuaqiang + * + * ṹ: + * + * K 1 9 + * K-1 1 5 9 + * K-2 1 3 5 7 9 + * ... .... + * 0(ԭʼ) 1 2 3 4 5 6 7 8 9 + */ + +const int MAX_LEVEL = 16; + +/** + * @brief ڵ +*/ +class CNode +{ +public: + CNode(); + ~CNode(); + + std::string toString(); + /** + * @brief ȡ + */ + CNode** GetIdxList(); + + /** + * @brief + */ + void SetData(int v); + /** + * @brief ȡ + */ + int GetData(); + /** + * @brief + */ + void SetLevel(int l); +private: + /**ǰڵֵ*/ + int m_data; + /** + * ǰڵÿȼһڵ. + * 2 N1 N2 + * 1 N1 N2 + * N1DZڵ, m_lpForwards[x] N2 + * + * [0] ԭʼ. + */ + CNode* m_lpForwards[MAX_LEVEL]; + /**ǰڵڵ*/ + int m_iMaxLevel; +}; + +/** + * @brief +*/ +class CSkipList +{ +public: + CSkipList(); + ~CSkipList(); + /** + * @brief ֵָĽڵ + * @param v + */ + CNode* Find(int v); + /** + * @brief ֵָ + * @param v + */ + void Insert(int v); + /** + * @brief ɾֵָĽڵ + * @param v + */ + int Delete(int v); + void PrintAll(); + /** + * @brief ӡṹ + * @param l -1ʱӡмĽṹ >=0ʱӡָĽṹ + */ + void PrintAll(int l); + /** + * @brief ڵʱ,õK + * @return K + */ + int RandomLevel(); + +private: + int levelCount; + /** + * + * ͷ/(ڵ) + */ + CNode* m_lpHead; +}; + +int main() +{ + CSkipList skipList; + /// ԭʼֵ + for(int i=1; i< 50; i++){ + if((i%3) == 0){ + skipList.Insert(i); + } + } + for(int i=1; i< 50; i++){ + if((i%3) == 1){ + skipList.Insert(i); + } + } + skipList.PrintAll(); + std::cout<GetData()< k-1 -> k-2 ...->0 + */ + for(int i=levelCount-1; i>=0; --i){ + /** + * СvĽڵ(lpNode). + */ + while((NULL != lpNode->GetIdxList()[i]) && (lpNode->GetIdxList()[i]->GetData() < v)){ + lpNode = lpNode->GetIdxList()[i]; + } + } + /** + * lpNode СvĽڵ, lpNodeһڵ͵ڻvĽڵ + */ + if((NULL != lpNode->GetIdxList()[0]) && (lpNode->GetIdxList()[0]->GetData() == v)){ + return lpNode->GetIdxList()[0]; + } + return NULL; +} +void CSkipList::Insert(int v) +{ + /// ½ڵ + CNode* lpNewNode = new CNode(); + if(NULL == lpNewNode){ + return; + } + + /** + * ½ڵֲڵ + * 3, µĽڵ123ϵ + */ + int level = RandomLevel(); + lpNewNode->SetData(v); + lpNewNode->SetLevel(level); + + /** + * ʱ + * ҪǵõµĽڵÿϵλ + */ + CNode *lpUpdateNode[level]; + for(int i=0; i= 0; --i){ + /** + * λ + * eg. 1 1 7 10 + * 6 + * lpFind->GetIdxList()[i]->GetData() : ʾڵlpFindڵ1һڵ + * "lpFind->GetIdxList()[i]->GetData() < v"ʱ, + * ½ڵҪ뵽 lpFindڵĺ, lpFind->GetIdxList()[i] ڵǰ + * lpFind1 lpFind->GetIdxList()[i] 7 + */ + while((NULL != lpFind->GetIdxList()[i]) && (lpFind->GetIdxList()[i]->GetData() < v)){ + lpFind = lpFind->GetIdxList()[i]; + } + /// lpFind ½ڵ iĺһڵ + lpUpdateNode[i] = lpFind; + } + + for(int i=0; iGetIdxList()[i]ڵ7 + * + * 2 6 17֮ + */ + lpNewNode->GetIdxList()[i] = lpUpdateNode[i]->GetIdxList()[i]; + lpUpdateNode[i]->GetIdxList()[i] = lpNewNode; + } + if(levelCount < level){ + levelCount = level; + } +} +int CSkipList::Delete(int v) +{ + int ret = -1; + CNode *lpUpdateNode[levelCount]; + CNode *lpFind = m_lpHead; + for(int i=levelCount-1; i>= 0; --i){ + /** + * СvĽڵ(lpFind). + */ + while((NULL != lpFind->GetIdxList()[i]) && (lpFind->GetIdxList()[i]->GetData() < v)){ + lpFind = lpFind->GetIdxList()[i]; + } + lpUpdateNode[i] = lpFind; + } + /** + * lpFind СvĽڵ, lpFindһڵ͵ڻvĽڵ + */ + if((NULL != lpFind->GetIdxList()[0]) && (lpFind->GetIdxList()[0]->GetData() == v)){ + for(int i=levelCount-1; i>=0; --i){ + if((NULL != lpUpdateNode[i]->GetIdxList()[i]) && (v == lpUpdateNode[i]->GetIdxList()[i]->GetData())){ + lpUpdateNode[i]->GetIdxList()[i] = lpUpdateNode[i]->GetIdxList()[i]->GetIdxList()[i]; + ret = 0; + } + } + } + return ret; +} +void CSkipList::PrintAll() +{ + CNode* lpNode = m_lpHead; + while(NULL != lpNode->GetIdxList()[0]){ + std::cout<GetIdxList()[0]->toString().data()<GetIdxList()[0]; + } +} +void CSkipList::PrintAll(int l) +{ + for(int i=MAX_LEVEL-1; i>=0;--i){ + CNode* lpNode = m_lpHead; + std::cout<<""<= 0) && (l == i))){ + while(NULL != lpNode->GetIdxList()[i]){ + std::cout<GetIdxList()[i]->GetData()<<" "; + lpNode = lpNode->GetIdxList()[i]; + } + std::cout<= 0){ + break; + } + } + } +} +int GetRandom() +{ + static int _count = 1; + std::default_random_engine generator(time(0) + _count); + std::uniform_int_distribution distribution(1,99999/*0x7FFFFFFF*/); + int dice_roll = distribution(generator); + _count += 100; + return dice_roll; +} +int CSkipList::RandomLevel() +{ + int level = 1; + for(int i=1; i Date: Sun, 11 Nov 2018 21:11:42 +0000 Subject: [PATCH 088/141] binary tree traversal in python --- python/23_binarytree/binary_tree.py | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 python/23_binarytree/binary_tree.py diff --git a/python/23_binarytree/binary_tree.py b/python/23_binarytree/binary_tree.py new file mode 100644 index 0000000..dae3973 --- /dev/null +++ b/python/23_binarytree/binary_tree.py @@ -0,0 +1,70 @@ +""" + Pre-order, in-order and post-order traversal of binary trees. + + Author: Wenru Dong +""" +from typing import TypeVar, Generic, Generator, Optional + +T = TypeVar("T") + +class TreeNode(Generic[T]): + def __init__(self, value: T): + self.val = value + self.left = None + self.right = None + + +# Pre-order traversal +def pre_order(root: Optional[TreeNode[T]]) -> Generator[T, None, None]: + if root: + yield root.val + yield from pre_order(root.left) + yield from pre_order(root.right) + +# In-order traversal +def in_order(root: Optional[TreeNode[T]]) -> Generator[T, None, None]: + if root: + yield from in_order(root.left) + yield root.val + yield from in_order(root.right) + +# Post-order traversal +def post_order(root: Optional[TreeNode[T]]) -> Generator[T, None, None]: + if root: + yield from post_order(root.left) + yield from post_order(root.right) + yield root.val + + +if __name__ == "__main__": + + singer = TreeNode("Taylor Swift") + + genre_country = TreeNode("Country") + genre_pop = TreeNode("Pop") + + album_fearless = TreeNode("Fearless") + album_red = TreeNode("Red") + album_1989 = TreeNode("1989") + album_reputation = TreeNode("Reputation") + + song_ls = TreeNode("Love Story") + song_wh = TreeNode("White Horse") + song_wanegbt = TreeNode("We Are Never Ever Getting Back Together") + song_ikywt = TreeNode("I Knew You Were Trouble") + song_sio = TreeNode("Shake It Off") + song_bb = TreeNode("Bad Blood") + song_lwymmd = TreeNode("Look What You Made Me Do") + song_g = TreeNode("Gorgeous") + + singer.left, singer.right = genre_country, genre_pop + genre_country.left, genre_country.right = album_fearless, album_red + genre_pop.left, genre_pop.right = album_1989, album_reputation + album_fearless.left, album_fearless.right = song_ls, song_wh + album_red.left, album_red.right = song_wanegbt, song_ikywt + album_1989.left, album_1989.right = song_sio, song_bb + album_reputation.left, album_reputation.right = song_lwymmd, song_g + + print(list(pre_order(singer))) + print(list(in_order(singer))) + print(list(post_order(singer))) From f41d01589c5da454cb271c6920fc66dd563c644e Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Mon, 12 Nov 2018 10:08:38 +0800 Subject: [PATCH 089/141] binary tree in array --- c-cpp/23_binarytree/binarytree.c | 83 ++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 c-cpp/23_binarytree/binarytree.c diff --git a/c-cpp/23_binarytree/binarytree.c b/c-cpp/23_binarytree/binarytree.c new file mode 100644 index 0000000..4143cd1 --- /dev/null +++ b/c-cpp/23_binarytree/binarytree.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +/* Implement binary tree in array */ + +#define MAX_TREE_NODES (1 << 8) + +struct node { + int data; +}; + +struct binary_tree { + union { + unsigned long nodes; + struct node *n[MAX_TREE_NODES]; + }; +}; + +void init_binary_tree(struct binary_tree *tree) +{ + int i; + + for(i = 0; i < MAX_TREE_NODES; i++) { + tree->n[i] = NULL; + } +} + +struct node* create_node(int data) +{ + struct node* n; + + n = malloc(sizeof(struct node)); + + if (n) + n->data = data; + + return n; +} + +void fake_a_tree(struct binary_tree* tree) +{ + /* data is in ordered */ + int i, data[10] = {7, 4, 9, 2, 6, 8, 10, 1, 3, 5}; + + init_binary_tree(tree); + + /* root start at 1 */ + for (i = 0; i < 10; i++) + tree->n[i+1] = create_node(data[i]); + + tree->nodes = 10; +} + +void _in_order(struct binary_tree* tree, int index) +{ + if (!tree->n[index]) + return; + + /* left child at (index << 1) */ + _in_order(tree, index << 1); + + printf("[%2d]: %4d\n", index, tree->n[index]->data); + + /* right child at (index << 1) + 1 */ + _in_order(tree, (index << 1) + 1); +} + +void in_order(struct binary_tree* tree) +{ + _in_order(tree, 1); +} + +int main() +{ + struct binary_tree tree; + + fake_a_tree(&tree); + in_order(&tree); + return 0; +} From 3aa1b38fb604406729ba59f10c92034375ff42dc Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Mon, 12 Nov 2018 18:26:14 -0500 Subject: [PATCH 090/141] add for binary tree preoreder inorder postoreder levleorder destroy tree ; you can mtrace a.out 1,txt check memory --- c-cpp/23_binarytree/tree/binarytree.c | 213 ++++++++++++++++++++++++++ c-cpp/23_binarytree/tree/list_queue.c | 85 ++++++++++ c-cpp/23_binarytree/tree/list_queue.h | 30 ++++ 3 files changed, 328 insertions(+) create mode 100644 c-cpp/23_binarytree/tree/binarytree.c create mode 100644 c-cpp/23_binarytree/tree/list_queue.c create mode 100644 c-cpp/23_binarytree/tree/list_queue.h diff --git a/c-cpp/23_binarytree/tree/binarytree.c b/c-cpp/23_binarytree/tree/binarytree.c new file mode 100644 index 0000000..8a5e66b --- /dev/null +++ b/c-cpp/23_binarytree/tree/binarytree.c @@ -0,0 +1,213 @@ +/************************************************************************* + > File Name: binarytree.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-12 + > Desc: + ************************************************************************/ +#include + +#include +#include +#include +#include"list_queue.h" + +typedef struct _treenode +{ + int data; + struct _treenode *lchild; + struct _treenode *rchild; +}Tnode,Tree; + +void binarytree_create(Tree **Root) +{ + int a = 0; + printf("\r\n输入节点数值((当输入为100时,当前节点创建完成))):"); + scanf("%d",&a); + + + if (a == 100) + { + *Root = NULL; + } + else + { + *Root = (Tnode *)malloc(sizeof(Tnode)); + if (*Root == NULL) + { + return; + } + + (*Root)->data = a; + printf("\r\n create %d 的左孩子:",a); + binarytree_create(&((*Root)->lchild)); + printf("\r\n create %d 的右孩子:",a); + binarytree_create(&((*Root)->rchild)); + } + + return ; +} + +void binarytree_destory(Tree *root) +{ + if (root == NULL) + { + return; + } + + binarytree_destory(root->lchild); + binarytree_destory(root->rchild); + free(root); +} + +/*先序遍历:根结点--》左子树---》右子树*/ +void binarytree_preorder(Tree *root) +{ + if (root == NULL) + { + return; + } + printf(" %d ",root->data); + binarytree_preorder(root->lchild); + binarytree_preorder(root->rchild); + return; +} +/*中序遍历:左子树--》跟节点---》右子树*/ +void binarytree_inorder(Tree *root) +{ + if (root == NULL) + { + return; + } + binarytree_inorder(root->lchild); + printf(" %d ",root->data); + binarytree_inorder(root->rchild); + return; +} +/*后序遍历:左子树---》右子树-》根节点*/ +void binarytree_postorder(Tree *root) +{ + if (root == NULL) + { + return; + } + binarytree_postorder(root->lchild); + binarytree_postorder(root->rchild); + printf(" %d ",root->data); + return; +} + +void binarytree_levelorder(Tree * root) +{ + list_queue *queue = NULL; + Tnode * node = NULL; + + if(root == NULL) + { + return; + } + + queue = list_queue_create(); + + /*根节点先入队*/ + list_queue_enqueue(queue,(void *)root); + + while(!list_queue_is_empty(queue)) + { + list_queue_dequeue(queue,(void *)&node); + printf(" %d ",node->data); + + if(node->lchild != NULL) + { + list_queue_enqueue(queue,(void *)node->lchild); + } + + if(node->rchild != NULL) + { + list_queue_enqueue(queue,(void *)node->rchild); + } + } + + free(queue); + +} +/*打印叶子节点*/ +void binarytree_printfleaf(Tree *root) +{ + if (root == NULL) + { + return; + } + + if ((root->lchild == NULL) && (root->rchild == NULL)) + { + printf(" %d ",root->data); + } + else + { + binarytree_printfleaf(root->lchild); + binarytree_printfleaf(root->rchild); + } +} +/*打印叶子的个数*/ +int binarytree_getleafnum(Tree*root) +{ + if (root == NULL) + { + return 0; + } + + if ((root->lchild == NULL) && (root->rchild == NULL)) + { + return 1; + } + + return binarytree_getleafnum(root->lchild) + binarytree_getleafnum(root->rchild); + +} +/*打印数的高度*/ +int binarytree_gethigh(Tree *root) +{ + int lhigh = 0; + int rhigh = 0; + + if (root == NULL) + { + return 0; + } + + lhigh = binarytree_gethigh(root->lchild); + rhigh = binarytree_gethigh(root->rchild); + + return ((lhigh > rhigh)?(lhigh + 1):(rhigh + 1)); +} + +int main() +{ + Tree *root = NULL; + + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + + printf("\r\n创建二叉树:"); + binarytree_create(&root); + printf("\r\n先序遍历二叉树:"); + binarytree_preorder(root); + printf("\r\n中序遍历二叉树:"); + binarytree_inorder(root); + printf("\r\n后序遍历二叉树:"); + binarytree_postorder(root); + printf("\r\n层次遍历二叉树:"); + binarytree_levelorder(root); + + printf("\r\n打印二叉树叶子节点:"); + binarytree_printfleaf(root); + printf("\r\n打印二叉树叶子节点个数:%d",binarytree_getleafnum(root)); + printf("\r\n打印二叉树高度:%d",binarytree_gethigh(root)); + + binarytree_destory(root); + + muntrace(); + return 0; +} + diff --git a/c-cpp/23_binarytree/tree/list_queue.c b/c-cpp/23_binarytree/tree/list_queue.c new file mode 100644 index 0000000..2dbc9f9 --- /dev/null +++ b/c-cpp/23_binarytree/tree/list_queue.c @@ -0,0 +1,85 @@ +/************************************************************************* + > File Name: list_queue.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-13 + > Desc: + ************************************************************************/ +#include +#include +#include +#include"./list_queue.h" + +/*创建队列头*/ +list_queue *list_queue_create() +{ + list_queue * queue = NULL; + + queue = (list_queue *)malloc(sizeof(list_queue)); + if(queue == NULL) + { + return NULL; + } + + queue->num = 0; + queue->head = NULL; + queue->tail = NULL; + + return queue; +} +int list_queue_enqueue(list_queue *queue,void *data) +{ + queue_node *ptmp = NULL; + + if(queue == NULL) + { + return -1; + } + + ptmp = (queue_node *)malloc(sizeof(queue_node)); + if (ptmp == NULL) + { + return -1; + } + + ptmp->data = data; + ptmp->next = NULL; + if (queue->head == NULL) + { + queue->head = ptmp; + } + else + { + queue->tail->next = ptmp; + + } + queue->tail = ptmp; + queue->num++; + + return 0; +} + +/*出队*/ +int list_queue_dequeue(list_queue *queue,void **data) +{ + queue_node * ptmp = NULL; + + if ((queue == NULL) || (data == NULL) || list_queue_is_empty(queue)) + { + return -1; + } + + *data = queue->head->data; + ptmp = queue->head; + queue->head = queue->head->next; + queue->num--; + + if (queue->head == NULL) + { + queue->tail = NULL; + } + + + free(ptmp); + return 0; +} diff --git a/c-cpp/23_binarytree/tree/list_queue.h b/c-cpp/23_binarytree/tree/list_queue.h new file mode 100644 index 0000000..a699185 --- /dev/null +++ b/c-cpp/23_binarytree/tree/list_queue.h @@ -0,0 +1,30 @@ +/************************************************************************* + > File Name: list_queue.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-13 + > Desc: + ************************************************************************/ + +#ifndef LINK_LIST_QUEUE_H +#define LINK_LIST_QUEUE_H + +typedef struct _list_queue_node +{ + void *data; + struct _list_queue_node *next; +}queue_node; + +typedef struct _list_queue +{ + int num; + queue_node *head; + queue_node *tail; +}list_queue; + +#define list_queue_is_empty(queue) ((queue->num) == 0) +list_queue *list_queue_create(); +int list_queue_enqueue(list_queue *queue,void *data); +int list_queue_dequeue(list_queue *queue,void **data); + +#endif From 96d308044e0d65d01df83dc637e57deffd9ff44a Mon Sep 17 00:00:00 2001 From: wangzheng0822 Date: Tue, 13 Nov 2018 22:55:15 +0800 Subject: [PATCH 091/141] Create BinarySearchTree.java --- java/24_tree/BinarySearchTree.java | 81 ++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 java/24_tree/BinarySearchTree.java diff --git a/java/24_tree/BinarySearchTree.java b/java/24_tree/BinarySearchTree.java new file mode 100644 index 0000000..098475f --- /dev/null +++ b/java/24_tree/BinarySearchTree.java @@ -0,0 +1,81 @@ +public class BinarySearchTree { + private Node tree; + + public Node find(int data) { + Node p = tree; + while (p != null) { + if (data < p.data) p = p.left; + else if (data > p.data) p = p.right; + else return p; + } + return null; + } + + public void insert(int data) { + if (tree == null) { + tree = new Node(data); + return; + } + + Node p = tree; + while (p != null) { + if (data > p.data) { + if (p.right == null) { + p.right = new Node(data); + return; + } + p = p.right; + } else { // data < p.data + if (p.left == null) { + p.left = new Node(data); + return; + } + p = p.left; + } + } + } + + public void delete(int data) { + Node p = tree; // p指向要删除的节点,初始化指向根节点 + Node pp = null; // pp记录的是p的父节点 + while (p != null && p.data != data) { + pp = p; + if (data > p.data) p = p.right; + else p = p.left; + } + if (p == null) return; // 没有找到 + + // 要删除的节点有两个子节点 + if (p.left != null && p.right != null) { // 查找右子树中最小节点 + Node minP = p.right; + Node minPP = p; // minPP表示minP的父节点 + while (minP.left != null) { + minPP = minP; + minP = minP.left; + } + p.data = minP.data; // 将minP的数据替换到p中 + p = minP; // 下面就变成了删除minP了 + pp = minPP; + } + + // 删除节点是叶子节点或者仅有一个子节点 + Node child; // p的子节点 + if (p.left != null) child = p.left; + else if (p.right != null) child = p.right; + else child = null; + + if (pp == null) tree = child; // 删除的是根节点 + else if (pp.left == p) pp.left = child; + else pp.right = child; + } + + public static class Node { + private int data; + private Node left; + private Node right; + + public Node(int data) { + this.data = data; + } + } +} From 273a25c08db706f2d3755016a6e2962e6d386338 Mon Sep 17 00:00:00 2001 From: Wenru Dong Date: Tue, 13 Nov 2018 18:01:57 +0000 Subject: [PATCH 092/141] binary search tree in python --- python/24_tree/binary_search_tree.py | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 python/24_tree/binary_search_tree.py diff --git a/python/24_tree/binary_search_tree.py b/python/24_tree/binary_search_tree.py new file mode 100644 index 0000000..f5a3f87 --- /dev/null +++ b/python/24_tree/binary_search_tree.py @@ -0,0 +1,64 @@ +""" + Binary search tree + + Author: Wenru Dong +""" +from typing import Optional + +class TreeNode: + def __init__(self, value: int): + self.val = value + self.left = None + self.right = None + +class BinarySearchTree: + def __init__(self): + self._root = None + + def find(self, value: int) -> Optional[TreeNode]: + node = self._root + while node and node.val != value: + node = node.left if node.val > value else node.right + return node + + def insert(self, value: int): + if not self._root: + self._root = TreeNode(value) + return + parent = None + node = self._root + while node: + parent = node + node = node.left if node.val > value else node.right + new_node = TreeNode(value) + if parent.val > value: + parent.left = new_node + else: + parent.right = new_node + + def delete(self, value: int): + node = self._root + parent = None + while node and node.val != value: + parent = node + node = node.left if node.val > value else node.right + if not node: return + + # 要删除的节点有两个子节点 + if node.left and node.right: + successor = node.right + successor_parent = node + while successor.left: + successor_parent = successor + successor = successor.left + node.val = successor.val + parent, node = successor_parent, successor + + # 删除节点是叶子节点或者仅有一个子节点 + child = node.left if node.left else node.right + if not parent: + self._root = child + elif parent.left == node: + parent.left = child + else: + parent.right = child From 215291ef5f0e66a069b196045ddc646797d17298 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Wed, 14 Nov 2018 10:02:26 +0800 Subject: [PATCH 093/141] implement bst in c --- c-cpp/bst.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 c-cpp/bst.c diff --git a/c-cpp/bst.c b/c-cpp/bst.c new file mode 100644 index 0000000..7fdfd87 --- /dev/null +++ b/c-cpp/bst.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +enum child_dir { + left_child, + right_child, + root, +}; + +struct node { + unsigned long data; + struct node *left; + struct node *right; +}; + +struct root { + struct node *r; +}; + +void dump(struct node *node, int level, enum child_dir dir) +{ + if (!node) + return; + + dump(node->right, level + 1, right_child); + + if (dir == left_child) + printf("%*s\n", level*3, "|"); + + printf("%*s - %05lu\n", level*3, " ", node->data); + + if (dir == right_child) + printf("%*s\n", level*3, "|"); + + dump(node->left, level + 1, left_child); +} + +struct node* find(struct root *root, unsigned long data) +{ + struct node* n = root->r; + + while (n) { + if (n->data == data) + return n; + if (data < n->data) + n = n->left; + else + n = n->right; + } + + return NULL; +} + +struct node* new_node(unsigned long data) +{ + struct node *n; + + n = malloc(sizeof(struct node)); + + n->data = data; + n->left = n->right = NULL; + return n; +} + +void insert(struct root *root, struct node *new) +{ + struct node *parent; + + if (!root->r) { + root->r = new; + return; + } + + parent = root->r; + + while (true) { + /* Don't support duplicate data */ + if (new->data == parent->data) + break; + + if (new->data < parent->data) { + if (!parent->left) { + parent->left = new; + break; + } + parent = parent->left; + } else { + if (!parent->right) { + parent->right = new; + break; + } + parent = parent->right; + } + } +} + +struct node* delete(struct root *root, unsigned long data) +{ + struct node *n = root->r, **p = &root->r; + struct node *child; + + while (n && n->data != data) { + if (data < n->data) { + p = &n->left; + n = n->left; + } else { + p = &n->right; + n = n->right; + } + } + + if (!n) + return NULL; + + if (n->left && n->right) { + struct node *rn = n->right, **rp = &n->right; + + while (rn->left) { + rp = &rn->left; + rn = rn->left; + } + + n->data = rn->data; + n = rn; + p = rp; + } + + child = n->left ? n->left : n->right; + *p = child; + + return NULL; +} + +void insert_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + n = find(&tree, 18); + if (n && n->data == 18) + printf("Get 18\n"); + +} + +void delete_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + delete(&tree, 20); + printf("Delete 20\n"); + dump(tree.r, 0, root); + + delete(&tree, 9); + printf("Delete 9\n"); + dump(tree.r, 0, root); +} + +int main() +{ + //insert_test(); + delete_test(); + return 0; +} From 5ebfdc90d80d1833a4421c2034368ef3f5480004 Mon Sep 17 00:00:00 2001 From: wangzheng0822 Date: Wed, 14 Nov 2018 10:36:51 +0800 Subject: [PATCH 094/141] Update BinarySearchTree.java --- java/24_tree/BinarySearchTree.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/java/24_tree/BinarySearchTree.java b/java/24_tree/BinarySearchTree.java index 098475f..69850d1 100644 --- a/java/24_tree/BinarySearchTree.java +++ b/java/24_tree/BinarySearchTree.java @@ -69,6 +69,24 @@ public class BinarySearchTree { else pp.right = child; } + public Node findMin() { + if (tree == null) return null; + Node p = tree; + while (p.left != null) { + p = p.left; + } + return p; + } + + public Node findMax() { + if (tree == null) return null; + Node p = tree; + while (p.right != null) { + p = p.right; + } + return p; + } + public static class Node { private int data; private Node left; From 09cd7bc11f0f25aee81b865e03d82ce4505412e9 Mon Sep 17 00:00:00 2001 From: jinshaohui Date: Tue, 13 Nov 2018 21:57:50 -0500 Subject: [PATCH 095/141] add by jinshaohui for binary search tree(search,insert,delete) --- c-cpp/24_binarysearchtree/binarysearchtree.c | 322 +++++++++++++++++++ c-cpp/24_binarysearchtree/binarysearchtree.h | 34 ++ 2 files changed, 356 insertions(+) create mode 100644 c-cpp/24_binarysearchtree/binarysearchtree.c create mode 100644 c-cpp/24_binarysearchtree/binarysearchtree.h diff --git a/c-cpp/24_binarysearchtree/binarysearchtree.c b/c-cpp/24_binarysearchtree/binarysearchtree.c new file mode 100644 index 0000000..f069de3 --- /dev/null +++ b/c-cpp/24_binarysearchtree/binarysearchtree.c @@ -0,0 +1,322 @@ +/************************************************************************* + > File Name: binarysearchtree.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-12 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include"binarysearchtree.h" + + +bstree *bstree_create(compare_fuc compare,destory_fuc destory) +{ + bstree *tree = NULL; + + tree = (bstree*)malloc(sizeof(bstree)); + if (tree == NULL) + { + return NULL; + } + + tree->size = 0; + tree->compare = compare; + tree->destory = destory; + tree->root = NULL; + return tree; +} + +bstree_node *bstree_search(bstree *tree,mytype data) +{ + bstree_node *node = NULL; + int res = 0; + + if ((tree == NULL) || (bstree_is_empty(tree))) + { + return NULL; + } + node = tree->root; + + while(node != NULL) + { + res = tree->compare(data,node->data); + if(res == 0) + { + return node; + } + else if (res > 0) + { + node = node->rchild; + } + else + { + node = node->lchild; + } + } + + return NULL; +} + +int bstree_insert(bstree * tree, mytype data) +{ + bstree_node *node = NULL; + bstree_node *tmp = NULL; + int res = 0; + + if (tree == NULL) + { + return -1; + } + + node = (bstree_node *)malloc(sizeof(bstree_node)); + if (node == NULL) + { + return -2; + } + + node->data = data; + node->lchild = NULL; + node->rchild = NULL; + + /*如果二叉树为空,直接挂到根节点*/ + if (bstree_is_empty(tree)) + { + tree->root = node; + tree->size++; + return 0; + } + + tmp = tree->root; + + while(tmp != NULL) + { + res = tree->compare(data,tmp->data); + if (res > 0) /*去右孩子查找*/ + { + if (tmp->rchild == NULL) + { + tmp->rchild = node; + tree->size++; + return 0; + } + tmp = tmp->rchild; + } + else /*去左孩子查找*/ + { + if(tmp->lchild == NULL) + { + tmp->lchild = node; + tree->size++; + return 0; + } + tmp = tmp->lchild; + } + } + + return -3; +} + +int bstree_delete(bstree *tree,mytype data) +{ + bstree_node *node = NULL;/*要删除的节点*/ + bstree_node *pnode = NULL;/*要删除节点的父节点*/ + bstree_node *minnode = NULL;/*要删除节点的父节点*/ + bstree_node *pminnode = NULL;/*要删除节点的父节点*/ + mytype tmp = 0; + int res = 0; + + if ((tree == NULL) || (bstree_is_empty(tree))) + { + return -1; + } + + node = tree->root; + while ((node != NULL) && ((res = tree->compare(data,node->data)) != 0)) + { + pnode = node; + if(res > 0) + { + node = node->rchild; + } + else + { + node = node->lchild; + } + } + /*说明要删除的节点不存在*/ + if (node == NULL) + { + return -2; + } + + /*1、如果要删除node有2个子节点,需要找到右子树的最小节点minnode, + * 更新minnode和node节点数据,这样minnode节点就是要删除的节点 + * 再更新node和pnode节点指向要删除的节点*/ + if ((node->lchild != NULL) && (node->rchild != NULL)) + { + minnode = node->rchild; + pminnode = node; + + while(minnode->lchild != NULL) + { + pminnode = minnode; + minnode = minnode->lchild; + } + + /*node 节点和minnode节点数据互换*/ + tmp = node->data; + node->data = minnode->data; + minnode->data = tmp; + /*更新要删除的节点和其父节点*/ + node = minnode; + pnode = pminnode; + } + + /*2、当前要删除的节点只有左孩子或者右孩子时,直接父节点的直向删除的节点*/ + if (node->lchild != NULL) + { + minnode = node->lchild; + } + else if (node->rchild != NULL) + { + minnode = node->rchild; + } + else + { + minnode = NULL; + } + + if (pnode == NULL)/*当要删除的时根节点时,*/ + { + tree->root = minnode; + } + else if (pnode->lchild == node) + { + pnode->lchild = minnode; + } + else + { + pnode->rchild = minnode; + } + tree->size--; + free (node); + + return 0; +} + +/*采用递归方式删除节点*/ +void bstree_destory_node(bstree *tree,bstree_node *root) +{ + if (root == NULL) + { + return; + } + + bstree_destory_node(tree,root->lchild); + bstree_destory_node(tree,root->rchild); + free(root); +} + +/*二叉搜索树销毁*/ +void bstree_destory(bstree *tree) +{ + bstree_destory_node(tree,tree->root); + free(tree); + return; +} + +/*中序遍历打印树节点*/ +void bstree_inorder_node(bstree_node *root) +{ + bstree_node *node = NULL; + if (root == NULL) + { + return; + } + + bstree_inorder_node(root->lchild); + printf(" %d ",root->data); + bstree_inorder_node(root->rchild); + return; +} + +void bstree_dump(bstree *tree) +{ + bstree_node *node = NULL; + if ((tree == NULL) || (bstree_is_empty(tree))) + { + printf("\r\n 当前树是空树"); + } + printf("\r\nSTART-----------------%d------------\r\n",tree->size); + bstree_inorder_node(tree->root); + printf("\r\nEND---------------------------------",tree->size); + +} + +int bstree_compare(mytype key1,mytype key2) +{ + if (key1 == key2) + { + return 0; + } + else if (key1 > key2) + { + return 1; + } + else + { + return -1; + } +} + +int main() +{ + bstree *tree = NULL; + bstree_node *node = NULL; + mytype data = 0; + int res = 0; + + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + + tree = bstree_create(bstree_compare,NULL); + assert(tree != NULL); + + while(1) + { + printf("\r\n插入一个数字,输入100时退出:"); + scanf("%d",&data); + if(data == 100)break; + res = bstree_insert(tree,data); + printf("\r\n %d 插入%s成功",data,(res != 0)?("不"):(" ")); + } + bstree_dump(tree); + + while(1) + { + printf("\r\n查询一个数字,输入100时退出:"); + scanf("%d",&data); + if(data == 100)break; + node = bstree_search(tree,data); + printf("\r\n %d %s存在树中",data,(node == NULL)?("不"):(" ")); + } + bstree_dump(tree); + while(1) + { + printf("\r\n删除一个数字,输入100时退出:"); + scanf("%d",&data); + if(data == 100)break; + res = bstree_delete(tree,data); + printf("\r\n %d 删除%s成功",data,(res != 0)?("不"):(" ")); + bstree_dump(tree); + } + + bstree_destory(tree); + + muntrace(); + + return 0; +} diff --git a/c-cpp/24_binarysearchtree/binarysearchtree.h b/c-cpp/24_binarysearchtree/binarysearchtree.h new file mode 100644 index 0000000..b4e0611 --- /dev/null +++ b/c-cpp/24_binarysearchtree/binarysearchtree.h @@ -0,0 +1,34 @@ +/************************************************************************* + > File Name: binarysearchtree.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-12 + > Desc: + ************************************************************************/ +#ifndef __BINARY_SEARCH_TREE__ +#define __BINARY_SEARCH_TREE__ +typedef int mytype; + +typedef struct _bstree_node +{ + mytype data; + struct _bstree_node *lchild; + struct _bstree_node *rchild; +}bstree_node; + +typedef struct _bstree +{ + int size; + int (*compare)(mytype key1,mytype key2); + int (*destory)(mytype data); + bstree_node *root; +}bstree; + +typedef int (*compare_fuc)(mytype key1,mytype key2); +typedef int (*destory_fuc)(mytype data); + +#define bstree_is_empty(tree) (tree->size == 0) + +bstree *bstree_create(compare_fuc compare,destory_fuc destory); + +#endif From 0a2b60c0d68550e663983222ea665211dd449e77 Mon Sep 17 00:00:00 2001 From: lee <554050334@qq.com> Date: Wed, 14 Nov 2018 16:41:59 +0800 Subject: [PATCH 096/141] use bit operation to replace + operation --- go/binarysearch2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/binarysearch2.go b/go/binarysearch2.go index ef2549e..145f4f7 100644 --- a/go/binarysearch2.go +++ b/go/binarysearch2.go @@ -6,7 +6,7 @@ func BinarySearch2(nums []int, value int) int { start := 0 end := length - 1 for start <= end { - mid := (start + end) / 2 + mid := start + ((end - start) >> 2) if nums[mid] > value { end = mid - 1 } else if nums[mid] < value { From 523574f8caa154f8304179ef52b10f2d11b89b7b Mon Sep 17 00:00:00 2001 From: Observer <45023046+Observer5@users.noreply.github.com> Date: Wed, 14 Nov 2018 16:44:53 +0800 Subject: [PATCH 097/141] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/composer.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/composer.json b/php/composer.json index 12bea69..eef8f49 100644 --- a/php/composer.json +++ b/php/composer.json @@ -7,12 +7,8 @@ "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 } } } From 66e8cfcfa22d415de7a9f258a23c20865f87e786 Mon Sep 17 00:00:00 2001 From: lee <554050334@qq.com> Date: Wed, 14 Nov 2018 16:51:06 +0800 Subject: [PATCH 098/141] operation optimization --- go/binarysearch2.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/binarysearch2.go b/go/binarysearch2.go index 145f4f7..9e3f71e 100644 --- a/go/binarysearch2.go +++ b/go/binarysearch2.go @@ -6,7 +6,7 @@ func BinarySearch2(nums []int, value int) int { start := 0 end := length - 1 for start <= end { - mid := start + ((end - start) >> 2) + mid := start + ((end - start) >> 1) if nums[mid] > value { end = mid - 1 } else if nums[mid] < value { @@ -29,7 +29,7 @@ func BinarySearch3(nums []int, value int) int { start := 0 end := len(nums) - 1 for start <= end { - mid := (start + end) / 2 + mid := start + ((end - start) >> 1) if nums[mid] > value { end = mid - 1 } else if nums[mid] < value { From 3b6ab0c07d089f80dd42c438e9ac78c79a7e305c Mon Sep 17 00:00:00 2001 From: CaiKnife Date: Thu, 15 Nov 2018 15:34:56 +0800 Subject: [PATCH 099/141] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/README.md | 4 ---- php/composer.json | 4 ---- 2 files changed, 8 deletions(-) diff --git a/php/README.md b/php/README.md index 6e3a277..aabcd3c 100644 --- a/php/README.md +++ b/php/README.md @@ -17,11 +17,7 @@ * findMiddleNode 求链表的中间结点 #### 08_stack -<<<<<<< HEAD -* 链栈实现 -======= * 链栈实现 #### 09_stack * 队列链表实现 ->>>>>>> upstream/master diff --git a/php/composer.json b/php/composer.json index 12bea69..eef8f49 100644 --- a/php/composer.json +++ b/php/composer.json @@ -7,12 +7,8 @@ "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 } } } From ccf862c51947463f594abdc73d3fd4884cf7e771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?leotyliu=28=E5=88=98=E5=A4=A9=E4=B8=80=29?= Date: Thu, 15 Nov 2018 16:07:29 +0800 Subject: [PATCH 100/141] BST by golang --- go/24_tree/BinarySearchTree.go | 145 ++++++++++++++++++++++++++++ go/24_tree/BinarySearchTree_test.go | 145 ++++++++++++++++++++++++++++ go/24_tree/BinaryTree.go | 65 +++++++++++++ go/24_tree/BinaryTree_test.go | 30 ++++++ go/24_tree/StackBasedOnArray.go | 72 ++++++++++++++ go/24_tree/TreeNode.go | 17 ++++ 6 files changed, 474 insertions(+) create mode 100644 go/24_tree/BinarySearchTree.go create mode 100644 go/24_tree/BinarySearchTree_test.go create mode 100644 go/24_tree/BinaryTree.go create mode 100644 go/24_tree/BinaryTree_test.go create mode 100644 go/24_tree/StackBasedOnArray.go create mode 100644 go/24_tree/TreeNode.go diff --git a/go/24_tree/BinarySearchTree.go b/go/24_tree/BinarySearchTree.go new file mode 100644 index 0000000..0e39e35 --- /dev/null +++ b/go/24_tree/BinarySearchTree.go @@ -0,0 +1,145 @@ +package _4_tree + +type BST struct { + *BinaryTree + //比对函数,0:v==nodeV,正数:v>nodeV,负数:v 0 { //v > nodeV + p = p.right + } else { //v < nodeV + p = p.left + } + } + return nil +} + +func (this *BST) Insert(v interface{}) bool { + p := this.root + for nil != p { + compareResult := this.compareFunc(v, p.data) + if compareResult == 0 { + return false + } else if compareResult > 0 { + if nil == p.right { + p.right = NewNode(v) + break + } + p = p.right + } else { + if nil == p.left { + p.left = NewNode(v) + break + } + p = p.left + } + } + return true +} + +func (this *BST) Delete(v interface{}) bool { + var pp *Node = nil + p := this.root + deleteLeft := false + for nil != p { + compareResult := this.compareFunc(v, p.data) + if compareResult > 0 { + pp = p + p = p.right + deleteLeft = false + } else if compareResult < 0 { + pp = p + p = p.left + deleteLeft = true + } else { + break + } + } + + if nil == p { //需要删除的节点不存在 + return false + } else if nil == p.left && nil == p.right { //删除的是一个叶子节点 + if nil != pp { + if deleteLeft { + pp.left = nil + } else { + pp.right = nil + } + } else { //根节点 + this.root = nil + } + } else if nil != p.right { //删除的是一个有右孩子,不一定有左孩子的节点 + //找到p节点右孩子的最小节点 + pq := p + q := p.right //向右走一步 + fromRight := true + for nil != q.left { //向左走到底 + pq = q + q = q.left + fromRight = false + } + if fromRight { + pq.right = nil + } else { + pq.left = nil + } + q.left = p.left + q.right = p.right + if nil == pp { //根节点被删除 + this.root = q + } else { + if deleteLeft { + pq.left = q + } else { + pq.right = q + } + } + } else { //删除的是一个只有左孩子的节点 + if nil != pp { + if deleteLeft { + pp.left = p.left + } else { + pp.right = p.left + } + } else { + if deleteLeft { + this.root = p.left + } else { + this.root = p.left + } + } + } + + return true + +} + +func (this *BST) Min() *Node { + p := this.root + for nil != p.left { + p = p.left + } + return p +} + +func (this *BST) Max() *Node { + p := this.root + for nil != p.right { + p = p.right + } + return p +} diff --git a/go/24_tree/BinarySearchTree_test.go b/go/24_tree/BinarySearchTree_test.go new file mode 100644 index 0000000..f9dbb61 --- /dev/null +++ b/go/24_tree/BinarySearchTree_test.go @@ -0,0 +1,145 @@ +package _4_tree + +import "testing" + +var compareFunc = func(v, nodeV interface{}) int { + vInt := v.(int) + nodeVInt := nodeV.(int) + + if vInt > nodeVInt { + return 1 + } else if vInt < nodeVInt { + return -1 + } + return 0 +} + +func TestBST_Find(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Find(2)) +} + +func TestBST_Insert(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + bst.InOrderTraverse() +} + +func TestBST_Min(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Min()) +} + +func TestBST_Max(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Max()) +} + +func TestBST_DeleteA(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Delete(7)) + + bst.InOrderTraverse() +} + +func TestBST_DeleteB(t *testing.T) { + bst := NewBST(1, compareFunc) + + t.Log(bst.Delete(1)) + t.Log(bst.root) + + bst.InOrderTraverse() +} + +func TestBST_DeleteC(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Delete(1)) + + bst.InOrderTraverse() +} + +func TestBST_DeleteD(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(5) + + t.Log(bst.Delete(1)) + + bst.InOrderTraverse() +} +func TestBST_DeleteE(t *testing.T) { + bst := NewBST(5, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(4) + bst.Insert(1) + + t.Log(bst.Delete(5)) + bst.InOrderTraverse() +} + +func TestBST_DeleteF(t *testing.T) { + bst := NewBST(5, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(4) + bst.Insert(1) + + t.Log(bst.Delete(2)) + bst.InOrderTraverse() +} + +func TestBST_DeleteG(t *testing.T) { + bst := NewBST(5, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(4) + bst.Insert(1) + + t.Log(bst.Delete(1)) + bst.InOrderTraverse() +} diff --git a/go/24_tree/BinaryTree.go b/go/24_tree/BinaryTree.go new file mode 100644 index 0000000..db9f8ae --- /dev/null +++ b/go/24_tree/BinaryTree.go @@ -0,0 +1,65 @@ +package _4_tree + +import "fmt" + +type BinaryTree struct { + root *Node +} + +func NewBinaryTree(rootV interface{}) *BinaryTree { + return &BinaryTree{NewNode(rootV)} +} + +func (this *BinaryTree) InOrderTraverse() { + p := this.root + s := NewArrayStack() + + for !s.IsEmpty() || nil != p { + if nil != p { + s.Push(p) + p = p.left + } else { + tmp := s.Pop().(*Node) + fmt.Printf("%+v ", tmp.data) + p = tmp.right + } + } + fmt.Println() +} + +func (this *BinaryTree) PreOrderTraverse() { + p := this.root + s := NewArrayStack() + + for !s.IsEmpty() || nil != p { + if nil != p { + fmt.Printf("%+v ", p.data) + s.Push(p) + p = p.left + } else { + p = s.Pop().(*Node).right + } + } + + fmt.Println() +} + +func (this *BinaryTree) PostOrderTraverse() { + s1 := NewArrayStack() + s2 := NewArrayStack() + s1.Push(this.root) + for !s1.IsEmpty() { + p := s1.Pop().(*Node) + s2.Push(p) + if nil != p.left { + s1.Push(p.left) + } + if nil != p.right { + s1.Push(p.right) + } + } + + for !s2.IsEmpty() { + fmt.Printf("%+v ", s2.Pop().(*Node).data) + } +} diff --git a/go/24_tree/BinaryTree_test.go b/go/24_tree/BinaryTree_test.go new file mode 100644 index 0000000..484c3b2 --- /dev/null +++ b/go/24_tree/BinaryTree_test.go @@ -0,0 +1,30 @@ +package _4_tree + +import "testing" + +func TestBinaryTree_InOrderTraverse(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.InOrderTraverse() +} + +func TestBinaryTree_PreOrderTraverse(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.PreOrderTraverse() +} + +func TestBinaryTree_PostOrderTraverse(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.PostOrderTraverse() +} diff --git a/go/24_tree/StackBasedOnArray.go b/go/24_tree/StackBasedOnArray.go new file mode 100644 index 0000000..e1c585f --- /dev/null +++ b/go/24_tree/StackBasedOnArray.go @@ -0,0 +1,72 @@ +package _4_tree + +import "fmt" + +/* +基于数组实现的栈 +*/ + +type ArrayStack struct { + //数据 + data []interface{} + //栈顶指针 + top int +} + +func NewArrayStack() *ArrayStack { + return &ArrayStack{ + data: make([]interface{}, 0, 32), + top: -1, + } +} + +func (this *ArrayStack) IsEmpty() bool { + if this.top < 0 { + return true + } + return false +} + +func (this *ArrayStack) Push(v interface{}) { + if this.top < 0 { + this.top = 0 + } else { + this.top += 1 + } + + if this.top > len(this.data)-1 { + this.data = append(this.data, v) + } else { + this.data[this.top] = v + } +} + +func (this *ArrayStack) Pop() interface{} { + if this.IsEmpty() { + return nil + } + v := this.data[this.top] + this.top -= 1 + return v +} + +func (this *ArrayStack) Top() interface{} { + if this.IsEmpty() { + return nil + } + return this.data[this.top] +} + +func (this *ArrayStack) Flush() { + this.top = -1 +} + +func (this *ArrayStack) Print() { + if this.IsEmpty() { + fmt.Println("empty statck") + } else { + for i := this.top; i >= 0; i-- { + fmt.Println(this.data[i]) + } + } +} diff --git a/go/24_tree/TreeNode.go b/go/24_tree/TreeNode.go new file mode 100644 index 0000000..775cf46 --- /dev/null +++ b/go/24_tree/TreeNode.go @@ -0,0 +1,17 @@ +package _4_tree + +import "fmt" + +type Node struct { + data interface{} + left *Node + right *Node +} + +func NewNode(data interface{}) *Node { + return &Node{data: data} +} + +func (this *Node) String() string { + return fmt.Sprintf("v:%+v, left:%+v, right:%+v", this.data, this.left, this.right) +} From 05416a1b0f2cf7e9b4cf22115a59f5806f655cff Mon Sep 17 00:00:00 2001 From: CaiKnife Date: Thu, 15 Nov 2018 16:39:14 +0800 Subject: [PATCH 101/141] =?UTF-8?q?=E8=A7=A3=E5=86=B3PHP=E7=9A=84=E6=A0=88?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=96=87=E4=BB=B6=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/08_stack/Compute.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/php/08_stack/Compute.php b/php/08_stack/Compute.php index 7e0a337..a7fd076 100644 --- a/php/08_stack/Compute.php +++ b/php/08_stack/Compute.php @@ -28,8 +28,6 @@ function expression($str) array_push($operStack, $arr[$i]); break; case '*': -<<<<<<< HEAD -======= $arrLen = count($operStack); while ($operStack[$arrLen-1] === '/'){ compute($numStack, $operStack); @@ -38,7 +36,6 @@ function expression($str) array_push($operStack, $arr[$i]); break; ->>>>>>> upstream/master case '/': case '(': array_push($operStack, $arr[$i]); From f6fdcdf620525f2da81fee9fee1ecff6dbda1262 Mon Sep 17 00:00:00 2001 From: CaiKnife Date: Thu, 15 Nov 2018 16:52:44 +0800 Subject: [PATCH 102/141] =?UTF-8?q?=E8=A7=A3=E5=86=B3PHP=E7=9A=84=E6=A0=88?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=96=87=E4=BB=B6=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/08_stack/Compute.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/php/08_stack/Compute.php b/php/08_stack/Compute.php index a7fd076..d9b8eb4 100644 --- a/php/08_stack/Compute.php +++ b/php/08_stack/Compute.php @@ -78,13 +78,9 @@ 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)'); From 73f0db5b5ec18f5d704238ebbe97bb68102aa1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E5=93=A5?= <109694228@qq.com> Date: Fri, 16 Nov 2018 12:20:46 +0800 Subject: [PATCH 103/141] binary search tree --- python/23_binarytree/binary_search_tree.py | 292 +++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 python/23_binarytree/binary_search_tree.py diff --git a/python/23_binarytree/binary_search_tree.py b/python/23_binarytree/binary_search_tree.py new file mode 100644 index 0000000..5500c5c --- /dev/null +++ b/python/23_binarytree/binary_search_tree.py @@ -0,0 +1,292 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from queue import Queue +import math + + +class TreeNode: + def __init__(self, val=None): + self.val = val + self.left = None + self.right = None + self.parent = None + + +class BinarySearchTree: + def __init__(self, val_list=[]): + self.root = None + for n in val_list: + self.insert(n) + + def insert(self, data): + """ + 插入 + :param data: + :return: + """ + assert(isinstance(data, int)) + + if self.root is None: + self.root = TreeNode(data) + else: + n = self.root + while n: + p = n + if data < n.val: + n = n.left + else: + n = n.right + + new_node = TreeNode(data) + new_node.parent = p + + if data < p.val: + p.left = new_node + else: + p.right = new_node + + return True + + def search(self, data): + """ + 搜索 + 返回bst中所有值为data的节点列表 + :param data: + :return: + """ + assert(isinstance(data, int)) + + # 所有搜索到的节点 + ret = [] + + n = self.root + while n: + if data < n.val: + n = n.left + else: + if data == n.val: + ret.append(n) + n = n.right + + return ret + + def delete(self, data): + """ + 删除 + :param data: + :return: + """ + assert (isinstance(data, int)) + + # 通过搜索得到需要删除的节点 + del_list = self.search(data) + + for n in del_list: + # 父节点为空,又不是根节点,已经不在树上,不用再删除 + if n.parent is None and n != self.root: + continue + else: + self._del(n) + + def _del(self, node): + """ + 删除 + 所删除的节点N存在以下情况: + 1. 没有子节点:直接删除N的父节点指针 + 2. 有一个子节点:将N父节点指针指向N的子节点 + 3. 有两个子节点:找到右子树的最小节点M,将值赋给N,然后删除M + :param data: + :return: + """ + # 1 + if node.left is None and node.right is None: + # 情况1和2,根节点和普通节点的处理方式不同 + if node == self.root: + self.root = None + else: + if node.val < node.parent.val: + node.parent.left = None + else: + node.parent.right = None + + node.parent = None + # 2 + elif node.left is None and node.right is not None: + if node == self.root: + self.root = node.right + self.root.parent = None + node.right = None + else: + if node.val < node.parent.val: + node.parent.left = node.right + else: + node.parent.right = node.right + + node.right.parent = node.parent + node.parent = None + node.right = None + elif node.left is not None and node.right is None: + if node == self.root: + self.root = node.left + self.root.parent = None + node.left = None + else: + if node.val < node.parent.val: + node.parent.left = node.left + else: + node.parent.right = node.left + + node.left.parent = node.parent + node.parent = None + node.left = None + # 3 + else: + min_node = node.right + # 找到右子树的最小值节点 + if min_node.left: + min_node = min_node.left + + if node.val != min_node.val: + node.val = min_node.val + self._del(min_node) + # 右子树的最小值节点与被删除节点的值相等,再次删除原节点 + else: + self._del(min_node) + self._del(node) + + def get_min(self): + """ + 返回最小值节点 + :return: + """ + if self.root is None: + return None + + n = self.root + while n.left: + n = n.left + return n.val + + def get_max(self): + """ + 返回最大值节点 + :return: + """ + if self.root is None: + return None + + n = self.root + while n.right: + n = n.right + return n.val + + def in_order(self): + """ + 中序遍历 + :return: + """ + if self.root is None: + return [] + + return self._in_order(self.root) + + def _in_order(self, node): + if node is None: + return [] + + ret = [] + n = node + ret.extend(self._in_order(n.left)) + ret.append(n.val) + ret.extend(self._in_order(n.right)) + + return ret + + def __repr__(self): + # return str(self.in_order()) + print(str(self.in_order())) + return self._draw_tree() + + def _bfs(self): + """ + bfs + 通过父子关系记录节点编号 + :return: + """ + if self.root is None: + return [] + + ret = [] + q = Queue() + # 队列[节点,编号] + q.put((self.root, 1)) + + while not q.empty(): + n = q.get() + + if n[0] is not None: + ret.append((n[0].val, n[1])) + q.put((n[0].left, n[1]*2)) + q.put((n[0].right, n[1]*2+1)) + + return ret + + def _draw_tree(self): + """ + 可视化 + :return: + """ + nodes = self._bfs() + + if not nodes: + print('This tree has no nodes.') + return + + layer_num = int(math.log(nodes[-1][1], 2)) + 1 + + prt_nums = [] + + for i in range(layer_num): + prt_nums.append([None]*2**i) + + for v, p in nodes: + row = int(math.log(p ,2)) + col = p % 2**row + prt_nums[row][col] = v + + prt_str = '' + for l in prt_nums: + prt_str += str(l)[1:-1] + '\n' + + return prt_str + + +if __name__ == '__main__': + nums = [4, 2, 5, 6, 1, 7, 3] + bst = BinarySearchTree(nums) + print(bst) + + # 插入 + bst.insert(1) + bst.insert(4) + print(bst) + + # 搜索 + for n in bst.search(2): + print(n.parent.val, n.val) + + # 删除 + bst.insert(6) + bst.insert(7) + print(bst) + bst.delete(7) + print(bst) + bst.delete(6) + print(bst) + bst.delete(4) + print(bst) + + # min max + print(bst.get_max()) + print(bst.get_min()) From f1897d10291d30e4fa015ab50802de2eca7b1b75 Mon Sep 17 00:00:00 2001 From: lee <554050334@qq.com> Date: Fri, 16 Nov 2018 18:40:50 +0800 Subject: [PATCH 104/141] add a new implemention way for BT post order traverse --- go/24_tree/BinaryTree.go | 32 ++++++++++++++++++++++++++++++++ go/24_tree/BinaryTree_test.go | 9 +++++++++ 2 files changed, 41 insertions(+) diff --git a/go/24_tree/BinaryTree.go b/go/24_tree/BinaryTree.go index db9f8ae..cd2417d 100644 --- a/go/24_tree/BinaryTree.go +++ b/go/24_tree/BinaryTree.go @@ -63,3 +63,35 @@ func (this *BinaryTree) PostOrderTraverse() { fmt.Printf("%+v ", s2.Pop().(*Node).data) } } + +//use one stack, pre cursor to traverse from post order +func (this *BinaryTree) PostOrderTraverse2() { + r := this.root + s := NewArrayStack() + + //point to last visit node + var pre *Node + + s.Push(r) + + for !s.IsEmpty() { + r = s.Top().(*Node) + if (r.left == nil && r.right == nil) || + (pre != nil && (pre == r.left || pre == r.right)) { + + fmt.Printf("%+v ", r.data) + s.Pop() + pre = r + } else { + if r.right != nil { + s.Push(r.right) + } + + if r.left != nil { + s.Push(r.left) + } + + } + + } +} diff --git a/go/24_tree/BinaryTree_test.go b/go/24_tree/BinaryTree_test.go index 484c3b2..6f8bf15 100644 --- a/go/24_tree/BinaryTree_test.go +++ b/go/24_tree/BinaryTree_test.go @@ -28,3 +28,12 @@ func TestBinaryTree_PostOrderTraverse(t *testing.T) { binaryTree.PostOrderTraverse() } + +func TestBinaryTree_PostOrderTraverse2(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.PostOrderTraverse2() +} From 44165a4611004768949765a34e0fa2fccb84f0b2 Mon Sep 17 00:00:00 2001 From: MG Date: Sun, 18 Nov 2018 11:40:01 +0800 Subject: [PATCH 105/141] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=8D=95?= =?UTF-8?q?=E5=90=91=E9=93=BE=E8=A1=A8=E5=8F=8D=E8=BD=AC=E3=80=81=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E7=8E=AF=E3=80=81=E5=88=A0=E9=99=A4=E5=80=92=E6=95=B0?= =?UTF-8?q?=E7=AC=ACN=E4=B8=AA=E8=8A=82=E7=82=B9=E3=80=81=E6=B1=82?= =?UTF-8?q?=E9=93=BE=E8=A1=A8=E4=B8=AD=E9=97=B4=E8=8A=82=E7=82=B9=E7=AD=89?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.增加了单向链表反转的方法:reversed_self 2.增加了检查环的方法:has_ring 3.增加了删除链表倒数第N个节点的方法:delete_last_N_node 4.增加了求链表中间节点的方法:find_mid_node --- python/06_linkedlist/singlyLinkedList.py | 91 +++++++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/python/06_linkedlist/singlyLinkedList.py b/python/06_linkedlist/singlyLinkedList.py index 0e9663b..030434f 100644 --- a/python/06_linkedlist/singlyLinkedList.py +++ b/python/06_linkedlist/singlyLinkedList.py @@ -63,9 +63,10 @@ class SinglyLinkedList(): Node ''' node = self.__head - while node != None and node.data != value: + if node != None and node.data != value: node = node.next - return node + else: + return node def find_by_index(self, index): '''按照索引值在列表中查找. @@ -176,6 +177,45 @@ class SinglyLinkedList(): if not_found == False: pro.next = node.next + def delete_last_N_node(self, n): + '''删除链表中倒数第N个节点. + 主体思路: + 设置快、慢两个指针,快指针先行,慢指针不动;当快指针跨了N步以后,快、慢指针同时往链表尾部移动, + 当快指针到达链表尾部的时候,慢指针所指向的就是链表的倒数第N个节点 + 参数: + n:需要删除的倒数第N个序数 + ''' + fast = self.__head + slow = self.__head + step = 0 + + while step <= n: + fast = fast.next + step += 1 + + while fast.next != None: + tmp = slow + fast = fast.next + slow = slow.next + + tmp.next = slow.next + + def find_mid_node(self): + '''查找链表中的中间节点. + 主体思想: + 设置快、慢两种指针,快指针每次跨两步,慢指针每次跨一步,则当快指针到达链表尾部的时候,慢指针指向链表的中间节点 + 返回: + node:链表的中间节点 + ''' + fast = self.__head + slow = self.__head + + while fast.next != None: + fast = fast.next.next + slow = slow.next + + return slow + def create_node(self, value): '''创建一个存储value值的Node节点. 参数: @@ -195,3 +235,50 @@ class SinglyLinkedList(): print(str(pos.data) + ' --> ', end='') pos = pos.next print(str(pos.data)) + + def reversed_self(self): + '''翻转链表自身.''' + if self.__head == None or self.__head.next == None: # 如果链表为空,或者链表只有一个节点 + return + + pre = self.__head + node = self.__head.next + while node != None: + pre, node = self.__reversed_with_two_node(pre, node) + + self.__head.next = None + self.__head = pre + + def __reversed_with_two_node(self, pre, node): + '''翻转相邻两个节点. + 参数: + pre:前一个节点 + node:当前节点 + 返回: + (pre,node):下一个相邻节点的元组 + ''' + tmp = node.next + node.next = pre + pre = node # 这样写有点啰嗦,但是能让人更能看明白 + node = tmp + return (pre, node) + + def has_ring(self): + '''检查链表中是否有环. + 主体思想: + 设置快、慢两种指针,快指针每次跨两步,慢指针每次跨一步,如果快指针没有与慢指针相遇而是顺利到达链表尾部 + 说明没有环;否则,存在环 + 返回: + True:有环 + False:没有环 + ''' + fast = self.__head + slow = self.__head + + while fast.next != None and fast != None: + fast = fast.next + slow = slow.next + if fast == slow: + return True + + return False From 425b724070835b83ef5c20c422595f7d06272568 Mon Sep 17 00:00:00 2001 From: quanxing Date: Sun, 18 Nov 2018 17:17:26 +0800 Subject: [PATCH 106/141] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9B=9E=E6=96=87?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E4=BB=A3=E7=A0=81bug=EF=BC=8C?= =?UTF-8?q?=E8=AF=B7=E6=8C=87=E6=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- java/06_linkedlist/SinglyLinkedList.java | 40 +++++++++++++----------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/java/06_linkedlist/SinglyLinkedList.java b/java/06_linkedlist/SinglyLinkedList.java index cf3d154..c6d36e2 100644 --- a/java/06_linkedlist/SinglyLinkedList.java +++ b/java/06_linkedlist/SinglyLinkedList.java @@ -218,15 +218,15 @@ public class SinglyLinkedList { Node rightLink = null; if(q.next == null){ // p 一定为整个链表的中点,且节点数目为奇数 - leftLink = inverseLinkList(p); + rightLink = p.next; + leftLink = inverseLinkList(p).next; System.out.println("左边第一个节点"+leftLink.data); - System.out.println("右边第一个节点"+p.next.data); - rightLink = p; + System.out.println("右边第一个节点"+rightLink.data); }else{ //p q 均为中点 + rightLink = p.next; leftLink = inverseLinkList(p); - rightLink = q; } return TFResult(leftLink, rightLink); @@ -306,29 +306,31 @@ public class SinglyLinkedList { SinglyLinkedList link = new SinglyLinkedList(); System.out.println("hello"); //int data[] = {1}; + //int data[] = {1,2}; //int data[] = {1,2,3,1}; - int data[] = {1,2,4,5}; + //int data[] = {1,2,5}; //int data[] = {1,2,2,1}; - //int data[] = {1,2,5,2,1}; + // int data[] = {1,2,5,2,1}; + int data[] = {1,2,5,3,1}; for(int i =0; i < data.length; i++){ //link.insertToHead(data[i]); link.insertTail(data[i]); } - link.printAll(); - Node p = link.inverseLinkList_head(link.head); - while(p != null){ - System.out.println("aa"+p.data); - p = p.next; - } + // link.printAll(); + // Node p = link.inverseLinkList_head(link.head); + // while(p != null){ + // System.out.println("aa"+p.data); + // p = p.next; + // } - //System.out.println("打印原始:"); - //link.printAll(); - //if (link.palindrome()){ - // System.out.println("回文"); - //}else{ - // System.out.println("不是回文"); - //} + System.out.println("打印原始:"); + link.printAll(); + if (link.palindrome()){ + System.out.println("回文"); + }else{ + System.out.println("不是回文"); + } } } From b2861cefe7ee0178c676807593961c466c98a267 Mon Sep 17 00:00:00 2001 From: danielyan86 <516495459@qq.com> Date: Mon, 19 Nov 2018 14:46:39 +0800 Subject: [PATCH 107/141] =?UTF-8?q?1=20=E6=9B=B4=E6=96=B0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=90=8D=E5=AD=97next=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E5=86=85=E5=BB=BA=E6=96=B9=E6=B3=95next=202?= =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0for=E6=89=93=E5=8D=B0=E8=BE=93=E5=87=BA=20?= =?UTF-8?q?3=20=E6=A0=B9=E6=8D=AEPEP8=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/06_linkedlist/singly_linked_list.py | 38 +++++++++++++--------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/python/06_linkedlist/singly_linked_list.py b/python/06_linkedlist/singly_linked_list.py index f5565f3..4c31f05 100644 --- a/python/06_linkedlist/singly_linked_list.py +++ b/python/06_linkedlist/singly_linked_list.py @@ -6,23 +6,23 @@ """ from typing import Optional + class Node: - - def __init__(self, data: int, next=None): + + def __init__(self, data: int, next_node=None): self.data = data - self._next = next - + self._next = next_node + class SinglyLinkedList: def __init__(self): self._head = None - + def find_by_value(self, value: int) -> Optional[Node]: p = self._head while p and p.data != value: p = p._next - return p def find_by_index(self, index: int) -> Optional[Node]: @@ -31,22 +31,21 @@ class SinglyLinkedList: while p and position != index: p = p._next position += 1 - return p def insert_value_to_head(self, value: int): new_node = Node(value) self.insert_node_to_head(new_node) - + def insert_node_to_head(self, new_node: Node): if new_node: new_node._next = self._head self._head = new_node - + def insert_value_after(self, node: Node, value: int): new_node = Node(value) self.insert_node_after(node, new_node) - + def insert_node_after(self, node: Node, new_node: Node): if not node or not new_node: return @@ -66,7 +65,7 @@ class SinglyLinkedList: current = self._head while current._next and current._next != node: current = current._next - if not current._next: # node is not even in the list + if not current._next: # node is not even in the list return new_node._next = node current._next = new_node @@ -83,13 +82,13 @@ class SinglyLinkedList: while current and current._next != node: current = current._next if not current: # node not in the list - return + return current._next = None def delete_by_value(self, value: int): if not self._head or not value: return - fake_head = Node(value+1) + fake_head = Node(value + 1) fake_head._next = self._head prev, current = fake_head, self._head while current: @@ -100,7 +99,7 @@ class SinglyLinkedList: if prev._next: prev._next = None self._head = fake_head._next # in case head.data == value - + def __repr__(self) -> str: nums = [] current = self._head @@ -112,6 +111,13 @@ class SinglyLinkedList: else: return "" + # 重写__iter__方法,方便for关键字调用打印值 + def __iter__(self): + node = self._head + while node: + yield node.data + node = node._next + def print_all(self): current = self._head if current: @@ -136,4 +142,6 @@ if __name__ == "__main__": l.delete_by_node(node11) l.delete_by_node(l._head) l.delete_by_value(13) - print(l) \ No newline at end of file + print(l) + for value in l: + print(value) From 2cd9e64fd7803550a3a7d7b2970471d834c888c1 Mon Sep 17 00:00:00 2001 From: q23wwwwe Date: Wed, 21 Nov 2018 18:21:22 +0800 Subject: [PATCH 108/141] =?UTF-8?q?[js]=E5=A2=9E=E5=8A=A0=E6=95=A3?= =?UTF-8?q?=E5=88=97=E8=A1=A8js=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- javascript/17_hashmap/HashTable.html | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 javascript/17_hashmap/HashTable.html diff --git a/javascript/17_hashmap/HashTable.html b/javascript/17_hashmap/HashTable.html new file mode 100644 index 0000000..a33f049 --- /dev/null +++ b/javascript/17_hashmap/HashTable.html @@ -0,0 +1,51 @@ + + + + + Title + + + + + From bf6e98f00d53dfcc2127cbaeab03525ee187fd04 Mon Sep 17 00:00:00 2001 From: q23wwwwe Date: Wed, 21 Nov 2018 23:11:39 +0800 Subject: [PATCH 109/141] =?UTF-8?q?[js]=E5=A2=9E=E5=8A=A0=E6=95=A3?= =?UTF-8?q?=E5=88=97=E8=A1=A8js=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- javascript/17_hashmap/HashTable.html | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/javascript/17_hashmap/HashTable.html b/javascript/17_hashmap/HashTable.html index a33f049..cd7cfe0 100644 --- a/javascript/17_hashmap/HashTable.html +++ b/javascript/17_hashmap/HashTable.html @@ -22,7 +22,7 @@ hash+=key.charCodeAt(i); } //为了得到比较小的数值,我们会用hash和任意数除余 - return hash%37; + return hash%30; } //向散列表增加一个新的项 put(key,value){ @@ -38,6 +38,13 @@ get(key){ console.log(this.table[this.loseHashCode(key)]) } + print(){ + for (var i=0;i From 31bab478b32231a80d73eb28c62e388b3521c623 Mon Sep 17 00:00:00 2001 From: q23wwwwe Date: Thu, 22 Nov 2018 20:22:09 +0800 Subject: [PATCH 110/141] Update HashTable.html --- javascript/17_hashmap/HashTable.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/17_hashmap/HashTable.html b/javascript/17_hashmap/HashTable.html index cd7cfe0..de04606 100644 --- a/javascript/17_hashmap/HashTable.html +++ b/javascript/17_hashmap/HashTable.html @@ -22,7 +22,7 @@ hash+=key.charCodeAt(i); } //为了得到比较小的数值,我们会用hash和任意数除余 - return hash%30; + return hash%37; } //向散列表增加一个新的项 put(key,value){ From 3b2b98e48343b5a6500f14f706008e383fda8c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E5=93=A5?= <109694228@qq.com> Date: Sun, 25 Nov 2018 14:31:48 +0800 Subject: [PATCH 111/141] red black tree implementation in Python --- python/26_red_black_tree/red_black_tree.py | 449 +++++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100644 python/26_red_black_tree/red_black_tree.py diff --git a/python/26_red_black_tree/red_black_tree.py b/python/26_red_black_tree/red_black_tree.py new file mode 100644 index 0000000..d3e1060 --- /dev/null +++ b/python/26_red_black_tree/red_black_tree.py @@ -0,0 +1,449 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from queue import Queue +import pygraphviz as pgv +import random + +OUTPUT_PATH = 'E:/' + + +class TreeNode: + def __init__(self, val=None, color=None): + self.val = val + assert color in ['r', 'b'] + self.color = 'red' if color == 'r' else 'black' + + self.left = None + self.right = None + self.parent = None + + def is_black(self): + return self.color == 'black' + + def set_black(self): + self.color = 'black' + return + + def set_red(self): + self.color = 'red' + + +class RedBlackTree: + """ + 红黑树实现 + 参考资料: + 1. 《算法导论》 + 第13章 红黑树 + 13.3 插入 p178 + 13.4 删除 p183 + + 2. 红黑树(二):删除 + https://zhuanlan.zhihu.com/p/25402654 + """ + def __init__(self, val_list=None): + self.root = None + self.black_leaf = TreeNode(color='b') # 共用的黑色叶子节点 + + # 可用数组初始化 + if type(val_list) is list: + for n in val_list: + assert type(n) is int + self.insert(n) + + def search(self, val): + """ + 搜索 + :param val: + :return: + """ + if self.root is None: + return None + + n = self.root + while n != self.black_leaf: + if val < n.val: + n = n.left + elif val > n.val: + n = n.right + else: + return n + return None + + def insert(self, val): + """ + 插入 + :param val: + :return: + """ + assert type(val) is int + + new_node = TreeNode(val, 'r') # 新插入的节点为红色 + + # 根节点 + if self.root is None: + self.root = new_node + else: + n = self.root + while n != self.black_leaf: # 黑色叶子节点 + p = n + if val < n.val: + n = n.left + elif val > n.val: + n = n.right + else: + raise KeyError('val:{} already exists') # 该值已存在,插入失败 + + if val < p.val: + p.left = new_node + else: + p.right = new_node + new_node.parent = p + + new_node.left = new_node.right = self.black_leaf + # 插入后调整 + self._insert_fixup(new_node) + + def _insert_fixup(self, node): + """ + 插入调整 + 参考资料:《算法导论》 13.3 p178-179 + :param node: + :return: + """ + n = node + while n is not self.root and not n.parent.is_black(): + # 父p 叔u 祖父g + p = self.parent(n) + u = self.bro(p) + g = self.parent(p) + + if not u.is_black(): # case 1 + p.set_black() # case 1 + u.set_black() # case 1 + g.set_red() # case 1 + n = g # case 1 + continue + + if p == g.left: # p为左结点 + if n == p.right: # case 2 + self.rotate_l(p) # case 2 + n, p = p, n # case 2 + p.set_black() # case 3 + g.set_red() # case 3 + self.rotate_r(g) # case 3 + else: # p为右节点 + if n == p.left: # case 2 + self.rotate_r(p) # case 2 + n, p = p, n # case 2 + p.set_black() # case 3 + g.set_red() # case 3 + self.rotate_l(g) # case 3 + + # 根节点强制置黑,有两种情况根节点是红色: + # 1. 新插入时是红色 + # 2. 经过case 1调整过后变红色 + self.root.color = 'black' + + def delete(self, val): + """ + 删除 + :param val: + :return: + """ + assert type(val) is int + + n = self.search(val) + if n is None: + print('can not find any nodes with value: {}'.format(val)) + return + + self._delete_node(n) + + def _delete_node(self, node): + """ + 删除节点内部实现 + 参考资料:《算法导论》 13.4 p183-184 + 实现方式有微调,当n有2个子节点时,将s拷贝至n,转为删除s(s最多有一个子节点) + :param node: + :return: + """ + n = node + + # n的子节点个数等于2 + if self.children_count(n) == 2: + # 寻找n的后继s + s = n.right + while s.left != self.black_leaf: + s = s.left + n.val = s.val + # 将删除n转化为删除s + n = s + + # n的子节点个数小于2 + if n.left == self.black_leaf: + c = n.right + else: + c = n.left + self._transplant(n, c) + + # 删除的节点是黑色,需要调整 + if n.is_black(): + self._delete_fixup(c) + return + + def _delete_fixup(self, node): + """ + 删除调整 + 参考资料:《算法导论》 13.4 p185-187 + :param node: + :return: + """ + n = node + while n != self.root and n.is_black(): + p = self.parent(n) + b = self.bro(n) + + # 左右节点对称 + if p.left == n: + if not b.is_black(): + b.set_black() # case 1 + p.set_red() # case 1 + self.rotate_l(p) # case 1 + # new bro after rotate + b = self.bro(n) # case 1 + + if b.left.is_black() and b.right.is_black(): + b.set_red() # case 2 + n = p # case 2 + else: + if b.right.is_black(): + b.left.set_black() # case 3 + b.set_red() # case 3 + self.rotate_r(b) # case 3 + # new bro after rotate + b = self.bro(n) # case 3 + + # 注意,因为p可能是红或黑,所以不能直接赋值颜色,只能copy + b.color = p.color # case 4 + p.set_black() # case 4 + b.right.set_black() # case 4 + self.rotate_l(p) # case 4 + # trick, 调整结束跳出while + n = self.root # case 4 + else: + if not b.is_black(): + b.set_black() # case 1 + p.set_red() # case 1 + self.rotate_r(p) # case 1 + # new bro after rotate + b = self.bro(n) # case 1 + + if b.left.is_black() and b.right.is_black(): + b.set_red() # case 2 + n = p # case 2 + else: + if b.left.is_black(): + b.right.set_black() # case 3 + b.set_red() # case 3 + self.rotate_l(b) # case 3 + # new bro after rotate + b = self.bro(n) # case 3 + + # 注意,因为p可能是红或黑,所以不能直接赋值颜色,只能copy + b.color = p.color # case 4 + p.set_black() # case 4 + b.left.set_black() # case 4 + self.rotate_r(p) # case 4 + # trick, 调整结束跳出while + n = self.root # case 4 + + # 将n设为黑色,从上面while循环跳出,情况有两种 + # 1. n是根节点,直接无视附加的黑色 + # 2. n是红色的节点,则染黑 + n.set_black() + + def _transplant(self, n1, n2): + """ + 节点移植, n2 -> n1 + :param n1: 原节点 + :param n2: 移植节点 + :return: + """ + if n1 == self.root: + if n2 != self.black_leaf: + self.root = n2 + n2.parent = None + else: + self.root = None # 只有删除根节点时会进来 + else: + p = self.parent(n1) + if p.left == n1: + p.left = n2 + else: + p.right = n2 + + n2.parent = p + + def rotate_l(self, node): + """ + 左旋 + :param node: + :return: + """ + if node is None: + return + + if node.right is self.black_leaf: + return + # raise Exception('try rotate left , but the node "{}" has no right child'.format(node.val)) + + p = self.parent(node) + x = node + y = node.right + + # node为根节点时,p为None,旋转后要更新根节点指向 + if p is not None: + if x == p.left: + p.left = y + else: + p.right = y + else: + self.root = y + + x.parent, y.parent = y, p + + if y.left != self.black_leaf: + y.left.parent = x + + x.right, y.left = y.left, x + + def rotate_r(self, node): + """ + 右旋 + :param node: + :return: + """ + if node is None: + return + + if node.left is self.black_leaf: + return + # raise Exception('try rotate left , but the node "{}" has no left child'.format(node.val)) + + p = self.parent(node) + x = node + y = node.left + + # 同左旋 + if p is not None: + if x == p.left: + p.left = y + else: + p.right = y + else: + self.root = y + + x.parent, y.parent = y, p + + if y.right is not None: + y.right.parent = x + + x.left, y.right = y.right, x + + @staticmethod + def bro(node): + """ + 获取兄弟节点 + :param node: + :return: + """ + if node is None or node.parent is None: + return None + else: + p = node.parent + if node == p.left: + return p.right + else: + return p.left + + @staticmethod + def parent(node): + """ + 获取父节点 + :param node: + :return: + """ + if node is None: + return None + else: + return node.parent + + def children_count(self, node): + """ + 获取子节点个数 + :param node: + :return: + """ + return 2 - [node.left, node.right].count(self.black_leaf) + + def draw_img(self, img_name='Red_Black_Tree.png'): + """ + 画图 + 用pygraphviz画出节点和箭头 + 箭头的红色和黑色分别代表左和右 + :param img_name: + :return: + """ + if self.root is None: + return + + tree = pgv.AGraph(directed=True, strict=True) + + q = Queue() + q.put(self.root) + + while not q.empty(): + n = q.get() + if n != self.black_leaf: # 黑色叶子的连线由各个节点自己画 + tree.add_node(n.val, color=n.color) + # 画父节点箭头 + # if n.parent is not None: + # tree.add_edge(n.val, n.parent.val) + + for c in [n.left, n.right]: + q.put(c) + color = 'red' if c == n.left else 'black' + if c != self.black_leaf: + tree.add_edge(n.val, c.val, color=color) + else: + tree.add_edge(n.val, 'None', color=color) + + tree.graph_attr['epsilon'] = '0.01' + tree.layout('dot') + tree.draw(OUTPUT_PATH + img_name) + return True + + +if __name__ == '__main__': + rbt = RedBlackTree() + + # insert + nums = list(range(1, 25)) + # random.shuffle(nums) + for num in nums: + rbt.insert(num) + + # search + search_num = 23 + n = rbt.search(search_num) + if n is not None: + print(n) + else: + print('node {} not found'.format(search_num)) + + # delete + rbt.delete(4) + + # draw image + rbt.draw_img('rbt.png') From 7935ed66ec4aabb0fc7c2e7a8914d5bcd6c92dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E5=93=A5?= <109694228@qq.com> Date: Sun, 25 Nov 2018 16:18:57 +0800 Subject: [PATCH 112/141] Update red_black_tree.py --- python/26_red_black_tree/red_black_tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/26_red_black_tree/red_black_tree.py b/python/26_red_black_tree/red_black_tree.py index d3e1060..ed67017 100644 --- a/python/26_red_black_tree/red_black_tree.py +++ b/python/26_red_black_tree/red_black_tree.py @@ -253,7 +253,7 @@ class RedBlackTree: # 注意,因为p可能是红或黑,所以不能直接赋值颜色,只能copy b.color = p.color # case 4 p.set_black() # case 4 - b.left.set_black() # case 4 + b.left.set_black() # case 4 self.rotate_r(p) # case 4 # trick, 调整结束跳出while n = self.root # case 4 @@ -329,7 +329,7 @@ class RedBlackTree: if node.left is self.black_leaf: return - # raise Exception('try rotate left , but the node "{}" has no left child'.format(node.val)) + # raise Exception('try rotate right , but the node "{}" has no left child'.format(node.val)) p = self.parent(node) x = node From cde443abbe3fee13939d0fe93e4c96f742a397fa Mon Sep 17 00:00:00 2001 From: yuan <1103916076@qq.com> Date: Mon, 26 Nov 2018 14:47:46 +0800 Subject: [PATCH 113/141] =?UTF-8?q?=E6=A1=B6=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/13_sort/bucketSort.php | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 php/13_sort/bucketSort.php diff --git a/php/13_sort/bucketSort.php b/php/13_sort/bucketSort.php new file mode 100644 index 0000000..5b59a86 --- /dev/null +++ b/php/13_sort/bucketSort.php @@ -0,0 +1,50 @@ + $value) { + $index = ceil(($value-$min)/$length); + $buckets[$index][] = $value; + } + + $result = []; + for($i=0;$i<$bucketNumber;$i++) { + $bucket = $buckets[$i]; + $length = count($bucket); + //如果桶内元素为空,跳过这个桶 + if($length == 0) { + continue; + } + if( $length > 10) { + $bucket = bucketSort($bucket,$length); + } + + quickSort($bucket,0,count($bucket)-1); + $result = array_merge($result,$bucket); + } + return $result; +} + From 93ea3c458db12524b9affb662dd9d1494ce513f3 Mon Sep 17 00:00:00 2001 From: yuan <1103916076@qq.com> Date: Mon, 26 Nov 2018 14:49:45 +0800 Subject: [PATCH 114/141] =?UTF-8?q?=E8=AE=A1=E6=95=B0=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/13_sort/countingSort.php | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 php/13_sort/countingSort.php diff --git a/php/13_sort/countingSort.php b/php/13_sort/countingSort.php new file mode 100644 index 0000000..edef0b8 --- /dev/null +++ b/php/13_sort/countingSort.php @@ -0,0 +1,43 @@ + $value) { + $countScore[$value]++; + } + + /** + * 顺序求和 + */ + for($i=1;$i<=5;$i++) { + $countScore[$i] += $countScore[$i-1]; + } + /** + * 排序 + */ + foreach ($score as $key => $value) { + $countScore[$value] --; + $temp[$countScore[$value]] = $value; + } + //copy + for($i=0;$i<$length;$i++) { + $score[$i] = $temp[$i]; + } + return $score; +} \ No newline at end of file From b1e6c24c149eada0ec9ebfd258f93231c0a4b80f Mon Sep 17 00:00:00 2001 From: yuan <1103916076@qq.com> Date: Mon, 26 Nov 2018 14:54:53 +0800 Subject: [PATCH 115/141] =?UTF-8?q?=E5=9F=BA=E6=95=B0=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/13_sort/radixSort.php | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 php/13_sort/radixSort.php diff --git a/php/13_sort/radixSort.php b/php/13_sort/radixSort.php new file mode 100644 index 0000000..8da3560 --- /dev/null +++ b/php/13_sort/radixSort.php @@ -0,0 +1,48 @@ + + */ +function radixSort(array &$numbers,$loop) { + + $divisor = pow(10,$loop);//除数 主要决定比较个位数、百位..... + $buckets = (new \SplFixedArray(10))->toArray(); + foreach ($numbers as $key => $value) { + $index = ($value/$divisor)%10;//计算该数字在哪个桶中 + $buckets[$index][] = $value; + } + /** + * 从桶中取出数字 + */ + $k=0; + for($i=0;$i<10;$i++) { + while(count($buckets[$i]) > 0) { + $numbers[$k++] = array_shift($buckets[$i]); + } + } +} From 683a21cb46a14143f165be0af46a7e60e664b9e0 Mon Sep 17 00:00:00 2001 From: yuan <1103916076@qq.com> Date: Mon, 26 Nov 2018 14:56:27 +0800 Subject: [PATCH 116/141] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=82=AE=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/13_sort/radixSort.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/13_sort/radixSort.php b/php/13_sort/radixSort.php index 8da3560..3f4164b 100644 --- a/php/13_sort/radixSort.php +++ b/php/13_sort/radixSort.php @@ -26,7 +26,7 @@ var_dump($numbers); * * @return void * @date 2018/11/26 - * @author yuanliandu + * @author yuanliandu */ function radixSort(array &$numbers,$loop) { From c930e9da85001ee59b8fa684829bbe19fde867d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E5=93=A5?= <109694228@qq.com> Date: Mon, 26 Nov 2018 20:03:25 +0800 Subject: [PATCH 117/141] Create binary_heap.py --- python/28_binary_heap/binary_heap.py | 194 +++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 python/28_binary_heap/binary_heap.py diff --git a/python/28_binary_heap/binary_heap.py b/python/28_binary_heap/binary_heap.py new file mode 100644 index 0000000..345f70a --- /dev/null +++ b/python/28_binary_heap/binary_heap.py @@ -0,0 +1,194 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import math +import random + + +class BinaryHeap: + """ + 大顶堆 + """ + def __init__(self, data=None): + self._data = [] + if type(data) is list: + map(self._type_assert, data) + self._data = data + # self.heapify() + + self._length = len(self._data) + + def heapify(self): + """ + 堆化 + :return: + """ + self._heapify(self._data, self._length-1) + + def _heapify(self, data, tail_idx): + """ + 堆化内部实现 + :param data: 需要堆化的数据 + :param tail_idx: 尾元素的索引 + :return: + """ + # heapify data[:tail_idx+1] + if tail_idx <= 0: + return + + # idx of the Last Parent node + lp = (tail_idx - 1) // 2 + + for i in range(lp, -1, -1): + self._heap_down(data, i, tail_idx) + + @staticmethod + def _heap_down(data, idx, tail_idx): + """ + 将指定的位置堆化 + :param data: 需要堆化的数据 + :param idx: data: 中需要堆化的位置 + :param tail_idx: 尾元素的索引 + :return: + """ + assert type(data) is list + + lp = (tail_idx - 1) // 2 + # top-down + while idx <= lp: + # Left and Right Child index + lc = 2 * idx + 1 + rc = lc + 1 + + # right child exists + if rc <= tail_idx: + tmp = lc if data[lc] > data[rc] else rc + else: + tmp = lc + + if data[tmp] > data[idx]: + data[tmp], data[idx] = data[idx], data[tmp] + idx = tmp + else: + break + + def insert(self, num): + """ + 插入 + :param num: + :return: + """ + if self._insert(self._data, num): + self._length += 1 + + @staticmethod + def _insert(data, num): + """ + 堆中插入元素的内部实现 + :param data: + :param num: + :return: + """ + assert type(data) is list + assert type(num) is int + + data.append(num) + length = len(data) + + # idx of New Node + nn = length - 1 + # bottom-up + while nn > 0: + p = (nn-1) // 2 + if data[nn] > data[p]: + data[nn], data[p] = data[p], data[nn] + nn = p + else: + break + + return True + + def delete_root(self): + """ + 删除根节点 + :return: + """ + if self._delete_root(self._data): + self._length -= 1 + + @staticmethod + def _delete_root(data): + """ + 删除根节点内部实现 + :param data: + :return: + """ + assert type(data) is list + + length = len(data) + if length == 0: + return False + + data[0], data[-1] = data[-1], data[0] + data.pop() + length -= 1 + + # length == 0 or == 1, return + if length > 1: + BinaryHeap._heap_down(data, 0, length-1) + + return True + + @staticmethod + def _type_assert(num): + assert type(num) is int + + @staticmethod + def _draw_heap(data): + """ + 格式化打印 + :param data: + :return: + """ + length = len(data) + + if length == 0: + return 'empty heap' + + ret = '' + for i, n in enumerate(data): + ret += str(n) + # 每行最后一个换行 + if i == 2**int(math.log(i+1, 2)+1) - 2 or i == len(data) - 1: + ret += '\n' + else: + ret += ', ' + + return ret + + def __repr__(self): + return self._draw_heap(self._data) + + +if __name__ == '__main__': + nums = list(range(10)) + random.shuffle(nums) + + bh = BinaryHeap(nums) + print('--- before heapify ---') + print(bh) + + # heapify + bh.heapify() + print('--- after heapify ---') + print(bh) + + # insert + bh.insert(8) + print('--- insert ---') + print(bh) + + # delete_root + bh.delete_root() + print('--- delete root ---') + print(bh) From 819710ea827c6518cb9bf25a013430aa5a7e6b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E5=93=A5?= <109694228@qq.com> Date: Mon, 26 Nov 2018 20:09:25 +0800 Subject: [PATCH 118/141] Create binary_heap_sort.py --- python/28_binary_heap/binary_heap_sort.py | 47 +++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 python/28_binary_heap/binary_heap_sort.py diff --git a/python/28_binary_heap/binary_heap_sort.py b/python/28_binary_heap/binary_heap_sort.py new file mode 100644 index 0000000..edfd86b --- /dev/null +++ b/python/28_binary_heap/binary_heap_sort.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from binary_heap import BinaryHeap + + +class BinaryHeapSort(BinaryHeap): + def __init__(self): + super(BinaryHeapSort, self).__init__() + + def sort(self, nums): + """ + 排序 + 1. 堆化,大顶堆 + 2. 排序,从后往前遍历,首尾元素互换,子数组堆化 + :param nums: + :return: + """ + assert type(nums) is list + length = len(nums) + + if length <= 1: + return + + map(self._type_assert, nums) + + # heapify + self._heapify(nums, length-1) + + # sort + for i in range(length-1, 0, -1): + nums[0], nums[i] = nums[i], nums[0] + self._heap_down(nums, 0, i-1) + + return + + +if __name__ == '__main__': + bhs = BinaryHeapSort() + nums = [3, 5, 2, 6, 1, 7, 6] + + print('--- before sort ---') + print(nums) + + bhs.sort(nums) + print('--- after sort ---') + print(nums) From 018c337fa2cc5756963e068d9ffa95619e7746c7 Mon Sep 17 00:00:00 2001 From: nameczz Date: Mon, 26 Nov 2018 23:38:43 +0800 Subject: [PATCH 119/141] add Javascript 28_heapsort --- javascript/28_heapsort/heap-sort.js | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 javascript/28_heapsort/heap-sort.js diff --git a/javascript/28_heapsort/heap-sort.js b/javascript/28_heapsort/heap-sort.js new file mode 100644 index 0000000..572ddf0 --- /dev/null +++ b/javascript/28_heapsort/heap-sort.js @@ -0,0 +1,65 @@ +/** + * 堆排序 + * + * Author: nameczz + */ + +// 忽视数组的第一位 +class HeapSort { + constructor(originArray) { + this.originArray = originArray + console.log(this.originArray) + } + buildHeap() { + const arr = this.originArray + const startIndex = Math.floor(arr.length) + for (let i = startIndex; i >= 1; i--) { + this.heapify(arr, arr.length, i) + } + return arr + } + + heapify(arr, len, i) { + while (true) { + let maxPos = i + // 如果index i拥有叶左节点 并且左节点较大 + if (i * 2 <= len && arr[i] < arr[i * 2]) { + maxPos = i * 2 + } + // 如果index i拥有叶右节点 与Max节点比较大小,选出父/左/右中最大的一个 + if (i * 2 + 1 <= len && arr[maxPos] < arr[i * 2 + 1]) { + maxPos = i * 2 + 1 + } + if (maxPos === i) break // 循环直到i节点为最大值 + this.swap(arr, i, maxPos) // 交换位置, 父节点为父/左/右中最大的一个 + i = maxPos // i为左/右节点,并尝试向下查找更大的值 + } + } + + sort() { + const arr = this.buildHeap() // 先建堆 + let len = arr.length - 1 + while (len > 1) { + this.swap(arr, 1, len) // 交换顶元素和最后一位。顶元素永远是最大的。 + len-- + this.heapify(arr, len, 1) //剩下的元素重新建堆 直到len === 1 停止 + } + console.log(arr) + } + + swap(arr, i, max) { + let temp = arr[i] + arr[i] = arr[max] + arr[max] = temp + } +} + +const arr = [null] +let i = 0 +while (i <= 10) { + const num = Math.floor(Math.random() * 100) + arr.push(num) + i++ +} +const testHeap = new HeapSort(arr) +testHeap.sort() \ No newline at end of file From ce8b8e312f4fdb95ec64402bdebf1eaf4e356cad Mon Sep 17 00:00:00 2001 From: Wenru Dong Date: Mon, 26 Nov 2018 16:36:32 +0000 Subject: [PATCH 120/141] max-heap in python --- python/28_heap/heap.py | 96 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 python/28_heap/heap.py diff --git a/python/28_heap/heap.py b/python/28_heap/heap.py new file mode 100644 index 0000000..f3961c6 --- /dev/null +++ b/python/28_heap/heap.py @@ -0,0 +1,96 @@ +""" + Max-heap + + Author: Wenru Dong +""" + +from typing import Optional, List + +class Heap: + def __init__(self, capacity: int): + self._data = [0] * (capacity + 1) + self._capacity = capacity + self._count = 0 + + @classmethod + def _parent(cls, child_index: int) -> int: + """The parent index.""" + return child_index // 2 + + @classmethod + def _left(cls, parent_index: int) -> int: + """The left child index.""" + return 2 * parent_index + + @classmethod + def _right(cls, parent_index: int) -> int: + """The right child index.""" + return 2 * parent_index + 1 + + def _siftup(self) -> None: + i, parent = self._count, Heap._parent(self._count) + while parent and self._data[i] > self._data[parent]: + self._data[i], self._data[parent] = self._data[parent], self._data[i] + i, parent = parent, Heap._parent(parent) + + @classmethod + def _siftdown(cls, a: List[int], count: int, root_index: int = 1) -> None: + i = larger_child_index = root_index + while True: + left, right = cls._left(i), cls._right(i) + if left <= count and a[i] < a[left]: + larger_child_index = left + if right <= count and a[larger_child_index] < a[right]: + larger_child_index = right + if larger_child_index == i: break + a[i], a[larger_child_index] = a[larger_child_index], a[i] + i = larger_child_index + + def insert(self, value: int) -> None: + if self._count >= self._capacity: return + self._count += 1 + self._data[self._count] = value + self._siftup() + + def remove_max(self) -> Optional[int]: + if self._count: + result = self._data[1] + self._data[1] = self._data[self._count] + self._count -= 1 + Heap._siftdown(self._data, self._count) + return result + + @classmethod + def build_heap(cls, a: List[int]) -> None: + """Data in a needs to start from index 1.""" + for i in range((len(a) - 1)//2, 0, -1): + cls._siftdown(a, len(a) - 1, i) + + @classmethod + def sort(cls, a: List[int]) -> None: + """Data in a needs to start from index 1.""" + cls.build_heap(a) + k = len(a) - 1 + while k > 1: + a[1], a[k] = a[k], a[1] + k -= 1 + cls._siftdown(a, k) + + def __repr__(self): + return self._data[1 : self._count + 1].__repr__() + + +if __name__ == "__main__": + hp = Heap(10) + hp.insert(3) + hp.insert(9) + hp.insert(1) + hp.insert(8) + hp.insert(7) + hp.insert(3) + print(hp) + for _ in range(6): + print(hp.remove_max()) + a = [0, 6, 3, 4, 0, 9, 2, 7, 5, -2, 8, 1, 6, 10] + Heap.sort(a) + print(a[1:]) \ No newline at end of file From 06ac246f987873406f48d70c9a71111c2c32bc49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E5=93=A5?= <109694228@qq.com> Date: Tue, 27 Nov 2018 10:53:31 +0800 Subject: [PATCH 121/141] Update binary_heap.py --- python/28_binary_heap/binary_heap.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/28_binary_heap/binary_heap.py b/python/28_binary_heap/binary_heap.py index 345f70a..c223e62 100644 --- a/python/28_binary_heap/binary_heap.py +++ b/python/28_binary_heap/binary_heap.py @@ -12,7 +12,7 @@ class BinaryHeap: def __init__(self, data=None): self._data = [] if type(data) is list: - map(self._type_assert, data) + self._type_assert(data) self._data = data # self.heapify() @@ -140,8 +140,10 @@ class BinaryHeap: return True @staticmethod - def _type_assert(num): - assert type(num) is int + def _type_assert(nums): + assert type(nums) is list + for n in nums: + assert type(n) is int @staticmethod def _draw_heap(data): From b7664b98eab93bcf692af2ad17952cdefa847aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E5=93=A5?= <109694228@qq.com> Date: Tue, 27 Nov 2018 10:54:07 +0800 Subject: [PATCH 122/141] Update binary_heap_sort.py --- python/28_binary_heap/binary_heap_sort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/28_binary_heap/binary_heap_sort.py b/python/28_binary_heap/binary_heap_sort.py index edfd86b..f0506d4 100644 --- a/python/28_binary_heap/binary_heap_sort.py +++ b/python/28_binary_heap/binary_heap_sort.py @@ -22,7 +22,7 @@ class BinaryHeapSort(BinaryHeap): if length <= 1: return - map(self._type_assert, nums) + self._type_assert(nums) # heapify self._heapify(nums, length-1) From 350c3237a7ac1f9359e036c5677f45c108135bf4 Mon Sep 17 00:00:00 2001 From: yuan <1103916076@qq.com> Date: Tue, 27 Nov 2018 15:56:11 +0800 Subject: [PATCH 123/141] =?UTF-8?q?16-=E4=BA=8C=E5=88=86=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E7=BB=99=E5=AE=9A=E5=80=BC=E3=80=81=E6=B1=82=E5=B9=B3=E6=96=B9?= =?UTF-8?q?=E6=A0=B9=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/15_binary/binary.php | 98 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 php/15_binary/binary.php diff --git a/php/15_binary/binary.php b/php/15_binary/binary.php new file mode 100644 index 0000000..e508451 --- /dev/null +++ b/php/15_binary/binary.php @@ -0,0 +1,98 @@ + $high) { + return -1; + } + + /** + * notice2 mid计算 + */ + $mid = $low + (($high - $low) >> 1); + if ($numbers[$mid] > $find) { + //notice3 high值更新 + return search($numbers, $low, $mid -1, $find); + } elseif ($numbers[$mid] < $find) { + //notice4 low值更新 + return search($numbers, $mid + 1, $high, $find); + } else { + return $mid; + } +} + +/** + * 求数字的平方根,保留6位小数 + * @param [type] $number + * + * @return void + * @date 2018/11/26 + * @author yuanliandu + */ +function squareRoot($number) +{ + if ($number < 0) { + return -1; + } elseif ($number < 1) { + $min = $number; + $max = 1; + } else { + $min = 1; + $max = $number; + } + $mid = $min + ($max - $min) / 2; + while (getDecimalPlaces($mid) < 6) { + $square = $mid * $mid; + if ($square > $number) { + $max = $mid; + } elseif ($square == $number) { + return $mid; + } else { + $min = $mid; + } + $mid = $min + ($max - $min) / 2; + } + return $mid; +} + +/** + * 计算数字小数点后有几位数字 + * @param [type] $number + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function getDecimalPlaces($number) +{ + $temp = explode('.', $number); + return strlen($temp[1]); +} + +// 测试二分查找给定值 +$numbers = [0, 1, 2, 3, 3, 4, 5, 6, 7, 9]; +$find = 1; +var_dump(binarySearch($numbers,$find)); + +//测试求平方根 +var_dump(squareRoot(3)); \ No newline at end of file From c078ee3a6ba7bc3f5e539d9a8ac3a1232a1e0631 Mon Sep 17 00:00:00 2001 From: yuan <1103916076@qq.com> Date: Tue, 27 Nov 2018 16:04:32 +0800 Subject: [PATCH 124/141] =?UTF-8?q?=E4=BA=8C=E5=88=86=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E5=8F=98=E7=A7=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- php/16_binary/binary.php | 191 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 php/16_binary/binary.php diff --git a/php/16_binary/binary.php b/php/16_binary/binary.php new file mode 100644 index 0000000..fc27a4c --- /dev/null +++ b/php/16_binary/binary.php @@ -0,0 +1,191 @@ + + */ +function findFirstEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] > $find) { + $high = $mid - 1; + }else if($numbers[$mid] < $find) { + $low = $mid + 1; + }else { + /** + * 如果是第一个元素,或之前一个元素不等于我们要找的值 + * 我们就找到了第一个=find的element + */ + if($mid==0 || $numbers[$mid-1]!=$find) { + return $mid; + }else { + $high = $mid - 1; + } + } + } + + return -1; +} + +/** + * 找到最后一个=find的元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function findLastEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] > $find) { + $high = $mid - 1; + }else if($numbers[$mid] < $find) { + $low = $mid + 1; + }else { + /** + * 如果mid是最后一个元素的index + * 或mid后一个元素!=我们要找的值 + * 则找到了最后一个=find的value + */ + if($mid==$length-1 || $numbers[$mid+1]!=$find) { + return $mid; + }else { + $low = $mid + 1; + } + } + } + + return -1; +} + +/** + * 找到第一个大于等于find的元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function findFirstGreaterEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] >= $find) { + if ($mid == 0 || $numbers[$mid-1] < $find) { + return $mid; + }else { + $high = $mid - 1; + } + }else { + $low = $mid + 1; + } + } + return -1; +} + +/** + * 找到最后一个小于等于find的元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function findLastLessEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] <= $find) { + if($mid==$length-1 || $numbers[$mid+1]> $find) { + return $mid; + } + $low = $mid + 1; + }else { + $high = $mid - 1; + } + } + return -1; +} + + + + + +/** + * 循环数组中找指定元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function searchCircularArray(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] === $find) { + return $mid; + } + + if($numbers[$low] > $numbers[$mid]) { + // 后半部分是有序数组 + if(($numbers[$mid] < $find) && ($numbers[$high] >= $find)) { + if($numbers[$high] === $find) return $high; + //在后半个区间内 + $low = $mid + 1; + }else { + $high = $mid - 1; + } + }else { + // 前半部分是有序的 + if(($numbers[$low] <= $find) && ($numbers[$mid] > $find)) { + // 在有序区间内 + if($numbers[$low] === $find) return $low; + $high = $mid - 1; + }else { + $low = $mid + 1; + } + } + + } + return -1; +} + +/*** + * 测试 + */ +$numbers = [1,2,3,3,3,4,5,6,8,11,13]; +$find = 3; + +var_dump(findFirstEqual($numbers,$find));//找到第一个等于find的元素 +var_dump(findFirstGreaterEqual($numbers,$find));//找到第一个大于等于find的元素 +var_dump(findLastEqual($numbers,$find));//找到最后一个=find的元素 +var_dump(findLastLessEqual($numbers,$find));//找到最后一个小于等于find的元素 + + +//测试在循环数组中找到指定数字 +$numbers = [9,10,1,2,3,4,5,6,7,8]; +$find = 2; +var_dump(searchCircularArray($numbers,$find)); From ea2e6136e89da5a4eeb2317c2e8fa0636cabbe1d Mon Sep 17 00:00:00 2001 From: gz1301 <109694228@qq.com> Date: Wed, 28 Nov 2018 15:30:36 +0800 Subject: [PATCH 125/141] heap capacity --- python/28_binary_heap/binary_heap.py | 53 +++++++++++++++++++--------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/python/28_binary_heap/binary_heap.py b/python/28_binary_heap/binary_heap.py index c223e62..5e5ddf0 100644 --- a/python/28_binary_heap/binary_heap.py +++ b/python/28_binary_heap/binary_heap.py @@ -9,12 +9,14 @@ class BinaryHeap: """ 大顶堆 """ - def __init__(self, data=None): + def __init__(self, data=None, capacity=100): self._data = [] + self._capacity = capacity if type(data) is list: + if len(data) > self._capacity: + raise Exception('Heap oversize, capacity:{}, data size:{}'.format(self._capacity, len(data))) self._type_assert(data) self._data = data - # self.heapify() self._length = len(self._data) @@ -78,8 +80,11 @@ class BinaryHeap: :param num: :return: """ - if self._insert(self._data, num): - self._length += 1 + if self._length < self._capacity: + if self._insert(self._data, num): + self._length += 1 + return True + return False @staticmethod def _insert(data, num): @@ -108,18 +113,30 @@ class BinaryHeap: return True - def delete_root(self): + def get_top(self): """ - 删除根节点 + 取堆顶 :return: """ - if self._delete_root(self._data): + if self._length <= 0: + return None + return self._data[0] + + def remove_top(self): + """ + 取堆顶 + :return: + """ + ret = None + if self._length > 0: + ret = self._remove_top(self._data) self._length -= 1 + return ret @staticmethod - def _delete_root(data): + def _remove_top(data): """ - 删除根节点内部实现 + 取堆顶内部实现 :param data: :return: """ @@ -127,17 +144,17 @@ class BinaryHeap: length = len(data) if length == 0: - return False + return None data[0], data[-1] = data[-1], data[0] - data.pop() + ret = data.pop() length -= 1 # length == 0 or == 1, return if length > 1: BinaryHeap._heap_down(data, 0, length-1) - return True + return ret @staticmethod def _type_assert(nums): @@ -186,11 +203,15 @@ if __name__ == '__main__': print(bh) # insert - bh.insert(8) print('--- insert ---') + if bh.insert(8): + print('insert success') + else: + print('insert fail') print(bh) - # delete_root - bh.delete_root() - print('--- delete root ---') + # get top + print('--- get top ---') + print('get top of the heap: {}'.format(bh.get_top())) + bh.remove_top() print(bh) From 8b9c42b1b790e318f5e7d29f3215f90e82ac7bdc Mon Sep 17 00:00:00 2001 From: gz1301 <109694228@qq.com> Date: Wed, 28 Nov 2018 16:45:04 +0800 Subject: [PATCH 126/141] heap applications --- python/28_binary_heap/heap.py | 178 ++++++++++++++++++++++++ python/28_binary_heap/priority_queue.py | 117 ++++++++++++++++ python/28_binary_heap/top_k.py | 39 ++++++ 3 files changed, 334 insertions(+) create mode 100644 python/28_binary_heap/heap.py create mode 100644 python/28_binary_heap/priority_queue.py create mode 100644 python/28_binary_heap/top_k.py diff --git a/python/28_binary_heap/heap.py b/python/28_binary_heap/heap.py new file mode 100644 index 0000000..b934057 --- /dev/null +++ b/python/28_binary_heap/heap.py @@ -0,0 +1,178 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import math +import random + + +class Heap: + def __init__(self, nums=None, capacity=100): + self._data = [] + self._capacity = capacity + if type(nums) == list and len(nums) <= self._capacity: + for n in nums: + assert type(n) is int + self._data.append(n) + self._length = len(self._data) + self._heapify() + + def _heapify(self): + if self._length <= 1: + return + + # idx of the Last Parent node + lp = (self._length - 2) // 2 + + for i in range(lp, -1, -1): + self._heap_down(i) + + def _heap_down(self, idx): + pass + + def insert(self, num): + pass + + def get_top(self): + if self._length <= 0: + return None + return self._data[0] + + def remove_top(self): + if self._length <= 0: + return None + + self._data[0], self._data[-1] = self._data[-1], self._data[0] + ret = self._data.pop() + self._length -= 1 + self._heap_down(0) + + return ret + + def get_data(self): + return self._data + + def get_length(self): + return self._length + + @staticmethod + def _draw_heap(data): + """ + 格式化打印 + :param data: + :return: + """ + length = len(data) + + if length == 0: + return 'empty heap' + + ret = '' + for i, n in enumerate(data): + ret += str(n) + # 每行最后一个换行 + if i == 2 ** int(math.log(i + 1, 2) + 1) - 2 or i == len(data) - 1: + ret += '\n' + else: + ret += ', ' + + return ret + + def __repr__(self): + return self._draw_heap(self._data) + + +class MaxHeap(Heap): + def _heap_down(self, idx): + if self._length <= 1: + return + + lp = (self._length - 2) // 2 + + while idx <= lp: + lc = 2 * idx + 1 + rc = lc + 1 + + if rc <= self._length-1: + tmp = lc if self._data[lc] > self._data[rc] else rc + else: + tmp = lc + + if self._data[tmp] > self._data[idx]: + self._data[tmp], self._data[idx] = self._data[idx], self._data[tmp] + idx = tmp + else: + break + + def insert(self, num): + if self._length >= self._capacity: + return False + + self._data.append(num) + self._length += 1 + + nn = self._length - 1 + while nn > 0: + p = (nn-1) // 2 + + if self._data[nn] > self._data[p]: + self._data[nn], self._data[p] = self._data[p], self._data[nn] + nn = p + else: + break + + return True + + +class MinHeap(Heap): + def _heap_down(self, idx): + if self._length <= 1: + return + + lp = (self._length - 2) // 2 + + while idx <= lp: + lc = 2 * idx + 1 + rc = lc + 1 + + if rc <= self._length-1: + tmp = lc if self._data[lc] < self._data[rc] else rc + else: + tmp = lc + + if self._data[tmp] < self._data[idx]: + self._data[tmp], self._data[idx] = self._data[idx], self._data[tmp] + idx = tmp + else: + break + + def insert(self, num): + if self._length >= self._capacity: + return False + + self._data.append(num) + self._length += 1 + + nn = self._length - 1 + while nn > 0: + p = (nn-1) // 2 + + if self._data[nn] < self._data[p]: + self._data[nn], self._data[p] = self._data[p], self._data[nn] + nn = p + else: + break + + return True + + +if __name__ == '__main__': + nums = list(range(10)) + random.shuffle(nums) + + max_h = MaxHeap(nums) + print('--- max heap ---') + print(max_h) + + print('--- min heap ---') + min_h = MinHeap(nums) + print(min_h) diff --git a/python/28_binary_heap/priority_queue.py b/python/28_binary_heap/priority_queue.py new file mode 100644 index 0000000..3264534 --- /dev/null +++ b/python/28_binary_heap/priority_queue.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import math + + +class QueueNode: + def __init__(self, priority, data=None): + assert type(priority) is int and priority >= 0 + self.priority = priority + self.data = data + + def __repr__(self): + return str((self.priority, self.data)) + + +class PriorityQueue: + def __init__(self, capacity=100): + self._capacity = capacity + self._q = [] + self._length = 0 + + def enqueue(self, priority, data=None): + if self._length >= self._capacity: + return False + + new_node = QueueNode(priority, data) + self._q.append(new_node) + self._length += 1 + + # update queue + nn = self._length - 1 + while nn > 0: + p = (nn - 1) // 2 + if self._q[nn].priority < self._q[p].priority: + self._q[nn], self._q[p] = self._q[p], self._q[nn] + nn = p + else: + break + + return True + + def dequeue(self): + if self._length <= 0: + raise Exception('the queue is empty....') + + self._q[0], self._q[-1] = self._q[-1], self._q[0] + ret = self._q.pop() + self._length -= 1 + + if self._length > 1: + # update queue + lp = (self._length - 2) // 2 + idx = 0 + + while idx <= lp: + lc = 2 * idx + 1 + rc = lc + 1 + + if rc <= self._length - 1: + tmp = lc if self._q[lc].priority < self._q[rc].priority else rc + else: + tmp = lc + + if self._q[tmp].priority < self._q[idx].priority: + self._q[tmp], self._q[idx] = self._q[idx], self._q[tmp] + idx = tmp + else: + break + return ret + + def get_length(self): + return self._length + + @staticmethod + def _draw_heap(data): + """ + 格式化打印 + :param data: + :return: + """ + length = len(data) + + if length == 0: + return 'empty' + + ret = '' + for i, n in enumerate(data): + ret += str(n) + # 每行最后一个换行 + if i == 2 ** int(math.log(i + 1, 2) + 1) - 2 or i == len(data) - 1: + ret += '\n' + else: + ret += ', ' + + return ret + + def __repr__(self): + def formater(node): + assert type(node) is QueueNode + return node.priority, node.data + + data = list(map(formater, self._q)) + return self._draw_heap(data) + + +if __name__ == '__main__': + pq = PriorityQueue() + pq.enqueue(5, 'Watch TV') + pq.enqueue(2, 'Learning') + pq.enqueue(10, 'Go Sleep') + pq.enqueue(0, 'Go Home') + pq.enqueue(7, 'Mobile Games') + print(pq) + + while pq.get_length() > 0: + print(pq.dequeue()) diff --git a/python/28_binary_heap/top_k.py b/python/28_binary_heap/top_k.py new file mode 100644 index 0000000..8123a70 --- /dev/null +++ b/python/28_binary_heap/top_k.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import random +from heap import MinHeap + + +def top_k(nums, k): + """ + 返回数组的前k大元素 + :param nums: + :param k: + :return: + """ + if len(nums) <= k: + return nums + + min_h = MinHeap(nums[:k], k) + for i in range(k, len(nums)): + tmp = min_h.get_top() + if nums[i] > tmp: + min_h.remove_top() + min_h.insert(nums[i]) + + return min_h.get_data() + + +if __name__ == '__main__': + nums = [] + k = 3 + + for i in range(20): + nums.append(random.randint(1, 100)) + + print('--- nums ---') + print(nums) + + print('--- top {} ---'.format(k)) + print(top_k(nums, k)) From f74a14c60d63f120b32b192c7cc4ee8a51710ef2 Mon Sep 17 00:00:00 2001 From: chenrong Date: Thu, 29 Nov 2018 17:05:38 +0800 Subject: [PATCH 127/141] =?UTF-8?q?=E6=8F=92=E5=85=A5=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=EF=BC=88=E6=8F=92=E5=85=A5=E4=BD=8D=E7=BD=AE=EF=BC=8C=E4=BB=8E?= =?UTF-8?q?=E5=A4=B4=E8=87=B3=E5=B0=BE=E6=90=9C=E7=B4=A2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- java/11_sorts/InsertionSortAdd.java | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 java/11_sorts/InsertionSortAdd.java diff --git a/java/11_sorts/InsertionSortAdd.java b/java/11_sorts/InsertionSortAdd.java new file mode 100644 index 0000000..31c436e --- /dev/null +++ b/java/11_sorts/InsertionSortAdd.java @@ -0,0 +1,48 @@ +package sorts; + +import java.util.Arrays; + +/** + * 插入排序(插入位置,从头至尾搜索) + * @Author: ooooor + */ +public class InsertionSortAdd { + + public static void main(String[] args) { + int[] data = new int[]{4, 6, 5, 3, 7, 1, 2}; + fromStartToEnd(Arrays.copyOf(data, data.length)); + System.out.println(Arrays.toString(data)); + } + + /** + * 查询插入位置时, 从头至尾搜索 + * @param data + */ + private static void fromStartToEnd(int[] data) { + for (int i=1; i < data.length; i++) { + int value = data[i]; + + int[] tmp = new int[2]; + int change = i; + for (int j=0; j < i; j++) { + if(value >= data[j]) { + continue; + } + + int index = j%2; + if (change == i) { + tmp[Math.abs(index-1)] = data[j]; + change = j; + } + tmp[index] = data[j+1]; + if (0 == index) { + data[j+1] = tmp[index+1]; + } else { + data[j+1] = tmp[index-1]; + } + } + data[change] = value; + } + } + +} From 296c7d471a03ca8fcda2623ad5f5a84632d89535 Mon Sep 17 00:00:00 2001 From: xiaobudongzhang Date: Thu, 29 Nov 2018 22:24:16 +0800 Subject: [PATCH 128/141] Update array.go --- go/05_array/array.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/05_array/array.go b/go/05_array/array.go index ce2e05a..c1a861d 100644 --- a/go/05_array/array.go +++ b/go/05_array/array.go @@ -34,7 +34,7 @@ func (this *Array) Len() uint { //判断索引是否越界 func (this *Array) isIndexOutOfRange(index uint) bool { - if index >= this.length { + if index >= uint(cap(this.data)) { return true } return false From 9c788bde5458ead84dc5f9b0063202c7f2915ef2 Mon Sep 17 00:00:00 2001 From: lijialin Date: Fri, 30 Nov 2018 14:43:31 +0800 Subject: [PATCH 129/141] =?UTF-8?q?=E6=95=B0=E7=BB=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BB=BB=E6=84=8F=E4=BD=8D=E7=BD=AE=E6=8F=92=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/05_array/myarray.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/python/05_array/myarray.py b/python/05_array/myarray.py index 03a07ec..547e3b5 100644 --- a/python/05_array/myarray.py +++ b/python/05_array/myarray.py @@ -59,6 +59,33 @@ class MyArray: self._count += 1 return True + def insert_v2(self, index: int, value: int) -> bool: + """ + 支持任意位置插入 + :param index: + :param value: + :return: + """ + # 数组空间已满 + if self._capacity == self._count: + return False + + # 插入位置大于当前的元素个数,可以插入最后的位置 + if index >= self._count: + self._data.append(value) + else: + if index < 0: + # 位置小于 0 可以插入第 0 个位置 + self._data.insert(0, value) + else: + # 挪动 index 至 _count 位到 index+1 至 _count+1 位 + # 插入第 index + self._data[index+1:self._count+1] = self._data[index:self._count] + self._data[index] = value + + self._count += 1 + return True + def insert_to_tail(self, value: int) -> bool: if self._count == self._capacity: From 05fb59166b4c1d26845f7b996b101d8c70a9cd70 Mon Sep 17 00:00:00 2001 From: lijialin Date: Fri, 30 Nov 2018 14:46:54 +0800 Subject: [PATCH 130/141] =?UTF-8?q?=E6=95=B0=E7=BB=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BB=BB=E6=84=8F=E4=BD=8D=E7=BD=AE=E6=8F=92=E5=85=A5=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/05_array/myarray.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/python/05_array/myarray.py b/python/05_array/myarray.py index 547e3b5..f85a33b 100644 --- a/python/05_array/myarray.py +++ b/python/05_array/myarray.py @@ -73,15 +73,14 @@ class MyArray: # 插入位置大于当前的元素个数,可以插入最后的位置 if index >= self._count: self._data.append(value) + elif index < 0: + # 位置小于 0 可以插入第 0 个位置 + self._data.insert(0, value) else: - if index < 0: - # 位置小于 0 可以插入第 0 个位置 - self._data.insert(0, value) - else: - # 挪动 index 至 _count 位到 index+1 至 _count+1 位 - # 插入第 index - self._data[index+1:self._count+1] = self._data[index:self._count] - self._data[index] = value + # 挪动 index 至 _count 位到 index+1 至 _count+1 位 + # 插入第 index + self._data[index+1:self._count+1] = self._data[index:self._count] + self._data[index] = value self._count += 1 return True From 2d1d248343d609bcf121391f589e54716e93b054 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 30 Nov 2018 23:09:12 +0800 Subject: [PATCH 131/141] [notes][18_hashtable] hash think. --- notes/18_hashtable/.gitkeep | 0 notes/18_hashtable/readme.md | 11 +++++++++++ 2 files changed, 11 insertions(+) create mode 100644 notes/18_hashtable/.gitkeep create mode 100644 notes/18_hashtable/readme.md diff --git a/notes/18_hashtable/.gitkeep b/notes/18_hashtable/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/notes/18_hashtable/readme.md b/notes/18_hashtable/readme.md new file mode 100644 index 0000000..2419e82 --- /dev/null +++ b/notes/18_hashtable/readme.md @@ -0,0 +1,11 @@ +# 散列表 + +散列表是数组的一种扩展,利用数组下标的随机访问特性。 + +## 散列思想 + +* 键/关键字/Key:用来标识一个数据 +* 散列函数/哈希函数/Hash:将 Key 映射到数组下标的函数 +* 散列值/哈希值:Key 经过散列函数得到的数值 + +![](https://static001.geekbang.org/resource/image/92/73/92c89a57e21f49d2f14f4424343a2773.jpg) From ec1cb44b33280f7b420001a2c3bf71151294ea3a Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Fri, 30 Nov 2018 23:15:50 +0800 Subject: [PATCH 132/141] [notes][18_hashtable] hash function. --- notes/18_hashtable/readme.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/notes/18_hashtable/readme.md b/notes/18_hashtable/readme.md index 2419e82..30b7c5b 100644 --- a/notes/18_hashtable/readme.md +++ b/notes/18_hashtable/readme.md @@ -9,3 +9,19 @@ * 散列值/哈希值:Key 经过散列函数得到的数值 ![](https://static001.geekbang.org/resource/image/92/73/92c89a57e21f49d2f14f4424343a2773.jpg) + +本质:利用散列函数将关键字映射到数组下标,而后利用数组随机访问时间复杂度为 $\Theta(1)$ 的特性快速访问。 + +## 散列函数 + +* 形式:`hash(key)` +* 基本要求 + 1. 散列值是非负整数 + 1. 如果 `key1 == key2`,那么 `hash(key1) == hash(key2)` + 1. 如果 `key1 != key2`,那么 `hash(key1) != hash(key2)` + +第 3 个要求,实际上不可能对任意的 `key1` 和 `key2` 都成立。因为通常散列函数的输出范围有限而输入范围无限。 + +## 散列冲突¡ + +* 散列冲突:`key1 != key2` 但 `hash(key1) == hash(key2)` From e9a6cc884b6d0d3a7bd601344ab2acaaf986cafd Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Sat, 1 Dec 2018 09:37:48 +0800 Subject: [PATCH 133/141] [notes][18_hashtable] open address. --- notes/18_hashtable/readme.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/notes/18_hashtable/readme.md b/notes/18_hashtable/readme.md index 30b7c5b..6a675a1 100644 --- a/notes/18_hashtable/readme.md +++ b/notes/18_hashtable/readme.md @@ -25,3 +25,33 @@ ## 散列冲突¡ * 散列冲突:`key1 != key2` 但 `hash(key1) == hash(key2)` + +散列冲突会导致不同键值映射到散列表的同一个位置。为此,我们需要解决散列冲突带来的问题。 + +### 开放寻址法 + +如果遇到冲突,那就继续寻找下一个空闲的槽位。 + +#### 线性探测 + +插入时,如果遇到冲突,那就依次往下寻找下一个空闲的槽位。(橙色表示已被占用的槽位,黄色表示空闲槽位) + +![](https://static001.geekbang.org/resource/image/5c/d5/5c31a3127cbc00f0c63409bbe1fbd0d5.jpg) + +查找时,如果目标槽位上不是目标数据,则依次往下寻找;直至遇见目标数据或空槽位。 + +![](https://static001.geekbang.org/resource/image/91/ff/9126b0d33476777e7371b96e676e90ff.jpg) + +删除时,标记为 `deleted`,而不是直接删除。 + +#### 平方探测(Quadratic probing) + +插入时,如果遇到冲突,那就往后寻找下一个空闲的槽位,其步长为 $1^2$, $2^2$, $3^2$, $\ldots$。 + +查找时,如果目标槽位上不是目标数据,则依次往下寻找,其步长为 $1^2$, $2^2$, $3^2$, $\ldots$;直至遇见目标数据或空槽位。 + +删除时,标记为 `deleted`,而不是直接删除。 + +#### 装载因子(load factor) + +$\text{load factor} = \frac{size()}{capacity()}$ From d8e52f17d88b0b1795bff112b546739043c12f4d Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Sat, 1 Dec 2018 09:41:43 +0800 Subject: [PATCH 134/141] [notes][18_hashtable] linked list. --- notes/18_hashtable/readme.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/notes/18_hashtable/readme.md b/notes/18_hashtable/readme.md index 6a675a1..f709209 100644 --- a/notes/18_hashtable/readme.md +++ b/notes/18_hashtable/readme.md @@ -55,3 +55,15 @@ #### 装载因子(load factor) $\text{load factor} = \frac{size()}{capacity()}$ + +### 链表法 + +所有散列值相同的 key 以链表的形式存储在同一个槽位中。 + +![](https://static001.geekbang.org/resource/image/a4/7f/a4b77d593e4cb76acb2b0689294ec17f.jpg) + +插入时,不论是否有冲突,直接插入目标位置的链表。 + +查找时,遍历目标位置的链表来查询。 + +删除时,遍历目标位置的链表来删除。 From 512c9b75c1f11fe1215d175ee0697ee99c958cf4 Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Sat, 1 Dec 2018 09:55:45 +0800 Subject: [PATCH 135/141] [notes][19_hashtable] conflict. --- notes/19_hashtable/.gitkeep | 0 notes/19_hashtable/readme.md | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 notes/19_hashtable/.gitkeep create mode 100644 notes/19_hashtable/readme.md diff --git a/notes/19_hashtable/.gitkeep b/notes/19_hashtable/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/notes/19_hashtable/readme.md b/notes/19_hashtable/readme.md new file mode 100644 index 0000000..9589b51 --- /dev/null +++ b/notes/19_hashtable/readme.md @@ -0,0 +1,53 @@ +# 散列表 + +核心:散列表的效率并不总是 $O(1)$,仅仅是在理论上能达到 $O(1)$。实际情况中,恶意攻击者可以通过精心构造数据,使得散列表的性能急剧下降。 + +如何设计一个工业级的散列表? + +## 散列函数 + +* 不能过于复杂——避免散列过程耗时 +* 散列函数的结果要尽可能均匀——最小化散列冲突 + +## 装载因子过大怎么办 + +动态扩容。涉及到 rehash,效率可能很低。 + +![](https://static001.geekbang.org/resource/image/67/43/67d12e07a7d673a9c1d14354ad029443.jpg) + +如何避免低效扩容? + +——将 rehash 的步骤,均摊到每一次插入中去: + +* 申请新的空间 +* 不立即使用 +* 每次来了新的数据,往新表插入数据 +* 同时,取出旧表的一个数据,插入新表 + +![](https://static001.geekbang.org/resource/image/6d/cb/6d6736f986ec4b75dabc5472965fb9cb.jpg) + +## 解决冲突 + +开放寻址法,优点: + +* 不需要额外空间 +* 有效利用 CPU 缓存 +* 方便序列化 + +开放寻址法,缺点: + +* 查找、删除数据时,涉及到 `delete` 标志,相对麻烦 +* 冲突的代价更高 +* 对装载因子敏感 + +链表法,优点: + +* 内存利用率较高——链表的优点 +* 对装载因子不敏感 + +链表法,缺点: + +* 需要额外的空间(保存指针) +* 对 CPU 缓存不友好 + +——将链表改造成更高效的数据结构,例如跳表、红黑树 From ed6d809936cc02774ac24e6adf7e6e7429418daa Mon Sep 17 00:00:00 2001 From: Liam Huang Date: Sat, 1 Dec 2018 09:58:39 +0800 Subject: [PATCH 136/141] [notes][19_hashtable] example. --- notes/19_hashtable/readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/notes/19_hashtable/readme.md b/notes/19_hashtable/readme.md index 9589b51..d530c05 100644 --- a/notes/19_hashtable/readme.md +++ b/notes/19_hashtable/readme.md @@ -51,3 +51,9 @@ * 对 CPU 缓存不友好 ——将链表改造成更高效的数据结构,例如跳表、红黑树 + +## 举个栗子(JAVA 中的 HashMap) + +* 初始大小:16 +* 装载因子:超过 0.75 时动态扩容 +* 散列冲突:优化版的链表法(当槽位冲突元素超过 8 时使用红黑树,否则使用链表) From 63c27a9ab3ceba9645632005d127cc2631185b18 Mon Sep 17 00:00:00 2001 From: lee <554050334@qq.com> Date: Sat, 1 Dec 2018 12:31:20 +0800 Subject: [PATCH 137/141] add heap insert and delete in golang --- go/28_heap/heap.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 go/28_heap/heap.go diff --git a/go/28_heap/heap.go b/go/28_heap/heap.go new file mode 100644 index 0000000..f978c13 --- /dev/null +++ b/go/28_heap/heap.go @@ -0,0 +1,79 @@ +package heap + +import "fmt" + +type Heap struct { + a []int + n int + count int +} + +//init heap +func NewHeap(capacity int) *Heap { + heap := &Heap{} + heap.n = capacity + heap.a = make([]int, capacity+1) + heap.count = 0 + return heap +} + +//top-max heap -> heapify from down to up +func (heap *Heap) insert(data int) { + //defensive + if heap.count == heap.n { + return + } + + heap.count++ + heap.a[heap.count] = data + + //compare with parent node + i := heap.count + parent := i / 2 + for parent > 0 && heap.a[parent] < heap.a[i] { + swap(heap.a, parent, i) + i = parent + parent = i / 2 + } +} + +//heapfify from up to down +func (heap *Heap) removeMax() { + + //defensive + if heap.count == 0 { + return + } + + //swap max and last + swap(heap.a, 1, heap.count) + heap.count-- + + //comapre with left and right + for i := 1; i <= heap.count/2; { + + maxIndex := i + if heap.a[i] < heap.a[i*2] { + maxIndex = i * 2 + } + + if i*2+1 <= heap.count && heap.a[maxIndex] < heap.a[i*2+1] { + maxIndex = i*2 + 1 + } + + if maxIndex == i { + break + } + + swap(heap.a, i, maxIndex) + i = maxIndex + } + +} + +//swap two elements +func swap(a []int, i int, j int) { + tmp := a[i] + a[i] = a[j] + a[j] = tmp +} From 086276d4d01967cd8d48cd56d236105760bd638f Mon Sep 17 00:00:00 2001 From: lee <554050334@qq.com> Date: Sat, 1 Dec 2018 13:43:00 +0800 Subject: [PATCH 138/141] add heap algo --- go/28_heap/heap.go | 18 ++++++++------ go/28_heap/heap_sort.go | 54 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 go/28_heap/heap_sort.go diff --git a/go/28_heap/heap.go b/go/28_heap/heap.go index f978c13..0d9327e 100644 --- a/go/28_heap/heap.go +++ b/go/28_heap/heap.go @@ -1,7 +1,5 @@ package heap -import "fmt" - type Heap struct { a []int n int @@ -49,15 +47,21 @@ func (heap *Heap) removeMax() { swap(heap.a, 1, heap.count) heap.count-- - //comapre with left and right - for i := 1; i <= heap.count/2; { + //heapify from up to down + heapifyUpToDown(heap.a, heap.count) +} + +//heapify +func heapifyUpToDown(a []int, count int) { + + for i := 1; i <= count/2; { maxIndex := i - if heap.a[i] < heap.a[i*2] { + if a[i] < a[i*2] { maxIndex = i * 2 } - if i*2+1 <= heap.count && heap.a[maxIndex] < heap.a[i*2+1] { + if i*2+1 <= count && a[maxIndex] < a[i*2+1] { maxIndex = i*2 + 1 } @@ -65,7 +69,7 @@ func (heap *Heap) removeMax() { break } - swap(heap.a, i, maxIndex) + swap(a, i, maxIndex) i = maxIndex } diff --git a/go/28_heap/heap_sort.go b/go/28_heap/heap_sort.go new file mode 100644 index 0000000..7617133 --- /dev/null +++ b/go/28_heap/heap_sort.go @@ -0,0 +1,54 @@ +package heap + +//build a heap +func buidHeap(a []int, n int) { + + //heapify from the last parent node + for i := n / 2; i >= 1; i-- { + heapifyUpToDown(a, i, n) + } + +} + +//sort by ascend, a index begin from 1, has n elements +func sort(a []int, n int) { + buidHeap(a, n) + + k := n + for k >= 1 { + swap(a, 1, k) + heapifyUpToDown(a, 1, k-1) + k-- + } +} + +//heapify from up to down , node index = top +func heapifyUpToDown(a []int, top int, count int) { + + for i := top; i <= count/2; { + + maxIndex := i + if a[i] < a[i*2] { + maxIndex = i * 2 + } + + if i*2+1 <= count && a[maxIndex] < a[i*2+1] { + maxIndex = i*2 + 1 + } + + if maxIndex == i { + break + } + + swap(a, i, maxIndex) + i = maxIndex + } + +} + +//swap two elements +func swap(a []int, i int, j int) { + tmp := a[i] + a[i] = a[j] + a[j] = tmp +} From 91fb78752208b66284413a15261751e330af7e36 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Sun, 2 Dec 2018 07:46:07 +0800 Subject: [PATCH 139/141] BST in c --- c-cpp/24_binarysearchtree/bst.c | 197 ++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 c-cpp/24_binarysearchtree/bst.c diff --git a/c-cpp/24_binarysearchtree/bst.c b/c-cpp/24_binarysearchtree/bst.c new file mode 100644 index 0000000..7fdfd87 --- /dev/null +++ b/c-cpp/24_binarysearchtree/bst.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +enum child_dir { + left_child, + right_child, + root, +}; + +struct node { + unsigned long data; + struct node *left; + struct node *right; +}; + +struct root { + struct node *r; +}; + +void dump(struct node *node, int level, enum child_dir dir) +{ + if (!node) + return; + + dump(node->right, level + 1, right_child); + + if (dir == left_child) + printf("%*s\n", level*3, "|"); + + printf("%*s - %05lu\n", level*3, " ", node->data); + + if (dir == right_child) + printf("%*s\n", level*3, "|"); + + dump(node->left, level + 1, left_child); +} + +struct node* find(struct root *root, unsigned long data) +{ + struct node* n = root->r; + + while (n) { + if (n->data == data) + return n; + if (data < n->data) + n = n->left; + else + n = n->right; + } + + return NULL; +} + +struct node* new_node(unsigned long data) +{ + struct node *n; + + n = malloc(sizeof(struct node)); + + n->data = data; + n->left = n->right = NULL; + return n; +} + +void insert(struct root *root, struct node *new) +{ + struct node *parent; + + if (!root->r) { + root->r = new; + return; + } + + parent = root->r; + + while (true) { + /* Don't support duplicate data */ + if (new->data == parent->data) + break; + + if (new->data < parent->data) { + if (!parent->left) { + parent->left = new; + break; + } + parent = parent->left; + } else { + if (!parent->right) { + parent->right = new; + break; + } + parent = parent->right; + } + } +} + +struct node* delete(struct root *root, unsigned long data) +{ + struct node *n = root->r, **p = &root->r; + struct node *child; + + while (n && n->data != data) { + if (data < n->data) { + p = &n->left; + n = n->left; + } else { + p = &n->right; + n = n->right; + } + } + + if (!n) + return NULL; + + if (n->left && n->right) { + struct node *rn = n->right, **rp = &n->right; + + while (rn->left) { + rp = &rn->left; + rn = rn->left; + } + + n->data = rn->data; + n = rn; + p = rp; + } + + child = n->left ? n->left : n->right; + *p = child; + + return NULL; +} + +void insert_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + n = find(&tree, 18); + if (n && n->data == 18) + printf("Get 18\n"); + +} + +void delete_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + delete(&tree, 20); + printf("Delete 20\n"); + dump(tree.r, 0, root); + + delete(&tree, 9); + printf("Delete 9\n"); + dump(tree.r, 0, root); +} + +int main() +{ + //insert_test(); + delete_test(); + return 0; +} From 2a095ae48f390fddad2506545c5b2893114f35c1 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Sun, 2 Dec 2018 09:56:35 +0800 Subject: [PATCH 140/141] implement heap in c --- c-cpp/28_heap/heap.c | 160 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 c-cpp/28_heap/heap.c diff --git a/c-cpp/28_heap/heap.c b/c-cpp/28_heap/heap.c new file mode 100644 index 0000000..6bd872d --- /dev/null +++ b/c-cpp/28_heap/heap.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include + +/* Implement heap */ + +#define MAX_HEAP_SIZE (1 << 8) + +struct element { + int data; +}; + +struct heap { + union { + unsigned long elements; + struct element *elem[MAX_HEAP_SIZE]; + }; +}; + +void init_heap(struct heap *heap) +{ + int i; + + for(i = 0; i < MAX_HEAP_SIZE; i++) { + heap->elem[i] = NULL; + } +} + +void dump_heap(struct heap *heap, int index) +{ + struct element *elem; + int level; + + if (index > heap->elements) + return; + + elem = heap->elem[index]; + level = fls(index); + + dump_heap(heap, index * 2 + 1); + + if (!(index % 2) && index != 1) + printf("%*s\n", level*3, "|"); + + printf("%*s - %05d\n", level*3, " ", elem->data); + + if (index % 2 && index != 1) + printf("%*s\n", level*3, "|"); + + dump_heap(heap, index * 2); +} + +void dump(struct heap *heap, int elements) +{ + int i; + + for (i = 1; i <= elements; i++) + printf("[%02d]: %4d\n", i, heap->elem[i]->data); + +} + +struct element* create_element(int data) +{ + struct element *elem; + + elem = malloc(sizeof(struct element)); + + if (elem) + elem->data = data; + + return elem; +} + +void fake_a_heap(struct heap *heap) +{ + /* data is in ordered */ + int i, data[10] = {7, 4, 9, 2, 6, 8, 10, 1, 3, 5}; + + init_heap(heap); + + /* root start at 1 */ + for (i = 0; i < 10; i++) + heap->elem[i+1] = create_element(data[i]); + + heap->elements = 10; +} + +void swap(struct heap *heap, int i, int j) +{ + struct element *tmp; + + tmp = heap->elem[j]; + heap->elem[j] = heap->elem[i]; + heap->elem[i] = tmp; +} + +void heapify(struct heap *heap, int parent) +{ + struct element **elem = heap->elem; + int elements = heap->elements; + int left, right, max; + + while (true) { + left = parent * 2; + right = left + 1; + + max = parent; + if (left <= elements && elem[max]->data < elem[left]->data) + max = left; + if (right <= elements && elem[max]->data < elem[right]->data) + max = right; + + if (max == parent) + break; + + swap(heap, max, parent); + parent = max; + } +} + +void build_heap(struct heap *heap) +{ + int i; + + for (i = heap->elements / 2; i >= 1; i--) + heapify(heap, i); +} + +int heap_sort(struct heap *heap) +{ + int elements = heap->elements; + + while (heap->elements) { + swap(heap, 1, heap->elements); + heap->elements--; + heapify(heap, 1); + } + + return elements; +} + +int main() +{ + struct heap heap; + int elements; + + fake_a_heap(&heap); + dump_heap(&heap, 1); + + printf("After Heapify:\n"); + build_heap(&heap); + dump_heap(&heap, 1); + + printf("After Heap sort:\n"); + elements = heap_sort(&heap); + dump(&heap, elements); + return 0; +} From 34805dabe44e8f8f903b62ed96797746bdec33e5 Mon Sep 17 00:00:00 2001 From: Wenru Dong Date: Sun, 2 Dec 2018 21:28:51 +0000 Subject: [PATCH 141/141] bfs and dfs of graphs in python --- python/31_bfs_dfs/bfs_dfs.py | 88 ++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 python/31_bfs_dfs/bfs_dfs.py diff --git a/python/31_bfs_dfs/bfs_dfs.py b/python/31_bfs_dfs/bfs_dfs.py new file mode 100644 index 0000000..59cebd8 --- /dev/null +++ b/python/31_bfs_dfs/bfs_dfs.py @@ -0,0 +1,88 @@ +""" + Breadth-first search and depth-first search. + + Author: Wenru Dong +""" + +from typing import List, Optional, Generator, IO +from collections import deque + +class Graph: + """Undirected graph.""" + def __init__(self, num_vertices: int): + self._num_vertices = num_vertices + self._adjacency = [[] for _ in range(num_vertices)] + + def add_edge(self, s: int, t: int) -> None: + self._adjacency[s].append(t) + self._adjacency[t].append(s) + + def _generate_path(self, s: int, t: int, prev: List[Optional[int]]) -> Generator[str, None, None]: + if prev[t] or s != t: + yield from self._generate_path(s, prev[t], prev) + yield str(t) + + def bfs(self, s: int, t: int) -> IO[str]: + """Print out the path from Vertex s to Vertex t + using bfs. + """ + if s == t: return + + visited = [False] * self._num_vertices + visited[s] = True + q = deque() + q.append(s) + prev = [None] * self._num_vertices + + while q: + v = q.popleft() + for neighbour in self._adjacency[v]: + if not visited[neighbour]: + prev[neighbour] = v + if neighbour == t: + print("->".join(self._generate_path(s, t, prev))) + return + visited[neighbour] = True + q.append(neighbour) + + def dfs(self, s: int, t: int) -> IO[str]: + """Print out a path from Vertex s to Vertex t + using dfs. + """ + found = False + visited = [False] * self._num_vertices + prev = [None] * self._num_vertices + + def _dfs(from_vertex: int) -> None: + nonlocal found + if found: return + visited[from_vertex] = True + if from_vertex == t: + found = True + return + for neighbour in self._adjacency[from_vertex]: + if not visited[neighbour]: + prev[neighbour] = from_vertex + _dfs(neighbour) + + _dfs(s) + print("->".join(self._generate_path(s, t, prev))) + + +if __name__ == "__main__": + + graph = Graph(8) + + graph.add_edge(0, 1) + graph.add_edge(0, 3) + graph.add_edge(1, 2) + graph.add_edge(1, 4) + graph.add_edge(2, 5) + graph.add_edge(3, 4) + graph.add_edge(4, 5) + graph.add_edge(4, 6) + graph.add_edge(5, 7) + graph.add_edge(6, 7) + + graph.bfs(0, 7) + graph.dfs(0, 7)