diff --git a/.gitignore b/.gitignore index 31f5f1e..c456446 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ hs_err_pid* # editor files .vscode +.*.swp diff --git a/README.md b/README.md index a915e84..0178939 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # 数据结构和算法之美 -# 请点击查看:[https://time.geekbang.org/column/intro/126](https://time.geekbang.org/column/intro/126) +# [https://time.geekbang.org/column/intro/126](https://time.geekbang.org/column/intro/126) + +# Java rate limiting library/framework +# https://github.com/wangzheng0822/ratelimiter4j diff --git a/c-cpp/05_array/Array_gp.c b/c-cpp/05_array/Array_gp.c new file mode 100644 index 0000000..0147a12 --- /dev/null +++ b/c-cpp/05_array/Array_gp.c @@ -0,0 +1,278 @@ +#include "Array.h" + +#include +#include + +Array* arrayCreate() +{ + struct Array *array = NULL; + array = malloc(sizeof(*array)); + if (NULL == array) + { + return NULL; + } + + array->p = NULL; + + array->size = 0; + array->typeSize = 0; + array->len = 0; + + array->dup = NULL; + array->free = NULL; + array->match = NULL; + + return array; +} + +void arrayInit(Array *array, int size, int typeSize) +{ + if (NULL == array + || typeSize <= 0 + || size < 0) + { + return; + } + + void *p = calloc(1, size* typeSize); + if (NULL == p) + { + return; + } + + array->p = p; + array->len = 0; + array->size = size; + array->typeSize = typeSize; +} + +int arrayInsert(Array *array, size_t pos, void *const value) +{ + if (NULL == array) + { + return -1; + } + + if (array->len >= array->size) + { + return -2; + } + + if (pos > array->size || pos <= 0) + { + return -3; + } + + char *pBegin = array->p; + for (size_t i = array->len; i > pos - 1; --i) + { + void *pNew = pBegin + i * array->typeSize; + void *pOld = pBegin + (i - 1) *array->typeSize; + if (NULL != array->dup) + { + array->dup(pNew, pOld); + } + else + { + memcpy(pNew, pOld, array->typeSize); + } + } + + void *pCopy = (void*)(pBegin + ((pos - 1) * array->typeSize)); + if (NULL != array->dup) + { + array->dup(pCopy, value); + } + else + { + memcpy(pCopy, value, array->typeSize); + } + ++array->len; + return 0; +} + +size_t arraySearchValue(Array *array, void* const value) +{ + if (NULL == array) + { + return -1; + } + + char *pBegin = array->p; + size_t i = 0; + for (; i < array->len; ++i) + { + int nCmp = 0; + if (NULL != array->match) + { + nCmp = array->match(pBegin + i * array->typeSize, value); + } + else + { + nCmp = memcmp(pBegin + i * array->typeSize, value, array->typeSize); + } + + if (nCmp == 0) + { + break; + } + } + + return i; +} + +void* arrayIndex(Array *array, size_t index) +{ + if (NULL == array) + { + return NULL; + } + + if (index > array->len + || index <= 0) + { + return NULL; + } + + char *pBegin = array->p; + return pBegin + array->typeSize * (index - 1); +} + +int arrayModify(Array *array, size_t pos, void *const value) +{ + if (NULL == array) + { + return -1; + } + if (pos > array->len + || pos <= 0) + { + return -2; + } + + char *pBegin = array->p; + void *pOld = pBegin + (pos - 1) * array->typeSize; + if (NULL != array->dup) + { + array->dup(pOld, value); + } + else + { + memcpy(pOld, value, array->typeSize); + } + + return 0; +} + +size_t arrayLen(Array *array) +{ + if (NULL == array) + { + return 0; + } + + return array->len; +} + +size_t arraySize(Array *array) +{ + if (NULL == array) + { + return 0; + } + + return array->size; +} + +void arrayEmpty(Array *array) +{ + if (NULL == array) + { + return; + } + + free(array->p); + array->p = NULL; + free(array); + array = NULL; +} + +void arrayDelValue(Array *array, void *value) +{ + if (NULL == array) + { + return; + } + + char* pBegin = array->p; + bool bCopy = false; + for (size_t i = 0; i < array->len; ++i) + { + if (!bCopy) + { + int nCmp = 0; + if (NULL != array->match) + { + nCmp = array->match(pBegin + i * array->typeSize, value); + } + else + { + nCmp = memcmp(pBegin + i * array->typeSize, value, array->typeSize); + } + + if (0 == nCmp) + { + bCopy = true; + continue; + } + } + else + { + void *pOld = pBegin + (i + 1) * array->typeSize; + void *pNew = pBegin + i * array->typeSize; + if (NULL != array->dup) + { + array->dup(pNew, pOld); + } + else + { + memcpy(pNew, pOld, array->typeSize); + } + } + } + + if (bCopy) + { + --array->len; + } +} + +void arrayDelIndex(Array *array, size_t pos) +{ + if (NULL == array) + { + return; + } + + if (pos > array->len || pos <= 0) + { + return; + } + + char* pBegin = array->p; + for (size_t i = pos - 1; i < array->len - 1; ++i) + { + void *pOld = pBegin + (i + 1) * array->typeSize; + void *pNew = pBegin + i * array->typeSize; + if (NULL != array->dup) + { + array->dup(pNew, pOld); + } + else + { + memcpy(pNew, pOld, array->typeSize); + } + } + + --array->len; +} \ No newline at end of file diff --git a/c-cpp/05_array/Array_gp.h b/c-cpp/05_array/Array_gp.h new file mode 100644 index 0000000..662ef8a --- /dev/null +++ b/c-cpp/05_array/Array_gp.h @@ -0,0 +1,48 @@ +#ifndef __ARRAY_H__ +#define __ARRAY_H__ + +#include +#include + +typedef struct Array +{ + // pָĿռС + size_t size; + // pָѾʹõĿռС + size_t len; + // ͵ĴС + size_t typeSize; + // ֵƺ + void(*dup)(void *ptr, void *key); + // ֵͷź + void(*free)(void *ptr); + // ֵȽϺ + int(*match)(void *ptr, void *key); + // ݵָ + void *p; +}Array; + +#define arraySetDupMethod(a, m) ((a)->dup = (m)) +#define arraySetFreeMethod(a, m) ((a)->free = (m)) +#define arraySetMatchMethod(a, m) ((a)->match = (m)) + +#define arrayGetDupMethod(a) ((a)->dup) +#define arrayGetFree(a) ((a)->free) +#define arrayGetMatchMethod(a) ((a)->match) + +Array* arrayCreate(); +void arrayInit(Array *array, int size, int typeSize); + +int arrayInsert(Array *array, size_t pos, void *const value); +size_t arraySearchValue(Array *array, void* const value); +void* arrayIndex(Array *array, size_t index); +int arrayModify(Array *array, size_t pos, void *const value); + +size_t arrayLen(Array *array); +size_t arraySize(Array *array); + +void arrayEmpty(Array *array); +void arrayDelValue(Array *array, void *value); +void arrayDelIndex(Array *array, size_t pos); + +#endif // !__ARRAY_H__ \ No newline at end of file diff --git a/c-cpp/06_linkedlist/Dlist/Dlist.c b/c-cpp/06_linkedlist/Dlist/Dlist.c new file mode 100644 index 0000000..d41cb45 --- /dev/null +++ b/c-cpp/06_linkedlist/Dlist/Dlist.c @@ -0,0 +1,220 @@ +/************************************************************************* + > File Name: Dlist.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-07 + > Desc: + ************************************************************************/ +#include +#include +#include "./Dlist.h" + + + +void dlist_init(stDlistHead *dlist) +{ + dlist->size = 0; + dlist->head = NULL; + dlist->tail = NULL; + return; +} + +void dlist_destory(stDlistHead *dlist) +{ + stDlistNode *pNode = NULL; + + while(dlist->size > 0) + { + pNode = dlist->head; + dlist->head = dlist->head->next; + free(pNode); + dlist->size--; + } + + memset(dlist,0,sizeof(stDlistHead)); + + return; +} + +int dlist_insert_head(stDlistHead *dlist,stDlistNode *pNode,int data) +{ + if(pNode == NULL) + { + pNode = (stDlistNode *)malloc(sizeof(stDlistNode)); + if (pNode == NULL) + { + return -1; + } + } + + pNode->data = data; + pNode->prev = NULL; + pNode->next = NULL; + + if (dlist->size == 0) + { + dlist->head = pNode; + dlist->tail = pNode; + } + else + { + pNode->next = dlist->head; + dlist->head->prev = pNode; + dlist->head = pNode; + } + + dlist->size++; + return 0; +} + +stDlistNode * dlist_remove_tail(stDlistHead *dlist) +{ + stDlistNode *pNode = NULL; + + if(dlist->size == 0) + { + return NULL; + } + + pNode = dlist->tail; + if(dlist->size > 1) + { + dlist->tail = dlist->tail->prev; + dlist->tail->next = NULL; + } + else + { + dlist->head = NULL; + dlist->tail = NULL; + } + dlist->size--; + return pNode; +} + +void dlist_remove_node(stDlistHead * dlist,stDlistNode *pNode) +{ + if ((dlist == NULL)||(pNode == NULL)) + { + return; + } + + if (dlist->head == pNode) + { + dlist->head = dlist->head->next; + } + else if (dlist->tail == pNode) + { + dlist->tail = pNode->prev; + + dlist->tail->next = NULL; + } + else + { + pNode->prev->next = pNode->next; + pNode->next->prev = pNode->prev; + } + dlist->size--; + pNode->prev = NULL; + pNode->next = NULL; + + if (dlist->size == 0) + { + memset(dlist,0,sizeof(stDlistHead)); + } + + return; +} +stDlistNode * dlist_search(stDlistHead * dlist,int data) +{ + stDlistNode *pNode = dlist->head; + while(pNode != NULL) + { + if (pNode->data == data) + { + return pNode; + } + pNode = pNode->next; + + } + return NULL; +} + +void dlist_dump(stDlistHead *dlist) +{ + int no = 0; + stDlistNode *pNode = dlist->head; + while(pNode != NULL) + { + printf("\r\n [%d] = %d",no++,pNode->data); + pNode = pNode->next; + } + + return; +} + + +void Lru_dlist(stDlistHead *dlist,int data) +{ + stDlistNode *pNode = NULL; + + pNode = dlist_search(dlist,data); + if (pNode != NULL) + { + dlist_remove_node(dlist,pNode); + } + else if(dlist->size >= 4) + { + pNode = dlist_remove_tail(dlist); + + } + + dlist_insert_head(dlist ,pNode,data); + + return; +} + +int main() +{ + stDlistHead dlist = {0}; + stDlistNode * pNode = NULL; + + dlist_init(&dlist); + + printf("\r\n inset 1,2,3"); + dlist_insert_head(&dlist,NULL,1); + dlist_insert_head(&dlist,NULL,2); + dlist_insert_head(&dlist,NULL,3); + + dlist_dump(&dlist); + + pNode = dlist_remove_tail(&dlist); + if(pNode != NULL) + { + printf("\r\n remove %d",pNode->data); + } + dlist_insert_head(&dlist,pNode,4); + dlist_dump(&dlist); + + Lru_dlist(&dlist,5); + dlist_dump(&dlist); + Lru_dlist(&dlist,6); + dlist_dump(&dlist); + Lru_dlist(&dlist,7); + dlist_dump(&dlist); + Lru_dlist(&dlist,5); + dlist_dump(&dlist); + + + + while(dlist.size > 0) + { + pNode = dlist_remove_tail(&dlist); + if(pNode != NULL) + { + printf("\r\n remove %d",pNode->data); + free (pNode); + } + } + + return 0; +} diff --git a/c-cpp/06_linkedlist/Dlist/Dlist.h b/c-cpp/06_linkedlist/Dlist/Dlist.h new file mode 100644 index 0000000..1721692 --- /dev/null +++ b/c-cpp/06_linkedlist/Dlist/Dlist.h @@ -0,0 +1,23 @@ +/************************************************************************* + > File Name: Dlist.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-07 + > Desc: + ************************************************************************/ +#include + +typedef struct DlistNode +{ + struct DlistNode *prev; + struct DlistNode *next; + int data; +}stDlistNode; + +typedef struct Dlisthead +{ + int size; + stDlistNode *head; + stDlistNode *tail; +}stDlistHead; + diff --git a/c-cpp/09_queue/.gitkeep b/c-cpp/09_queue/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/c-cpp/09_queue/array_queue.hpp b/c-cpp/09_queue/array_queue.hpp new file mode 100644 index 0000000..6bf0892 --- /dev/null +++ b/c-cpp/09_queue/array_queue.hpp @@ -0,0 +1,97 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/10. + */ + +#ifndef QUEUE_ARRAY_QUEUE_HPP_ +#define QUEUE_ARRAY_QUEUE_HPP_ + +template +class ArrayQueue { + private: + T* items_ = nullptr; + size_t capacity_ = 0; + size_t head_ = 0; + size_t tail_ = 0; + + public: + ArrayQueue() = delete; + ArrayQueue(const size_t capacity) : capacity_(capacity) { + items_ = new T[capacity_]; + } + ~ArrayQueue() { + if (nullptr != items_) { + delete[] items_; + items_ = nullptr; + } + } + ArrayQueue(const ArrayQueue& other) : capacity_(other.capacity_) { + items_ = new T[capacity_]; + for (size_t i = other.head_; i != other.tail_; ++i) { + enqueue(other.items_[i]); + } + } + ArrayQueue& operator=(const ArrayQueue& rhs) { + delete[] items_; + head_ = 0; + tail_ = 0; + capacity_ = rhs.capacity_; + items_ = new T[capacity_]; + for (size_t i = rhs.head_; i != rhs.tail_; ++i) { + enqueue(rhs.items_[i]); + } + return *this; + } + ArrayQueue(ArrayQueue&& other) : items_(other.items_), + capacity_(other.capacity_), + head_(other.head_), + tail_(other.tail_) { + other.items_ = nullptr; + other.capacity_ = 0; + other.head_ = 0; + other.tail_ = 0; + } + ArrayQueue& operator=(ArrayQueue&& rhs) { + delete[] items_; + items_ = rhs.items_; + capacity_ = rhs.capacity_; + head_ = rhs.head_; + tail_ = rhs.tail_; + rhs.items_ = nullptr; + rhs.capacity_ = 0; + rhs.head_ = 0; + rhs.tail_ = 0; + return *this; + } + + public: + void enqueue(T item) { + if (capacity_ == tail_) { + throw "Push data into a full queue!"; + } + items_[tail_++] = item; + } + T head() const { + if (head_ != tail_) { + return items_[head_]; + } else { + throw "Fetch data from an empty queue!"; + } + } + void dequeue() { + if (head_ != tail_) { + ++head_; + } else { + throw "Pop data from an empty queue!"; + } + } + + public: + template + void traverse(UnaryFunc do_traverse) { + for (size_t i = head_; i != tail_; ++i) { + do_traverse(items_[i]); + } + } +}; + +#endif // QUEUE_ARRAY_QUEUE_HPP_ diff --git a/c-cpp/09_queue/array_queue_test.cc b/c-cpp/09_queue/array_queue_test.cc new file mode 100644 index 0000000..c2c3b3b --- /dev/null +++ b/c-cpp/09_queue/array_queue_test.cc @@ -0,0 +1,56 @@ +#include +#include "array_queue.hpp" + +int main() { + auto do_traverse = [&](auto item){ std::cout << item << ' '; }; + + ArrayQueue array_queue_1(3); + array_queue_1.enqueue(1); + array_queue_1.enqueue(2); + array_queue_1.enqueue(3); + // array_queue_1.enqueue(4); // throw + array_queue_1.traverse(do_traverse); + std::cout << std::endl; + + ArrayQueue array_queue_2(array_queue_1); // copy constructor + array_queue_2.traverse(do_traverse); + std::cout << std::endl; + + ArrayQueue array_queue_3(std::move(array_queue_2)); // move constructor + array_queue_3.traverse(do_traverse); + std::cout << std::endl; + array_queue_2.traverse(do_traverse); + std::cout << std::endl; + + std::cout << array_queue_3.head() << std::endl; + array_queue_3.dequeue(); + std::cout << array_queue_3.head() << std::endl; + array_queue_3.dequeue(); + std::cout << array_queue_3.head() << std::endl; + array_queue_3.dequeue(); + // std::cout << array_queue_3.head() << std::endl; // throw + // array_queue_3.dequeue(); // throw + + ArrayQueue array_queue_4(1); + array_queue_4 = array_queue_1; // copy assignment + array_queue_4.traverse(do_traverse); + std::cout << std::endl; + + ArrayQueue array_queue_5(100); + array_queue_5 = std::move(array_queue_4); // move assignment + array_queue_5.traverse(do_traverse); + std::cout << std::endl; + array_queue_4.traverse(do_traverse); + std::cout << std::endl; + + std::cout << array_queue_5.head() << std::endl; + array_queue_5.dequeue(); + std::cout << array_queue_5.head() << std::endl; + array_queue_5.dequeue(); + std::cout << array_queue_5.head() << std::endl; + array_queue_5.dequeue(); + // std::cout << array_queue_5.head() << std::endl; // throw + // array_queue_5.dequeue(); // throw + + return 0; +} diff --git a/c-cpp/09_queue/block_queue.hpp b/c-cpp/09_queue/block_queue.hpp new file mode 100644 index 0000000..d8de168 --- /dev/null +++ b/c-cpp/09_queue/block_queue.hpp @@ -0,0 +1,82 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/11. + */ + +#ifndef QUEUE_BLOCK_QUEUE_HPP_ +#define QUEUE_BLOCK_QUEUE_HPP_ + +#include +#include +#include + +template +class BlockQueue { + public: + using value_type = T; + using container_type = std::queue; + using size_type = typename container_type::size_type; + + private: + size_type capacity_ = 0; + container_type container_; + mutable std::mutex mutex_; + mutable std::condition_variable not_empty_; + mutable std::condition_variable not_full_; + + public: + BlockQueue() = delete; + BlockQueue(const size_type capacity) : capacity_(capacity) {} + BlockQueue(const BlockQueue&) = default; + BlockQueue(BlockQueue&&) = default; + BlockQueue& operator=(const BlockQueue&) = default; + BlockQueue& operator=(BlockQueue&&) = default; + + private: + bool empty() const { return container_.empty(); } + bool full() const { return not(container_.size() < capacity_); } + + public: + void put(const value_type& item) { + std::unqiue_lock lock(mutex_); + while (full()) { + not_full_.wait(lock); + } + container_.push(item); + not_empty_.notify_one(); + } + void take(value_type& out) { + std::unique_lock lock(mutex_); + while (empty()) { + not_empty_.wait(lock); + } + out = container_.front(); + container_.pop(); + not_full_.notify_one(); + } + template + bool put_for(const value_type& item, const Duration& d) { + std::unqiue_lock lock(mutex_); + if (not_full_.wait_for(lock, d, [&](){ return not full(); })) { + container_.push(item); + not_empty_.notify_one(); + return true; + } else { + return false; + } + } + template + bool take_for(const Duration& d, value_type& out) { + std::unique_lock lock(mutex_); + if (not_empty_.wait_for(lock, d, [&](){ return not empty(); })) { + out = container_.front(); + container_.pop(); + not_full_.notify_one(); + return true; + } else { + return false; + } + } +}; + +#endif // QUEUE_BLOCK_QUEUE_HPP_ + diff --git a/c-cpp/09_queue/circular_queue.hpp b/c-cpp/09_queue/circular_queue.hpp new file mode 100644 index 0000000..df4664c --- /dev/null +++ b/c-cpp/09_queue/circular_queue.hpp @@ -0,0 +1,99 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/10. + */ + +#ifndef QUEUE_CIRCULAR_QUEUE_HPP_ +#define QUEUE_CIRCULAR_QUEUE_HPP_ + +template +class CircularQueue { + private: + T* items_ = nullptr; + size_t capacity_ = 0; + size_t head_ = 0; + size_t tail_ = 0; + + public: + CircularQueue() = delete; + CircularQueue(const size_t capacity) : capacity_(capacity) { + items_ = new T[capacity_]; + } + ~CircularQueue() { + if (nullptr != items_) { + delete[] items_; + items_ = nullptr; + } + } + CircularQueue(const CircularQueue& other) : capacity_(other.capacity_) { + items_ = new T[capacity_]; + for (size_t i = other.head_; i != other.tail_; ++i) { + enqueue(other.items_[i]); + } + } + CircularQueue& operator=(const CircularQueue& rhs) { + delete[] items_; + head_ = 0; + tail_ = 0; + capacity_ = rhs.capacity_; + items_ = new T[capacity_]; + for (size_t i = rhs.head_; i != rhs.tail_; ++i) { + enqueue(rhs.items_[i]); + } + return *this; + } + CircularQueue(CircularQueue&& other) : items_(other.items_), + capacity_(other.capacity_), + head_(other.head_), + tail_(other.tail_) { + other.items_ = nullptr; + other.capacity_ = 0; + other.head_ = 0; + other.tail_ = 0; + } + CircularQueue& operator=(CircularQueue&& rhs) { + delete[] items_; + items_ = rhs.items_; + capacity_ = rhs.capacity_; + head_ = rhs.head_; + tail_ = rhs.tail_; + rhs.items_ = nullptr; + rhs.capacity_ = 0; + rhs.head_ = 0; + rhs.tail_ = 0; + return *this; + } + + public: + void enqueue(T item) { + if ((tail_ + 1) % capacity_ == head_) { + throw "Push data into a full queue!"; + } + items_[tail_] = item; + tail_ = (tail_ + 1) % capacity_; + } + T head() const { + if (head_ != tail_) { + return items_[head_]; + } else { + throw "Fetch data from an empty queue!"; + } + } + void dequeue() { + if (head_ != tail_) { + head_ = (head_ + 1) % capacity_; + } else { + throw "Pop data from an empty queue!"; + } + } + + public: + template + void traverse(UnaryFunc do_traverse) { + if (0 == capacity_) return; + for (size_t i = head_; i % capacity_ != tail_; ++i) { + do_traverse(items_[i % capacity_]); + } + } +}; + +#endif // QUEUE_CIRCULAR_QUEUE_HPP_ diff --git a/c-cpp/09_queue/circular_queue_test.cc b/c-cpp/09_queue/circular_queue_test.cc new file mode 100644 index 0000000..46e025a --- /dev/null +++ b/c-cpp/09_queue/circular_queue_test.cc @@ -0,0 +1,62 @@ +#include +#include "circular_queue.hpp" + +int main() { + auto do_traverse = [&](auto item){ std::cout << item << ' '; }; + + CircularQueue circular_queue_1(4); + circular_queue_1.enqueue(1); + circular_queue_1.enqueue(2); + circular_queue_1.enqueue(3); + // circular_queue_1.enqueue(4); // throw + circular_queue_1.traverse(do_traverse); + std::cout << std::endl; + + CircularQueue circular_queue_2(circular_queue_1); // copy constructor + circular_queue_2.traverse(do_traverse); + std::cout << std::endl; + + CircularQueue circular_queue_3(std::move(circular_queue_2)); // move constructor + circular_queue_3.traverse(do_traverse); + std::cout << std::endl; + circular_queue_2.traverse(do_traverse); + std::cout << std::endl; + + std::cout << circular_queue_3.head() << std::endl; + circular_queue_3.dequeue(); + std::cout << circular_queue_3.head() << std::endl; + circular_queue_3.dequeue(); + std::cout << circular_queue_3.head() << std::endl; + circular_queue_3.dequeue(); + // std::cout << circular_queue_3.head() << std::endl; // throw + // circular_queue_3.dequeue(); // throw + + CircularQueue circular_queue_4(1); + circular_queue_4 = circular_queue_1; // copy assignment + circular_queue_4.traverse(do_traverse); + std::cout << std::endl; + + CircularQueue circular_queue_5(100); + circular_queue_5 = std::move(circular_queue_4); // move assignment + circular_queue_5.traverse(do_traverse); + std::cout << std::endl; + circular_queue_4.traverse(do_traverse); + std::cout << std::endl; + + std::cout << circular_queue_5.head() << std::endl; + circular_queue_5.dequeue(); + std::cout << circular_queue_5.head() << std::endl; + circular_queue_5.dequeue(); + std::cout << circular_queue_5.head() << std::endl; + circular_queue_5.dequeue(); + // std::cout << circular_queue_5.head() << std::endl; // throw + // circular_queue_5.dequeue(); // throw + + for (size_t i = 0; i != 4; ++i) { + circular_queue_1.dequeue(); + circular_queue_1.enqueue(i + 4); + circular_queue_1.traverse(do_traverse); + std::cout << std::endl; + } + return 0; +} diff --git a/c-cpp/09_queue/concurrency_queue.hpp b/c-cpp/09_queue/concurrency_queue.hpp new file mode 100644 index 0000000..8e9bb78 --- /dev/null +++ b/c-cpp/09_queue/concurrency_queue.hpp @@ -0,0 +1,85 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/11. + */ + +#ifndef QUEUE_CONCURRENCY_QUEUE_HPP_ +#define QUEUE_CONCURRENCY_QUEUE_HPP_ + +#include +#include +#include +#include + +template +class ConcurrencyQueue { + public: + using value_type = T; + using container_type = std::queue; + using size_type = typename container_type::size_type; + + private: + container_type container_; + mutable std::mutex mutex_; + std::condition_variable container_cond_; + + public: + ConcurrencyQueue() = default; + ConcurrencyQueue(const ConcurrencyQueue&) = default; + ConcurrencyQueue(ConcurrencyQueue&&) = default; + ConcurrencyQueue& operator=(const ConcurrencyQueue&) = default; + ConcurrencyQueue& operator=(ConcurrencyQueue&&) = default; + + private: + bool empty_() const { return container_.empty(); } + + public: + bool empty() const { + std::lock_guard lg(mutex_); + return container_.empty(); + } + void push(value_type item) { + std::lock_guard lg(mutex_); + container_.push(std::move(item)); + container_cond_.notify_one(); + } + void wait_and_pop(value_type& out) { + std::unique_lock lk(mutex_); + while (empty_()) { + container_cond_.wait(lk) + } + out = std::move(container_.front()); + container_.pop(); + } + std::shared_ptr wait_and_pop() { + std::unique_lock lk(mutex_); + while (empty_()) { + container_cond_.wait(lk) + } + auto res = std::make_shared(std::move(container_.front())); + container_.pop(); + return res; + } + bool try_pop(value_type& out) { + std::lock_guard lg(mutex_); + if (empty_()) { + return false; + } else { + out = std::move(container_.front()); + container_.pop(); + return true; + } + } + std::shared_ptr try_pop() { + std::lock_guard lg(mutex_); + if (empty_()) { + return nullptr; + } else { + auto res = std::make_shared(std::move(container_.front())); + container_.pop(); + return res; + } + } +}; + +#endif // QUEUE_CONCURRENCY_QUEUE_HPP_ + diff --git a/c-cpp/09_queue/dynamic_array_queue.hpp b/c-cpp/09_queue/dynamic_array_queue.hpp new file mode 100644 index 0000000..73939e4 --- /dev/null +++ b/c-cpp/09_queue/dynamic_array_queue.hpp @@ -0,0 +1,105 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/10. + */ + +#ifndef QUEUE_DYNAMIC_ARRAY_QUEUE_HPP_ +#define QUEUE_DYNAMIC_ARRAY_QUEUE_HPP_ + +template +class DynamicArrayQueue { + private: + T* items_ = nullptr; + size_t capacity_ = 0; + size_t head_ = 0; + size_t tail_ = 0; + + public: + DynamicArrayQueue() = delete; + DynamicArrayQueue(const size_t capacity) : capacity_(capacity) { + items_ = new T[capacity_]; + } + ~DynamicArrayQueue() { + if (nullptr != items_) { + delete[] items_; + items_ = nullptr; + } + } + DynamicArrayQueue(const DynamicArrayQueue& other) : capacity_(other.capacity_) { + items_ = new T[capacity_]; + for (size_t i = other.head_; i != other.tail_; ++i) { + enqueue(other.items_[i]); + } + } + DynamicArrayQueue& operator=(const DynamicArrayQueue& rhs) { + delete[] items_; + head_ = 0; + tail_ = 0; + capacity_ = rhs.capacity_; + items_ = new T[capacity_]; + for (size_t i = rhs.head_; i != rhs.tail_; ++i) { + enqueue(rhs.items_[i]); + } + return *this; + } + DynamicArrayQueue(DynamicArrayQueue&& other) : items_(other.items_), + capacity_(other.capacity_), + head_(other.head_), + tail_(other.tail_) { + other.items_ = nullptr; + other.capacity_ = 0; + other.head_ = 0; + other.tail_ = 0; + } + DynamicArrayQueue& operator=(DynamicArrayQueue&& rhs) { + delete[] items_; + items_ = rhs.items_; + capacity_ = rhs.capacity_; + head_ = rhs.head_; + tail_ = rhs.tail_; + rhs.items_ = nullptr; + rhs.capacity_ = 0; + rhs.head_ = 0; + rhs.tail_ = 0; + return *this; + } + + public: + void enqueue(T item) { + if (capacity_ == tail_ - head_) { + throw "Push data into a full queue!"; + } + if (capacity_ == tail_) { + // item transport + for (size_t i = head_; i != tail_; ++i) { + items_[i - head_] = items_[i]; + } + tail_ = tail_ - head_; + head_ = 0; + } + items_[tail_++] = item; + } + T head() const { + if (head_ != tail_) { + return items_[head_]; + } else { + throw "Fetch data from an empty queue!"; + } + } + void dequeue() { + if (head_ != tail_) { + ++head_; + } else { + throw "Pop data from an empty queue!"; + } + } + + public: + template + void traverse(UnaryFunc do_traverse) { + for (size_t i = head_; i != tail_; ++i) { + do_traverse(items_[i]); + } + } +}; + +#endif // QUEUE_DYNAMIC_ARRAY_QUEUE_HPP_ diff --git a/c-cpp/09_queue/dynamic_array_queue_test.cc b/c-cpp/09_queue/dynamic_array_queue_test.cc new file mode 100644 index 0000000..6580433 --- /dev/null +++ b/c-cpp/09_queue/dynamic_array_queue_test.cc @@ -0,0 +1,62 @@ +#include +#include "dynamic_array_queue.hpp" + +int main() { + auto do_traverse = [&](auto item){ std::cout << item << ' '; }; + + DynamicArrayQueue dynamic_array_queue_1(3); + dynamic_array_queue_1.enqueue(1); + dynamic_array_queue_1.enqueue(2); + dynamic_array_queue_1.enqueue(3); + // dynamic_array_queue_1.enqueue(4); // throw + dynamic_array_queue_1.traverse(do_traverse); + std::cout << std::endl; + + DynamicArrayQueue dynamic_array_queue_2(dynamic_array_queue_1); // copy constructor + dynamic_array_queue_2.traverse(do_traverse); + std::cout << std::endl; + + DynamicArrayQueue dynamic_array_queue_3(std::move(dynamic_array_queue_2)); // move constructor + dynamic_array_queue_3.traverse(do_traverse); + std::cout << std::endl; + dynamic_array_queue_2.traverse(do_traverse); + std::cout << std::endl; + + std::cout << dynamic_array_queue_3.head() << std::endl; + dynamic_array_queue_3.dequeue(); + std::cout << dynamic_array_queue_3.head() << std::endl; + dynamic_array_queue_3.dequeue(); + std::cout << dynamic_array_queue_3.head() << std::endl; + dynamic_array_queue_3.dequeue(); + // std::cout << dynamic_array_queue_3.head() << std::endl; // throw + // dynamic_array_queue_3.dequeue(); // throw + + DynamicArrayQueue dynamic_array_queue_4(1); + dynamic_array_queue_4 = dynamic_array_queue_1; // copy assignment + dynamic_array_queue_4.traverse(do_traverse); + std::cout << std::endl; + + DynamicArrayQueue dynamic_array_queue_5(100); + dynamic_array_queue_5 = std::move(dynamic_array_queue_4); // move assignment + dynamic_array_queue_5.traverse(do_traverse); + std::cout << std::endl; + dynamic_array_queue_4.traverse(do_traverse); + std::cout << std::endl; + + std::cout << dynamic_array_queue_5.head() << std::endl; + dynamic_array_queue_5.dequeue(); + std::cout << dynamic_array_queue_5.head() << std::endl; + dynamic_array_queue_5.dequeue(); + std::cout << dynamic_array_queue_5.head() << std::endl; + dynamic_array_queue_5.dequeue(); + // std::cout << dynamic_array_queue_5.head() << std::endl; // throw + // dynamic_array_queue_5.dequeue(); // throw + + for (size_t i = 0; i != 3; ++i) { + dynamic_array_queue_1.dequeue(); + dynamic_array_queue_1.enqueue(i + 4); + dynamic_array_queue_1.traverse(do_traverse); + std::cout << std::endl; + } + return 0; +} diff --git a/c-cpp/09_queue/linked_queue.hpp b/c-cpp/09_queue/linked_queue.hpp new file mode 100644 index 0000000..1372775 --- /dev/null +++ b/c-cpp/09_queue/linked_queue.hpp @@ -0,0 +1,75 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/10. + */ + +#ifndef QUEUE_LINKED_QUEUE_HPP_ +#define QUEUE_LINKED_QUEUE_HPP_ + +#include + +template +struct Node { + using ptr_t = std::shared_ptr>; + T data; + ptr_t next; + + Node(T data_) : data(data_), next(nullptr) {} + Node() : next(nullptr) {} +}; + +template +class LinkedQueue { + public: + using node_type = Node; + using node_ptr_t = typename node_type::ptr_t; + + private: + node_ptr_t head_ = nullptr; + node_ptr_t before_tail_ = nullptr; + + public: + LinkedQueue() = default; + ~LinkedQueue() = default; + LinkedQueue(const LinkedQueue& other) = default; + LinkedQueue& operator=(const LinkedQueue& rhs) = default; + LinkedQueue(LinkedQueue&& other) = default; + LinkedQueue& operator=(LinkedQueue&& rhs) = default; + + public: + void enqueue(T item) { + if (nullptr == head_) { + head_ = std::make_shared(item); + before_tail_ = head_; + } else { + before_tail_->next = std::make_shared(item); + before_tail_ = before_tail_->next; + } + } + T head() const { + if (nullptr != head_) { + return head_->data; + } else { + throw "Fetch data from an empty queue!"; + } + } + void dequeue() { + if (nullptr != head_) { + head_ = head_->next; + if (nullptr == head_) { + before_tail_ = nullptr; + } + } else { + throw "Pop data from an empty queue!"; + } + } + + public: + template + void traverse(UnaryFunc do_traverse) { + for (node_ptr_t work = head_; nullptr != work; work = work->next) { + do_traverse(work->data); + } + } +}; + +#endif // QUEUE_LINKED_QUEUE_HPP_ diff --git a/c-cpp/09_queue/linked_queue_test.cc b/c-cpp/09_queue/linked_queue_test.cc new file mode 100644 index 0000000..04a9019 --- /dev/null +++ b/c-cpp/09_queue/linked_queue_test.cc @@ -0,0 +1,55 @@ +#include +#include "linked_queue.hpp" + +int main() { + auto do_traverse = [&](auto item){ std::cout << item << ' '; }; + + LinkedQueue linked_queue_1; + linked_queue_1.enqueue(1); + linked_queue_1.enqueue(2); + linked_queue_1.enqueue(3); + linked_queue_1.traverse(do_traverse); + std::cout << std::endl; + + LinkedQueue linked_queue_2(linked_queue_1); // copy constructor + linked_queue_2.traverse(do_traverse); + std::cout << std::endl; + + LinkedQueue linked_queue_3(std::move(linked_queue_2)); // move constructor + linked_queue_3.traverse(do_traverse); + std::cout << std::endl; + linked_queue_2.traverse(do_traverse); + std::cout << std::endl; + + std::cout << linked_queue_3.head() << std::endl; + linked_queue_3.dequeue(); + std::cout << linked_queue_3.head() << std::endl; + linked_queue_3.dequeue(); + std::cout << linked_queue_3.head() << std::endl; + linked_queue_3.dequeue(); + // std::cout << linked_queue_3.head() << std::endl; // throw + // linked_queue_3.dequeue(); // throw + + LinkedQueue linked_queue_4; + linked_queue_4 = linked_queue_1; // copy assignment + linked_queue_4.traverse(do_traverse); + std::cout << std::endl; + + LinkedQueue linked_queue_5; + linked_queue_5 = std::move(linked_queue_4); // move assignment + linked_queue_5.traverse(do_traverse); + std::cout << std::endl; + linked_queue_4.traverse(do_traverse); + std::cout << std::endl; + + std::cout << linked_queue_5.head() << std::endl; + linked_queue_5.dequeue(); + std::cout << linked_queue_5.head() << std::endl; + linked_queue_5.dequeue(); + std::cout << linked_queue_5.head() << std::endl; + linked_queue_5.dequeue(); + // std::cout << linked_queue_5.head() << std::endl; // throw + // linked_queue_5.dequeue(); // throw + + return 0; +} diff --git a/c-cpp/09_queue/lock_free_queue.hpp b/c-cpp/09_queue/lock_free_queue.hpp new file mode 100644 index 0000000..3f02d8a --- /dev/null +++ b/c-cpp/09_queue/lock_free_queue.hpp @@ -0,0 +1,84 @@ +/** + * Created by Liam Huang (Liam0205) on 2018/10/11. + */ + +#ifndef QUEUE_LOCK_FREE_QUEUE_HPP_ +#define QUEUE_LOCK_FREE_QUEUE_HPP_ + +#include +#include + +template +class LockFreeQueue { + public: + using value_type = T; + + private: + struct node { + std::shared data = nullptr; + node* next = nullptr; + }; + std::atomic head = nullptr; + std::atomic tail = nullptr; + + public: + LockFreeQueue() head(new node), tail(head.load()) {} + LockFreeQueue(const LockFreeQueue&) = delete; + LockFreeQueue(LockFreeQueue&& other) : head(other.head.load()), tail(other.tail.load()) { + other.head.store(nullptr); + other.tail.store(nullptr); + } + LockFreeQueue& operator=(const LockFreeQueue&) = delete; + LockFreeQueue& operator=(LockFreeQueue&& rhs) { + while (node* const old_head = head.load()) { + head.store(old_head->next); + delete old_head; + } + head.store(rhs.head.load()); + tail.store(rhs.tail.load()); + rhs.head.store(nullptr); + rhs.tail.store(nullptr); + } + ~LockFreeQueue() { + while (node* const old_head = head.load()) { + head.store(old_head->next); + delete old_head; + } + } + + private: + node* pop_head() { + node* const res = head.load(); + if (res == tail.load()) { + return nullptr; + } + head.store(res->next); + return res; + } + + public: + bool empty() const { + return head.load() == tail.load(); + } + std::shared_ptr pop() { + node* old_head = pop_head(); + if (nullptr == old_head) { + return nullptr; + } else { + auto res = old_head->data; + delete old_head; + return res; + } + } + void push(value_type new_value) { + auto new_data = std::make_shared(new_value); + node* p = new node; + node* old_tail = tail.load(); + old_tail->data.swap(new_data); + old_tail->next = p; + tail_.store(p); + } +}; + +#endif // QUEUE_LOCK_FREE_QUEUE_HPP_ + diff --git a/c-cpp/10_recursive/.gitkeep b/c-cpp/10_recursive/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/c-cpp/10_recursive/one_two_step.cc b/c-cpp/10_recursive/one_two_step.cc new file mode 100644 index 0000000..11159c7 --- /dev/null +++ b/c-cpp/10_recursive/one_two_step.cc @@ -0,0 +1,71 @@ +#include +#include + +class SolutionOFOneTwoStep { + private: + static std::unordered_map result_; + + public: + enum class POLICY { + RECURSIVE, + NONRECURSIVE + }; + + private: + size_t recursive(size_t steps) { + auto iter = result_.find(steps); + if (result_.end() != iter) { // found. + return iter->second; + } else { + size_t res = operator()(steps - 1) + operator()(steps - 2); + result_.insert({steps, res}); + return res; + } + } + size_t nonrecursive(size_t steps) { + auto iter = result_.find(steps); + if (result_.end() != iter) { // found. + return iter->second; + } else { + size_t start; + for (start = steps; start != 2 and result_.end() == result_.find(start); --start) {} + for (size_t i = start; i != steps; ++i) { + result_.insert({i + 1, result_[i - 1] + result_[i]}); + } + return result_[steps]; + } + } + + public: + size_t operator()(size_t steps, const POLICY policy = POLICY::RECURSIVE) { + if (policy == POLICY::RECURSIVE) { + return recursive(steps); + } else if (policy == POLICY::NONRECURSIVE) { + return nonrecursive(steps); + } + } + static void debug() { + for (auto kv : result_) { + std::cout << kv.first << ' ' << kv.second << std::endl; + } + std::cout << std::endl; + } +}; + +std::unordered_map SolutionOFOneTwoStep::result_ = {{1, 1}, {2, 2}}; + +int main() { + SolutionOFOneTwoStep::debug(); + + std::cout << SolutionOFOneTwoStep()(5, SolutionOFOneTwoStep::POLICY::RECURSIVE) << std::endl; + SolutionOFOneTwoStep::debug(); + + std::cout << SolutionOFOneTwoStep()(10, SolutionOFOneTwoStep::POLICY::NONRECURSIVE) << std::endl; + SolutionOFOneTwoStep::debug(); + + std::cout << SolutionOFOneTwoStep()(20, SolutionOFOneTwoStep::POLICY::RECURSIVE) << std::endl; + SolutionOFOneTwoStep::debug(); + + return 0; +} + diff --git a/go/08_stack/StackBasedOnArray.go b/go/08_stack/StackBasedOnArray.go index cdecbf8..27e3bec 100644 --- a/go/08_stack/StackBasedOnArray.go +++ b/go/08_stack/StackBasedOnArray.go @@ -28,12 +28,17 @@ func (this *ArrayStack) IsEmpty() bool { } func (this *ArrayStack) Push(v interface{}) { - this.data = append(this.data, v) 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{} { diff --git a/go/08_stack/StackBasedOnArray_test.go b/go/08_stack/StackBasedOnArray_test.go index 0a6ea7d..55dc800 100644 --- a/go/08_stack/StackBasedOnArray_test.go +++ b/go/08_stack/StackBasedOnArray_test.go @@ -6,7 +6,12 @@ func TestArrayStack_Push(t *testing.T) { s := NewArrayStack() s.Push(1) s.Push(2) + t.Log(s.Pop()) s.Push(3) + t.Log(s.Pop()) + t.Log(s.Pop()) + s.Push(4) + t.Log(s.Pop()) s.Print() } diff --git a/go/09_queue/CircularQueue.go b/go/09_queue/CircularQueue.go new file mode 100644 index 0000000..c228490 --- /dev/null +++ b/go/09_queue/CircularQueue.go @@ -0,0 +1,72 @@ +package _9_queue + +import "fmt" + +type CircularQueue struct { + q []interface{} + capacity int + head int + tail int +} + +func NewCircularQueue(n int) *CircularQueue { + if n == 0 { + return nil + } + return &CircularQueue{make([]interface{}, n), n, 0, 0} +} + +/* +栈空条件:head==tail为true +*/ +func (this *CircularQueue) IsEmpty() bool { + if this.head == this.tail { + return true + } + return false +} + +/* +栈满条件:(tail+1)%capacity==head为true +*/ +func (this *CircularQueue) IsFull() bool { + if this.head == (this.tail+1)%this.capacity { + return true + } + return false +} + +func (this *CircularQueue) EnQueue(v interface{}) bool { + if this.IsFull() { + return false + } + this.q[this.tail] = v + this.tail = (this.tail + 1) % this.capacity + return true +} + +func (this *CircularQueue) DeQueue() interface{} { + if this.IsEmpty() { + return nil + } + v := this.q[this.head] + this.head = (this.head + 1) % this.capacity + return v +} + +func (this *CircularQueue) String() string { + if this.IsEmpty() { + return "empty queue" + } + result := "head" + var i = this.head + for true { + result += fmt.Sprintf("<-%+v", this.q[i]) + i = (i + 1) % this.capacity + if i == this.tail { + break + } + } + result += "<-tail" + return result +} diff --git a/go/09_queue/CircularQueue_test.go b/go/09_queue/CircularQueue_test.go new file mode 100644 index 0000000..59c6441 --- /dev/null +++ b/go/09_queue/CircularQueue_test.go @@ -0,0 +1,37 @@ +package _9_queue + +import "testing" + +func TestCircularQueue_EnQueue(t *testing.T) { + q := NewCircularQueue(5) + q.EnQueue(1) + q.EnQueue(2) + q.EnQueue(3) + q.EnQueue(4) + q.EnQueue(5) + q.EnQueue(6) + t.Log(q) +} + +func TestCircularQueue_DeQueue(t *testing.T) { + q := NewCircularQueue(5) + q.EnQueue(1) + q.EnQueue(2) + q.EnQueue(3) + q.EnQueue(4) + q.EnQueue(5) + q.EnQueue(6) + t.Log(q) + t.Log(q.DeQueue()) + t.Log(q) + q.EnQueue(5) + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) +} diff --git a/go/09_queue/QueueBasedOnArray.go b/go/09_queue/QueueBasedOnArray.go new file mode 100644 index 0000000..d70335f --- /dev/null +++ b/go/09_queue/QueueBasedOnArray.go @@ -0,0 +1,44 @@ +package _9_queue + +import "fmt" + +type ArrayQueue struct { + q []interface{} + capacity int + head int + tail int +} + +func NewArrayQueue(n int) *ArrayQueue { + return &ArrayQueue{make([]interface{}, n), n, 0, 0} +} + +func (this *ArrayQueue) EnQueue(v interface{}) bool { + if this.tail == this.capacity { + return false + } + this.q[this.tail] = v + this.tail++ + return true +} + +func (this *ArrayQueue) DeQueue() interface{} { + if this.head == this.tail { + return nil + } + v := this.q[this.head] + this.head++ + return v +} + +func (this *ArrayQueue) String() string { + if this.head == this.tail { + return "empty queue" + } + result := "head" + for i := this.head; i <= this.tail-1; i++ { + result += fmt.Sprintf("<-%+v", this.q[i]) + } + result += "<-tail" + return result +} diff --git a/go/09_queue/QueueBasedOnArray_test.go b/go/09_queue/QueueBasedOnArray_test.go new file mode 100644 index 0000000..50335f7 --- /dev/null +++ b/go/09_queue/QueueBasedOnArray_test.go @@ -0,0 +1,35 @@ +package _9_queue + +import "testing" + +func TestArrayQueue_EnQueue(t *testing.T) { + q := NewArrayQueue(5) + q.EnQueue(1) + q.EnQueue(2) + q.EnQueue(3) + q.EnQueue(4) + q.EnQueue(5) + q.EnQueue(6) + t.Log(q) +} + +func TestArrayQueue_DeQueue(t *testing.T) { + q := NewArrayQueue(5) + q.EnQueue(1) + q.EnQueue(2) + q.EnQueue(3) + q.EnQueue(4) + q.EnQueue(5) + q.EnQueue(6) + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) +} diff --git a/go/09_queue/QueueBasedOnLinkedList.go b/go/09_queue/QueueBasedOnLinkedList.go new file mode 100644 index 0000000..65d898d --- /dev/null +++ b/go/09_queue/QueueBasedOnLinkedList.go @@ -0,0 +1,52 @@ +package _9_queue + +import "fmt" + +type ListNode struct { + val interface{} + next *ListNode +} + +type LinkedListQueue struct { + head *ListNode + tail *ListNode + length int +} + +func NewLinkedListQueue() *LinkedListQueue { + return &LinkedListQueue{nil, nil, 0} +} + +func (this *LinkedListQueue) EnQueue(v interface{}) { + node := &ListNode{v, nil} + if nil == this.tail { + this.tail = node + this.head = node + } else { + this.tail.next = node + this.tail = node + } + this.length++ +} + +func (this *LinkedListQueue) DeQueue() interface{} { + if this.head == nil { + return nil + } + v := this.head.val + this.head = this.head.next + this.length-- + return v +} + +func (this *LinkedListQueue) String() string { + if this.head == nil { + return "empty queue" + } + result := "head<-" + for cur := this.head; cur != nil; cur = cur.next { + result += fmt.Sprintf("<-%+v", cur.val) + } + result += "<-tail" + return result +} diff --git a/go/09_queue/QueueBasedOnLinkedList_test.go b/go/09_queue/QueueBasedOnLinkedList_test.go new file mode 100644 index 0000000..425c6e8 --- /dev/null +++ b/go/09_queue/QueueBasedOnLinkedList_test.go @@ -0,0 +1,35 @@ +package _9_queue + +import "testing" + +func TestListQueue_EnQueue(t *testing.T) { + q := NewLinkedListQueue() + q.EnQueue(1) + q.EnQueue(2) + q.EnQueue(3) + q.EnQueue(4) + q.EnQueue(5) + q.EnQueue(6) + t.Log(q) +} + +func TestListQueue_DeQueue(t *testing.T) { + q := NewLinkedListQueue() + q.EnQueue(1) + q.EnQueue(2) + q.EnQueue(3) + q.EnQueue(4) + q.EnQueue(5) + q.EnQueue(6) + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) + q.DeQueue() + t.Log(q) +} diff --git a/java/05_array/Array.java b/java/05_array/Array.java index 6b7ad05..8ec2fe1 100644 --- a/java/05_array/Array.java +++ b/java/05_array/Array.java @@ -11,14 +11,14 @@ public class Array { public int data[]; //定义数组长度 private int n; - //定义中保存的数据个数 + //定义中实际个数 private int count; //构造方法,定义数组大小 public Array(int capacity){ - this.data = new int[]{0,1,2,3,4}; + this.data = new int[capacity]; this.n = capacity; - this.count=capacity; + this.count=0;//一开始一个数都没有存所以为0 } //根据索引,找到数据中的元素并返回 @@ -49,13 +49,14 @@ public class Array { //向数组中插入一个元素 public boolean insert(int index, int value){ if (index<0 || index>=count) return false; -// if (count == n) return false;不是太懂 - //数组长度增加1 - int[] arr = new int[count+1]; + //当实际存储的个数等于数组的最大长度就不让新增 + if (count == n) return false; + //数组长度增加1。不需要初始化 + /*int[] arr = new int[count+1]; for (int i = 0; i < data.length; i++) { arr[i] = data[i]; } - data=arr; + data=arr;*/ for (int i = count-1; i>=index; --i){ data[i+1] = data[i]; @@ -66,13 +67,15 @@ public class Array { } public boolean insertToTail(int value) { -// if (count == n) return false;不是太懂 + + //当实际存储的个数等于数组的最大长度就不让新增 + if (count == n) return false; //数组长度增加1 - int[] arr = new int[count+1]; + /*int[] arr = new int[count+1]; for (int i = 0; i < data.length; i++) { arr[i] = data[i]; } - data=arr; + data=arr;*/ data[count++] = value; return true; } diff --git a/java/09_queue/CircularQueue.java b/java/09_queue/CircularQueue.java index c3c54cc..71a988c 100644 --- a/java/09_queue/CircularQueue.java +++ b/java/09_queue/CircularQueue.java @@ -36,7 +36,8 @@ public class CircularQueue { } public void printAll() { - for (int i = head; i < tail; ++i) { + if (0 == n) return; + for (int i = head; i % n != tail; ++i) { System.out.print(items[i] + " "); } System.out.println(); diff --git a/java/09_queue/DynimacArrayQueue.java b/java/09_queue/DynamicArrayQueue.java similarity index 94% rename from java/09_queue/DynimacArrayQueue.java rename to java/09_queue/DynamicArrayQueue.java index 3a19fa3..9faad0f 100644 --- a/java/09_queue/DynimacArrayQueue.java +++ b/java/09_queue/DynamicArrayQueue.java @@ -3,7 +3,7 @@ package queue; /** * Created by wangzheng on 2018/10/9. */ -public class DynimacArrayQueue { +public class DynamicArrayQueue { // 数组:items,数组大小:n private String[] items; private int n = 0; @@ -12,7 +12,7 @@ public class DynimacArrayQueue { private int tail = 0; // 申请一个大小为capacity的数组 - public DynimacArrayQueue(int capacity) { + public DynamicArrayQueue(int capacity) { items = new String[capacity]; n = capacity; } diff --git a/javascript/07_linkedlist/LinkedListAlgo.js b/javascript/07_linkedlist/LinkedListAlgo.js index 39cf6e4..77695c9 100644 --- a/javascript/07_linkedlist/LinkedListAlgo.js +++ b/javascript/07_linkedlist/LinkedListAlgo.js @@ -33,7 +33,7 @@ class LinkedList { currentNode = currentNode.next pos++ } - return currentNode === null ? -1 : pos + return currentNode === null ? -1 : currentNode } // 指定元素向后插入 insert(newElement, element) { @@ -69,6 +69,9 @@ class LinkedList { } // 遍历显示所有节点 display() { + //先检查是否为环 + if(this.checkCircle()) return false + let currentNode = this.head while (currentNode !== null) { console.log(currentNode.element) @@ -89,6 +92,30 @@ class LinkedList { this.head = root } + //增强尾插法可读性,便于初学者理解 + reverseList1(){ + //head节点即哨兵,作用就是使所有链表, + // 包括空链表的头节点不为null,并使对单链表的插入、删除操作不需要区分是否为空表或是否在第一个位置进行, + // 从而与其他位置的插入、删除操作一致 + //所以反转链表的时候不需要带上head节点 + let currentNode=this.head.next + //第一个节点头结点让其指向null + let previousNode=null + while(currentNode!==null){ + //务必先保留下一节点的指针地址 + let nextNode=currentNode.next + //第一次是null + currentNode.next=previousNode + //此时将previousNode赋值为当前节点, + // 那么下次循环的时候,方便下次的currentNode指向previousNode + previousNode=currentNode + //抬走,下一个! + currentNode=nextNode + } + //最后将反转好的链表加上头节点 + this.head.next=previousNode + } + // 自己一开始瞎想的。差距啊 reverseList2() { let currentNode = this.head.next @@ -122,6 +149,8 @@ class LinkedList { } // 删除倒数第k个节点 removeByIndexFromEnd(index) { + //务必先判断是否是 环链表 + if(this.checkCircle()) return false let pos = 1 this.reverseList() let currentNode = this.head.next diff --git a/javascript/08_stack/SampleBrowser.js b/javascript/08_stack/SampleBrowser.js new file mode 100644 index 0000000..c084dd7 --- /dev/null +++ b/javascript/08_stack/SampleBrowser.js @@ -0,0 +1,56 @@ +/** + * 使用前后栈实现浏览器的前进后退。 + * + * Author nameczz + */ +const stack = require('./StackBasedOnLinkedList') + +class SampleBrowser { + constructor() { + this.normalStack = new stack.CreatedStack() + this.backStack = new stack.CreatedStack() + } + // 正常浏览页面 + pushNormal(name) { + this.normalStack.push(name) + this.backStack.clear() + this.displayAllStack() + } + // 后退 + back() { + const value = this.normalStack.pop() + if (value !== -1) { + this.backStack.push(value) + this.displayAllStack() + } else { + console.log('无法后退') + } + } + // 前进 + front() { + const value = this.backStack.pop() + if (value !== -1) { + this.normalStack.push(value) + this.displayAllStack() + } else { + console.log('无法前进') + } + } + // 打印栈内数据 + displayAllStack() { + console.log('---后退页面---') + this.backStack.display() + console.log('---浏览页面---') + this.normalStack.display() + } +} +// Test +const browser = new SampleBrowser() +browser.pushNormal('www.google.com') +browser.pushNormal('www.baidu.com') +browser.pushNormal('www.github.com') +// 后退 +browser.back() +browser.back() +browser.front() +browser.pushNormal('www.new.com') \ No newline at end of file diff --git a/javascript/08_stack/StackBasedOnLinkedList.js b/javascript/08_stack/StackBasedOnLinkedList.js new file mode 100644 index 0000000..07acc0e --- /dev/null +++ b/javascript/08_stack/StackBasedOnLinkedList.js @@ -0,0 +1,62 @@ +/** + * 基于链表实现的栈。 + * + * Author: nameczz + */ + +class Node { + constructor(element) { + this.element = element + this.next = null + } +} + +class StackBasedLinkedList { + constructor() { + this.top = null + } + push(value) { + const node = new Node(value) + if (this.top === null) { + this.top = node + } else { + node.next = this.top + this.top = node + } + } + pop() { + if (this.top === null) { + return -1 + } + const value = this.top.element + this.top = this.top.next + return value + } + // 为了实现浏览器前进后退 + clear() { + this.top = null + } + display() { + if (this.top !== null) { + let temp = this.top + while (temp !== null) { + console.log(temp.element) + temp = temp.next + } + } + } +} +// Test +const newStack = new StackBasedLinkedList() +newStack.push(1) +newStack.push(2) +newStack.push(3) +// 获取元素 +let res = 0 +console.log('-------获取pop元素------') +while (res !== -1) { + res = newStack.pop() + console.log(res) +} + +exports.CreatedStack = StackBasedLinkedList \ No newline at end of file diff --git a/javascript/09_queue/CircularQueueBasedOnLinkedList.js b/javascript/09_queue/CircularQueueBasedOnLinkedList.js new file mode 100644 index 0000000..a94f46d --- /dev/null +++ b/javascript/09_queue/CircularQueueBasedOnLinkedList.js @@ -0,0 +1,71 @@ +/** + * 基于链表实现的循环队列。 + * + * Author: nameczz + */ + +class Node { + constructor(element) { + this.element = element + this.next = null + } +} + +class CircularQueue { + constructor() { + this.head = null + this.tail = null + } + + enqueue(value) { + if (this.head === null) { + this.head = new Node(value) + this.head.next = this.head + this.tail = this.head + } else { + const flag = this.head === this.tail + this.tail.next = new Node(value) + this.tail.next.next = this.head + this.tail = this.tail.next + if (flag) { + this.head.next = this.tail + } + } + } + + dequeue() { + if (this.head === this.tail) { + const value = this.head.element + this.head = null + return value + } else if (this.head !== null) { + const value = this.head.element + this.head = this.head.next + this.tail.next = this.head + return value + } else { + return -1 + } + } + + display() { + let res = 0 + console.log('-------获取dequeue元素------') + while (res !== -1) { + res = this.dequeue() + console.log(res) + } + } +} +// Test +const newCircularQueue = new CircularQueue() +// 插入元素 +newCircularQueue.enqueue(1) +newCircularQueue.enqueue(2) +newCircularQueue.enqueue(3) +// 获取元素 +newCircularQueue.display() +newCircularQueue.enqueue(1) +newCircularQueue.display() + +// exports.CreatedStack = StackBasedLinkedList \ No newline at end of file diff --git a/javascript/09_queue/QueueBasedOnLinkedList.js b/javascript/09_queue/QueueBasedOnLinkedList.js new file mode 100644 index 0000000..7591858 --- /dev/null +++ b/javascript/09_queue/QueueBasedOnLinkedList.js @@ -0,0 +1,52 @@ +/** + * 基于链表实现的队列。 + * + * Author: nameczz + */ + +class Node { + constructor(element) { + this.element = element + this.next = null + } +} + +class QueueBasedOnLinkedList { + constructor() { + this.head = null + this.tail = null + } + + enqueue(value) { + if (this.head === null) { + this.head = new Node(value) + this.tail = this.head + } else { + this.tail.next = new Node(value) + this.tail = this.tail.next + } + } + + dequeue() { + if (this.head !== null) { + const value = this.head.element + this.head = this.head.next + return value + } else { + return -1 + } + } +} +// Test +const newQueue = new QueueBasedOnLinkedList() +// 插入元素 +newQueue.enqueue(1) +newQueue.enqueue(2) +newQueue.enqueue(3) +// 获取元素 +let res = 0 +console.log('-------获取dequeue元素------') +while (res !== -1) { + res = newQueue.dequeue() + console.log(res) +} diff --git a/notes/.gitkeep b/notes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/notes/10_recursion/readme.md b/notes/10_recursion/readme.md new file mode 100644 index 0000000..29478b1 --- /dev/null +++ b/notes/10_recursion/readme.md @@ -0,0 +1,28 @@ +# 递归 + +## 三个条件 + +* 可分解为子问题 +* 子问题与原问题解法一致,只有规模上的不同 +* 有终止条件 + +## 写递归代码 + +* 整理出递推公式 +* 确定好终止条件 +* 「翻译」成代码 + +关键: + +> 只要遇到递归,我们就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解每一个步骤。 + +## 警惕 + +* 堆栈溢出 <- 递归深度过大 +* 重复计算 <- 递归过程中的不同分支,重复计算相同子问题 + * 保存子问题结果(map/dict) +* 空间复杂度高 <- 递归函数调用带来的消耗 + +## 递归改写非递归 + +本质:人肉模拟函数调用堆栈。 diff --git a/php/06_linkedlist/SingleLinkedList.php b/php/06_linkedlist/SingleLinkedList.php index 5928860..222f638 100644 --- a/php/06_linkedlist/SingleLinkedList.php +++ b/php/06_linkedlist/SingleLinkedList.php @@ -133,7 +133,7 @@ class SingleLinkedList $preNode = $this->head; // 遍历找到前置节点 要用全等判断是否是同一个对象 // http://php.net/manual/zh/language.oop5.object-comparison.php - while ($curNode !== $node) { + while ($curNode !== $node && $curNode != null) { $preNode = $curNode; $curNode = $curNode->next; } diff --git a/php/08_stack/.gitkeep b/php/08_stack/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/php/08_stack/StackOnLinkedList.php b/php/08_stack/StackOnLinkedList.php new file mode 100644 index 0000000..bfac655 --- /dev/null +++ b/php/08_stack/StackOnLinkedList.php @@ -0,0 +1,159 @@ +head = new SingleLinkedListNode(); + $this->length = 0; + } + + /** + * 出栈 + * + * @return bool + */ + public function pop() + { + if (0 == $this->length) { + return false; + } + + $this->head->next = $this->head->next->next; + $this->length--; + + return true; + } + + /** + * 入栈 + * + * @param $data + * + * @return SingleLinkedListNode|bool + */ + public function push($data) + { + return $this->pushData($data); + } + + /** + * 入栈 node + * + * @param SingleLinkedListNode $node + * + * @return bool + */ + public function pushNode(SingleLinkedListNode $node) + { + if (null == $node) { + return false; + } + + $node->next = $this->head->next; + $this->head->next = $node; + + $this->length++; + return true; + } + + /** + * 入栈 data + * + * @param $data + * + * @return SingleLinkedListNode|bool + */ + public function pushData($data) + { + $node = new SingleLinkedListNode($data); + + if (!$this->pushNode($node)) { + return false; + } + + return $node; + } + + /** + * 获取栈顶元素 + * + * @return SingleLinkedListNode|bool|null + */ + public function top() + { + if (0 == $this->length) { + return false; + } + + return $this->head->next; + } + + /** + * 打印栈 + */ + public function printSelf() + { + if (0 == $this->length) { + echo 'empty stack' . PHP_EOL; + return; + } + + echo 'head.next -> '; + $curNode = $this->head; + while ($curNode->next) { + echo $curNode->next->data . ' -> '; + + $curNode = $curNode->next; + } + echo 'NULL' . PHP_EOL; + } + + /** + * 获取栈长度 + * + * @return int + */ + public function getLength() + { + return $this->length; + } + + /** + * 判断栈是否为空 + * + * @return bool + */ + public function isEmpty() + { + return $this->length > 0 ? false : true; + } +} \ No newline at end of file diff --git a/php/08_stack/main.php b/php/08_stack/main.php new file mode 100644 index 0000000..6347821 --- /dev/null +++ b/php/08_stack/main.php @@ -0,0 +1,32 @@ +pushData(1); +$stack->pushData(2); +$stack->pushData(3); +$stack->pushData(4); +var_dump($stack->getLength()); +$stack->printSelf(); + +$topNode = $stack->top(); +var_dump($topNode->data); + +$stack->pop(); +$stack->printSelf(); +$stack->pop(); +$stack->printSelf(); + +var_dump($stack->getLength()); + +$stack->pop(); +$stack->pop(); +$stack->printSelf(); \ No newline at end of file diff --git a/php/README.md b/php/README.md index 3aa9674..6a6fa5d 100644 --- a/php/README.md +++ b/php/README.md @@ -1,16 +1,20 @@ ## 数据结构与算法之美PHP实现 ### 项目运行 -* 依赖composer自动加载,php目录下执行`composer dump-autoload` +* 依赖composer自动加载,php目录下执行`composer dump-autoload` || `sh buildAutoLoad.sh` * 项目代码均在mac&php7环境下跑通 ### 项目实现 -#### 06 +#### 06_linkedlist * 单链表php实现 * 回文判断 -#### 07 + +#### 07_linkedlist * reverse 单链表反转 * checkCircle 链表中环的检测 * mergerSortedList 两个有序的链表合并 * deleteLastKth 删除链表倒数第n个结点 -* findMiddleNode 求链表的中间结点 \ No newline at end of file +* findMiddleNode 求链表的中间结点 + +#### 08_stack +* 链栈实现 \ No newline at end of file diff --git a/php/Stack/Compute.php b/php/Stack/Compute.php new file mode 100644 index 0000000..3e5624b --- /dev/null +++ b/php/Stack/Compute.php @@ -0,0 +1,78 @@ += 48 && ord($arr[$i] <= 57)){ + array_push($numStack, $arr[$i]); + continue; + } + switch ($arr[$i]){ + case '+': + case '-': + $arrLen = count($operStack); + while ($operStack[$arrLen-1] === '*' || $operStack[$arrLen-1] === '/' || $operStack[$arrLen-1] === '-'){ + compute($numStack, $operStack); + $arrLen--; + } + array_push($operStack, $arr[$i]); + break; + case '*': + case '/': + case '(': + array_push($operStack, $arr[$i]); + break; + case ')': + $arrLen = count($operStack); + while ($operStack[$arrLen-1] !== '('){ + compute($numStack, $operStack); + $arrLen--; + } + array_pop($operStack); + break; + default: + throw new \Exception("不支持的运算符", 1); + break; + } + } + + $arrLen = count($operStack); + while ($operStack[$arrLen-1] !== NULL){ + compute($numStack, $operStack); + $arrLen--; + } + echo array_pop($numStack); +} + +//数字栈长度减一,运算符栈长度减一 +function compute(&$numStack, &$operStack){ + $num = array_pop($numStack); + switch (array_pop($operStack)) { + case '*': + array_push($numStack, array_pop($numStack) * $num); + break; + case '/': + array_push($numStack, array_pop($numStack) / $num); + break; + case '+': + array_push($numStack, array_pop($numStack) + $num); + break; + case '-': + array_push($numStack, array_pop($numStack) - $num); + break; + + } +} +expression('-1+2-(1+2*3)'); +echo PHP_EOL; +eval('echo -1+2-(1+2*3);'); \ No newline at end of file diff --git a/php/composer.json b/php/composer.json index ea60240..01f6f02 100644 --- a/php/composer.json +++ b/php/composer.json @@ -6,7 +6,8 @@ "autoload": { "psr-4": { "Algo_06\\": "06_linkedlist/", - "Algo_07\\": "07_linkedlist/" + "Algo_07\\": "07_linkedlist/", + "Algo_08\\": "08_stack/" } } } diff --git a/python/05_array/myarray.py b/python/05_array/myarray.py index af55480..e4df25b 100644 --- a/python/05_array/myarray.py +++ b/python/05_array/myarray.py @@ -39,7 +39,10 @@ class MyArray: def insert_to_tail(self, value: int) -> bool: if self._count == self._capacity: return False - self._data.append(value) + if self._count == len(self._data): + self._data.append(value) + else: + self._data[self._count] = value self._count += 1 return True @@ -57,4 +60,6 @@ if __name__ == "__main__": a.insert_to_tail(i) a.delete(2) + print(a) + a.insert_to_tail(7) print(a) \ No newline at end of file diff --git a/python/07_linkedlist/linked_list_algo.py b/python/07_linkedlist/linked_list_algo.py index 9427126..4d69ae8 100644 --- a/python/07_linkedlist/linked_list_algo.py +++ b/python/07_linkedlist/linked_list_algo.py @@ -55,7 +55,7 @@ def merge_sorted_list(l1: Node, l2: Node) -> Optional[Node]: current = current._next current._next = p1 if p1 else p2 return fake_head._next - return p1 or p2 + return l1 or l2 # Remove nth node from the end # 删除倒数第n个节点。假设n大于0 diff --git a/python/09_queue/array_queue.py b/python/09_queue/array_queue.py index 40f34c2..1b1252e 100644 --- a/python/09_queue/array_queue.py +++ b/python/09_queue/array_queue.py @@ -16,9 +16,16 @@ class ArrayQueue: self._tail = 0 def enqueue(self, item: str) -> bool: - if self._tail == self._capacity: return False + if self._tail == self._capacity: + if self._head == 0: + return False + else: + for i in range(0, self._tail - self._head): + self._data[i] = self._items[i + self._head] + self._tail = self._tail - self._head + self._head = 0 - self._items.append(item) + self._items.insert(self._tail, item) self._tail += 1 return True diff --git a/python/09_queue/dynamic_array_queue.py b/python/09_queue/dynamic_array_queue.py new file mode 100644 index 0000000..b422840 --- /dev/null +++ b/python/09_queue/dynamic_array_queue.py @@ -0,0 +1,51 @@ +""" + Author: Wenru +""" + +from typing import Optional + +class DynamicArrayQueue: + + def __init__(self, capacity: int): + self._items = [] + self._capacity = capacity + self._head = 0 + self._tail = 0 + + def enqueue(self, item: str) -> bool: + if self._tail == self._capacity: + if self._head == 0: return False + + self._items[0 : self._tail - self._head] = self._items[self._head : self._tail] + self._tail -= self._head + self._head = 0 + + if self._tail == len(self._items): + self._items.append(item) + else: + self._items[self._tail] = item + self._tail += 1 + return True + + def dequeue(self) -> Optional[str]: + if self._head != self._tail: + item = self._items[self._head] + self._head += 1 + return item + + def __repr__(self) -> str: + return " ".join(item for item in self._items[self._head:self._tail]) + +if __name__ == "__main__": + q = DynamicArrayQueue(10) + for i in range(10): + q.enqueue(str(i)) + print(q) + + for _ in range(3): + q.dequeue() + print(q) + + q.enqueue("7") + q.enqueue("8") + print(q) \ No newline at end of file diff --git a/python/09_queue/linked_queue.py b/python/09_queue/linked_queue.py new file mode 100644 index 0000000..4ee4ecf --- /dev/null +++ b/python/09_queue/linked_queue.py @@ -0,0 +1,58 @@ +""" + Queue based upon linked list + + Author: Wenru +""" + +from typing import Optional + +class Node: + + def __init__(self, data: str, next=None): + self.data = data + self._next = next + +class LinkedQueue: + + def __init__(self): + self._head: Optional[Node] = None + self._tail: Optional[Node] = None + + def enqueue(self, value: str): + new_node = Node(value) + if self._tail: + self._tail._next = new_node + else: + self._head = new_node + self._tail = new_node + + def dequeue(self) -> Optional[str]: + if self._head: + value = self._head.data + self._head = self._head._next + if not self._head: + self._tail = None + return value + + def __repr__(self) -> str: + values = [] + current = self._head + while current: + values.append(current.data) + current = current._next + return "->".join(value for value in values) + + +if __name__ == "__main__": + q = LinkedQueue() + for i in range(10): + q.enqueue(str(i)) + print(q) + + for _ in range(3): + q.dequeue() + print(q) + + q.enqueue("7") + q.enqueue("8") + print(q) diff --git a/swift/05_array/MyArray.swift b/swift/05_array/MyArray.swift new file mode 100644 index 0000000..42a135b --- /dev/null +++ b/swift/05_array/MyArray.swift @@ -0,0 +1,77 @@ +// +// Created by Jiandan on 2018/10/10. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +// Swift 泛型,此数组支持不同数据类型 +public struct MyArray { + private var data: [Element] + private var capacity = 0 // 数组长度 + private var count = 0 // 已保存的数据个数 + + /// 构造方法 + /// - parameter defaultElement: 默认元素,用来占位 + /// - parameter capacity: 数组长度 + init(defaultElement: Element, capacity: Int) { + data = [Element](repeating: defaultElement, count: capacity) + self.capacity = capacity + } + + // 根据 index,查找元素 + func find(at index: Int) -> Element? { + // index 必须在 [0, count) + guard index >= 0, index < count else { + return nil + } + + return data[index] + } + + // 根据 index,删除元素 + mutating func delete(at index: Int) -> Bool { + // index 必须在 [0, count) + guard index >= 0, index < count else { + return false + } + + // [index, count - 1) 从 index 开始,元素分别向前移动一位 + for i in index ..< count - 1 { + data[i] = data[i+1] + } + count -= 1 + return true + } + + // 根据 index 插入元素 + mutating func insert(value: Element, at index: Int) -> Bool { + // index 必须在 [0, count) + guard index >= 0, index < count, count < capacity else { + return false + } + + // count - 1 ~ index + for i in (index ... count - 1).reversed() { + data[i + 1] = data[i] + } + + data[index] = value + count += 1 + return true + } + + // 添加元素 + mutating func add(value: Element) -> Bool { + guard count < capacity else { + return false + } + data[count] = value + count += 1 + return true + } + + func printAll() { + print("\(data)") + } +} diff --git a/swift/09_queue/ArrayQueue.swift b/swift/09_queue/ArrayQueue.swift new file mode 100644 index 0000000..1dea014 --- /dev/null +++ b/swift/09_queue/ArrayQueue.swift @@ -0,0 +1,112 @@ +// +// Created by Jiandan on 2018/10/11. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +/// 用数组实现的队列 +struct ArrayQueue: Queue { + typealias Element = T + + /// 数组 + private var items: [Element] + /// 数组最大长度 + private var capacity = 0 + /// 队头下标 + private var head = 0 + /// 队尾下标 + private var tail = 0 + + /// 构造方法 + /// - parameter defaultElement: 默认元素 + /// - parameter capacity: 数组长度 + init(defaultElement: Element, capacity: Int) { + self.capacity = capacity + items = [Element](repeating: defaultElement, count: capacity) + } + + // MARK: Protocol: Queue + + var isEmpty: Bool { return head == tail } + + var size: Int { return tail - head } + + var peek: Element? { return isEmpty ? nil : items[head] } + + // 没有数据搬移的实现,即实现了一个有界序列 +// mutating func enqueue(newElement: Element) -> Bool { +// // 整个队列都占满了 +// if tail == capacity { +// return false +// } +// +// items[tail] = newElement +// tail += 1 +// return true +// } + // 有数据搬移的实现,即实现了一个无界序列 + mutating func enqueue(newElement: Element) -> Bool { + // 如果 tail == capacity 表示队列末尾没有空间了 + if tail == capacity { + // 整个队列都占满了 + if head == 0 { return false } + // 数据搬移 + for i in head ..< tail { + items[i - head] = items[i] + } + // 搬移完之后重新更新 head 和 tail + tail -= head + head = 0 + } + + items[tail] = newElement + tail += 1 + return true + } + + mutating func dequeue() -> Element? { + if isEmpty { + return nil + } + + let item = items[head] + head += 1 + return item + } +} + +/// 使用2个数组实现无界队列,用到 Swift 中 Array 较多的方法 +/// 来源:《iOS 面试之道》(故胤道长,唐巧) +struct ArrayQueue2: Queue { + typealias Element = T + + /// 输入数组,主要负责入队 + var inArray = [Element]() + /// 输出数组,主要负责出队 + var outArray = [Element]() + + var isEmpty: Bool { return inArray.isEmpty && outArray.isEmpty } + + var size: Int { return inArray.count + outArray.count } + + // 当 outArray 为空时,返回 inArray 首个元素,否则返回 outArray 末尾元素 + var peek: Element? { return outArray.isEmpty ? inArray.first : outArray.last } + + mutating func enqueue(newElement: Element) -> Bool { + // inArray 添加元素 + inArray.append(newElement) + return true + } + + mutating func dequeue() -> Element? { + if outArray.isEmpty { + // 将 inArray 倒序存入 outArray 中 + outArray = inArray.reversed() + // 清空 inArray + inArray.removeAll() + } + // 弹出 outArray 最后一个元素 + return outArray.popLast() + } +} diff --git a/swift/09_queue/CircularQueue.swift b/swift/09_queue/CircularQueue.swift new file mode 100644 index 0000000..6a58f98 --- /dev/null +++ b/swift/09_queue/CircularQueue.swift @@ -0,0 +1,63 @@ +// +// Created by Jiandan on 2018/10/11. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +/// 循环队列 +struct CircularQueue: Queue { + typealias Element = T + + /// 数组 + private var items: [Element] + /// 数组最大长度 + private var capacity = 0 + /// 队头下标 + private var head = 0 + /// 队尾下标 + private var tail = 0 + + /// 构造方法 + /// - parameter defaultElement: 默认元素 + /// - parameter capacity: 数组长度 + init(defaultElement: Element, capacity: Int) { + self.capacity = capacity + items = [Element](repeating: defaultElement, count: capacity) + } + + // MARK: Protocol: Queue + + var isEmpty: Bool { return head == tail } + + var size: Int { + if tail >= head { + return tail - head + } else { + return (tail + 1) + (capacity - head) + } + } + + var peek: Element? { return isEmpty ? nil : items[head] } + + mutating func enqueue(newElement: Element) -> Bool { + // 整个队列都占满了 + if (tail + 1) % capacity == head { + return false + } + + items[tail] = newElement + tail = (tail + 1) % capacity + return true + } + + mutating func dequeue() -> Element? { + if isEmpty { + return nil + } + + let item = items[head] + head = (head + 1) % capacity + return item + } +} diff --git a/swift/09_queue/Queue.swift b/swift/09_queue/Queue.swift new file mode 100644 index 0000000..ab0bdd9 --- /dev/null +++ b/swift/09_queue/Queue.swift @@ -0,0 +1,21 @@ +// +// Created by Jiandan on 2018/10/11. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +protocol Queue { + /// 持有的数据类型 + associatedtype Element + /// 是否为空 + var isEmpty: Bool { get } + /// 队列大小 + var size: Int { get } + /// 返回队列头部元素 + var peek: Element? { get } + /// 入队 + mutating func enqueue(newElement: Element) -> Bool + /// 出队 + mutating func dequeue() -> Element? +} diff --git a/swift/09_queue/QueueBasedOnLinkedList.swift b/swift/09_queue/QueueBasedOnLinkedList.swift new file mode 100644 index 0000000..be73795 --- /dev/null +++ b/swift/09_queue/QueueBasedOnLinkedList.swift @@ -0,0 +1,61 @@ +// +// Created by Jiandan on 2018/10/11. +// Copyright (c) 2018 Jiandan. All rights reserved. +// + +import Foundation + +class Node { + var value: T? + var next: Node? + + init(value: T) { + self.value = value + } +} + +struct QueueBasedOnLinkedList: Queue { + typealias Element = T + + /// 队首 + var head: Node? + /// 队尾 + var tail: Node? + + // MARK: Protocol: Queue + + var isEmpty: Bool { return head == nil } + + var size: Int { + var count = 0 + while head?.next != nil { + count += 1 + } + return count + } + + var peek: Element? { return head?.value } + + mutating func enqueue(newElement: Element) -> Bool { + if isEmpty { + // 空队列 + let node = Node(value: newElement) + head = node + tail = node + } else { + tail!.next = Node(value: newElement) + tail = tail!.next + } + return true + } + + mutating func dequeue() -> Element? { + if isEmpty { + return nil + } + + let node = head + head = head!.next + return node?.value + } +}