commit
c6275984b0
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,3 +24,4 @@ hs_err_pid*
|
||||
|
||||
# editor files
|
||||
.vscode
|
||||
.*.swp
|
||||
|
@ -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
|
||||
|
278
c-cpp/05_array/Array_gp.c
Normal file
278
c-cpp/05_array/Array_gp.c
Normal file
@ -0,0 +1,278 @@
|
||||
#include "Array.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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;
|
||||
}
|
48
c-cpp/05_array/Array_gp.h
Normal file
48
c-cpp/05_array/Array_gp.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef __ARRAY_H__
|
||||
#define __ARRAY_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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__
|
220
c-cpp/06_linkedlist/Dlist/Dlist.c
Normal file
220
c-cpp/06_linkedlist/Dlist/Dlist.c
Normal file
@ -0,0 +1,220 @@
|
||||
/*************************************************************************
|
||||
> File Name: Dlist.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-07
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include <stdbool.h>
|
||||
#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;
|
||||
}
|
23
c-cpp/06_linkedlist/Dlist/Dlist.h
Normal file
23
c-cpp/06_linkedlist/Dlist/Dlist.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*************************************************************************
|
||||
> File Name: Dlist.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-07
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
|
||||
typedef struct DlistNode
|
||||
{
|
||||
struct DlistNode *prev;
|
||||
struct DlistNode *next;
|
||||
int data;
|
||||
}stDlistNode;
|
||||
|
||||
typedef struct Dlisthead
|
||||
{
|
||||
int size;
|
||||
stDlistNode *head;
|
||||
stDlistNode *tail;
|
||||
}stDlistHead;
|
||||
|
0
c-cpp/09_queue/.gitkeep
Normal file
0
c-cpp/09_queue/.gitkeep
Normal file
97
c-cpp/09_queue/array_queue.hpp
Normal file
97
c-cpp/09_queue/array_queue.hpp
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/10.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_ARRAY_QUEUE_HPP_
|
||||
#define QUEUE_ARRAY_QUEUE_HPP_
|
||||
|
||||
template <typename T>
|
||||
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 <typename UnaryFunc>
|
||||
void traverse(UnaryFunc do_traverse) {
|
||||
for (size_t i = head_; i != tail_; ++i) {
|
||||
do_traverse(items_[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUEUE_ARRAY_QUEUE_HPP_
|
56
c-cpp/09_queue/array_queue_test.cc
Normal file
56
c-cpp/09_queue/array_queue_test.cc
Normal file
@ -0,0 +1,56 @@
|
||||
#include <iostream>
|
||||
#include "array_queue.hpp"
|
||||
|
||||
int main() {
|
||||
auto do_traverse = [&](auto item){ std::cout << item << ' '; };
|
||||
|
||||
ArrayQueue<int> 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<int> array_queue_2(array_queue_1); // copy constructor
|
||||
array_queue_2.traverse(do_traverse);
|
||||
std::cout << std::endl;
|
||||
|
||||
ArrayQueue<int> 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<int> array_queue_4(1);
|
||||
array_queue_4 = array_queue_1; // copy assignment
|
||||
array_queue_4.traverse(do_traverse);
|
||||
std::cout << std::endl;
|
||||
|
||||
ArrayQueue<int> 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;
|
||||
}
|
82
c-cpp/09_queue/block_queue.hpp
Normal file
82
c-cpp/09_queue/block_queue.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/11.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_BLOCK_QUEUE_HPP_
|
||||
#define QUEUE_BLOCK_QUEUE_HPP_
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
template <typename T>
|
||||
class BlockQueue {
|
||||
public:
|
||||
using value_type = T;
|
||||
using container_type = std::queue<value_type>;
|
||||
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<std::mutex> lock(mutex_);
|
||||
while (full()) {
|
||||
not_full_.wait(lock);
|
||||
}
|
||||
container_.push(item);
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
void take(value_type& out) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (empty()) {
|
||||
not_empty_.wait(lock);
|
||||
}
|
||||
out = container_.front();
|
||||
container_.pop();
|
||||
not_full_.notify_one();
|
||||
}
|
||||
template <typename Duration>
|
||||
bool put_for(const value_type& item, const Duration& d) {
|
||||
std::unqiue_lock<std::mutex> 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 <typename Duration>
|
||||
bool take_for(const Duration& d, value_type& out) {
|
||||
std::unique_lock<std::mutex> 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_
|
||||
|
99
c-cpp/09_queue/circular_queue.hpp
Normal file
99
c-cpp/09_queue/circular_queue.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/10.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_CIRCULAR_QUEUE_HPP_
|
||||
#define QUEUE_CIRCULAR_QUEUE_HPP_
|
||||
|
||||
template <typename T>
|
||||
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 <typename UnaryFunc>
|
||||
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_
|
62
c-cpp/09_queue/circular_queue_test.cc
Normal file
62
c-cpp/09_queue/circular_queue_test.cc
Normal file
@ -0,0 +1,62 @@
|
||||
#include <iostream>
|
||||
#include "circular_queue.hpp"
|
||||
|
||||
int main() {
|
||||
auto do_traverse = [&](auto item){ std::cout << item << ' '; };
|
||||
|
||||
CircularQueue<int> 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<int> circular_queue_2(circular_queue_1); // copy constructor
|
||||
circular_queue_2.traverse(do_traverse);
|
||||
std::cout << std::endl;
|
||||
|
||||
CircularQueue<int> 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<int> circular_queue_4(1);
|
||||
circular_queue_4 = circular_queue_1; // copy assignment
|
||||
circular_queue_4.traverse(do_traverse);
|
||||
std::cout << std::endl;
|
||||
|
||||
CircularQueue<int> 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;
|
||||
}
|
85
c-cpp/09_queue/concurrency_queue.hpp
Normal file
85
c-cpp/09_queue/concurrency_queue.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/11.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_CONCURRENCY_QUEUE_HPP_
|
||||
#define QUEUE_CONCURRENCY_QUEUE_HPP_
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
|
||||
template <typename T>
|
||||
class ConcurrencyQueue {
|
||||
public:
|
||||
using value_type = T;
|
||||
using container_type = std::queue<value_type>;
|
||||
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<std::mutex> lg(mutex_);
|
||||
return container_.empty();
|
||||
}
|
||||
void push(value_type item) {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
container_.push(std::move(item));
|
||||
container_cond_.notify_one();
|
||||
}
|
||||
void wait_and_pop(value_type& out) {
|
||||
std::unique_lock<std::mutex> lk(mutex_);
|
||||
while (empty_()) {
|
||||
container_cond_.wait(lk)
|
||||
}
|
||||
out = std::move(container_.front());
|
||||
container_.pop();
|
||||
}
|
||||
std::shared_ptr<value_type> wait_and_pop() {
|
||||
std::unique_lock<std::mutex> lk(mutex_);
|
||||
while (empty_()) {
|
||||
container_cond_.wait(lk)
|
||||
}
|
||||
auto res = std::make_shared<value_type>(std::move(container_.front()));
|
||||
container_.pop();
|
||||
return res;
|
||||
}
|
||||
bool try_pop(value_type& out) {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
if (empty_()) {
|
||||
return false;
|
||||
} else {
|
||||
out = std::move(container_.front());
|
||||
container_.pop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
std::shared_ptr<value_type> try_pop() {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
if (empty_()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
auto res = std::make_shared<value_type>(std::move(container_.front()));
|
||||
container_.pop();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUEUE_CONCURRENCY_QUEUE_HPP_
|
||||
|
105
c-cpp/09_queue/dynamic_array_queue.hpp
Normal file
105
c-cpp/09_queue/dynamic_array_queue.hpp
Normal file
@ -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 <typename T>
|
||||
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 <typename UnaryFunc>
|
||||
void traverse(UnaryFunc do_traverse) {
|
||||
for (size_t i = head_; i != tail_; ++i) {
|
||||
do_traverse(items_[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUEUE_DYNAMIC_ARRAY_QUEUE_HPP_
|
62
c-cpp/09_queue/dynamic_array_queue_test.cc
Normal file
62
c-cpp/09_queue/dynamic_array_queue_test.cc
Normal file
@ -0,0 +1,62 @@
|
||||
#include <iostream>
|
||||
#include "dynamic_array_queue.hpp"
|
||||
|
||||
int main() {
|
||||
auto do_traverse = [&](auto item){ std::cout << item << ' '; };
|
||||
|
||||
DynamicArrayQueue<int> 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<int> dynamic_array_queue_2(dynamic_array_queue_1); // copy constructor
|
||||
dynamic_array_queue_2.traverse(do_traverse);
|
||||
std::cout << std::endl;
|
||||
|
||||
DynamicArrayQueue<int> 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<int> 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<int> 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;
|
||||
}
|
75
c-cpp/09_queue/linked_queue.hpp
Normal file
75
c-cpp/09_queue/linked_queue.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/10.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_LINKED_QUEUE_HPP_
|
||||
#define QUEUE_LINKED_QUEUE_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
template <typename T>
|
||||
struct Node {
|
||||
using ptr_t = std::shared_ptr<Node<T>>;
|
||||
T data;
|
||||
ptr_t next;
|
||||
|
||||
Node(T data_) : data(data_), next(nullptr) {}
|
||||
Node() : next(nullptr) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LinkedQueue {
|
||||
public:
|
||||
using node_type = Node<T>;
|
||||
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<node_type>(item);
|
||||
before_tail_ = head_;
|
||||
} else {
|
||||
before_tail_->next = std::make_shared<node_type>(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 <typename UnaryFunc>
|
||||
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_
|
55
c-cpp/09_queue/linked_queue_test.cc
Normal file
55
c-cpp/09_queue/linked_queue_test.cc
Normal file
@ -0,0 +1,55 @@
|
||||
#include <iostream>
|
||||
#include "linked_queue.hpp"
|
||||
|
||||
int main() {
|
||||
auto do_traverse = [&](auto item){ std::cout << item << ' '; };
|
||||
|
||||
LinkedQueue<int> 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<int> linked_queue_2(linked_queue_1); // copy constructor
|
||||
linked_queue_2.traverse(do_traverse);
|
||||
std::cout << std::endl;
|
||||
|
||||
LinkedQueue<int> 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<int> linked_queue_4;
|
||||
linked_queue_4 = linked_queue_1; // copy assignment
|
||||
linked_queue_4.traverse(do_traverse);
|
||||
std::cout << std::endl;
|
||||
|
||||
LinkedQueue<int> 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;
|
||||
}
|
84
c-cpp/09_queue/lock_free_queue.hpp
Normal file
84
c-cpp/09_queue/lock_free_queue.hpp
Normal file
@ -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 <memory>
|
||||
#include <atomic>
|
||||
|
||||
template <typename T>
|
||||
class LockFreeQueue {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
private:
|
||||
struct node {
|
||||
std::shared<value_type> data = nullptr;
|
||||
node* next = nullptr;
|
||||
};
|
||||
std::atomic<node*> head = nullptr;
|
||||
std::atomic<node*> 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<value_type> 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<value_type>(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_
|
||||
|
0
c-cpp/10_recursive/.gitkeep
Normal file
0
c-cpp/10_recursive/.gitkeep
Normal file
71
c-cpp/10_recursive/one_two_step.cc
Normal file
71
c-cpp/10_recursive/one_two_step.cc
Normal file
@ -0,0 +1,71 @@
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
|
||||
class SolutionOFOneTwoStep {
|
||||
private:
|
||||
static std::unordered_map<size_t, size_t> 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<size_t, size_t> 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;
|
||||
}
|
||||
|
@ -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{} {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
72
go/09_queue/CircularQueue.go
Normal file
72
go/09_queue/CircularQueue.go
Normal file
@ -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
|
||||
}
|
37
go/09_queue/CircularQueue_test.go
Normal file
37
go/09_queue/CircularQueue_test.go
Normal file
@ -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)
|
||||
}
|
44
go/09_queue/QueueBasedOnArray.go
Normal file
44
go/09_queue/QueueBasedOnArray.go
Normal file
@ -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
|
||||
}
|
35
go/09_queue/QueueBasedOnArray_test.go
Normal file
35
go/09_queue/QueueBasedOnArray_test.go
Normal file
@ -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)
|
||||
}
|
52
go/09_queue/QueueBasedOnLinkedList.go
Normal file
52
go/09_queue/QueueBasedOnLinkedList.go
Normal file
@ -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
|
||||
}
|
35
go/09_queue/QueueBasedOnLinkedList_test.go
Normal file
35
go/09_queue/QueueBasedOnLinkedList_test.go
Normal file
@ -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)
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
56
javascript/08_stack/SampleBrowser.js
Normal file
56
javascript/08_stack/SampleBrowser.js
Normal file
@ -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')
|
62
javascript/08_stack/StackBasedOnLinkedList.js
Normal file
62
javascript/08_stack/StackBasedOnLinkedList.js
Normal file
@ -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
|
71
javascript/09_queue/CircularQueueBasedOnLinkedList.js
Normal file
71
javascript/09_queue/CircularQueueBasedOnLinkedList.js
Normal file
@ -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
|
52
javascript/09_queue/QueueBasedOnLinkedList.js
Normal file
52
javascript/09_queue/QueueBasedOnLinkedList.js
Normal file
@ -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)
|
||||
}
|
0
notes/.gitkeep
Normal file
0
notes/.gitkeep
Normal file
28
notes/10_recursion/readme.md
Normal file
28
notes/10_recursion/readme.md
Normal file
@ -0,0 +1,28 @@
|
||||
# 递归
|
||||
|
||||
## 三个条件
|
||||
|
||||
* 可分解为子问题
|
||||
* 子问题与原问题解法一致,只有规模上的不同
|
||||
* 有终止条件
|
||||
|
||||
## 写递归代码
|
||||
|
||||
* 整理出递推公式
|
||||
* 确定好终止条件
|
||||
* 「翻译」成代码
|
||||
|
||||
关键:
|
||||
|
||||
> 只要遇到递归,我们就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解每一个步骤。
|
||||
|
||||
## 警惕
|
||||
|
||||
* 堆栈溢出 <- 递归深度过大
|
||||
* 重复计算 <- 递归过程中的不同分支,重复计算相同子问题
|
||||
* 保存子问题结果(map/dict)
|
||||
* 空间复杂度高 <- 递归函数调用带来的消耗
|
||||
|
||||
## 递归改写非递归
|
||||
|
||||
本质:人肉模拟函数调用堆栈。
|
@ -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;
|
||||
}
|
||||
|
0
php/08_stack/.gitkeep
Normal file
0
php/08_stack/.gitkeep
Normal file
159
php/08_stack/StackOnLinkedList.php
Normal file
159
php/08_stack/StackOnLinkedList.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* User: lide01
|
||||
* Date: 2018/10/11 19:37
|
||||
* Desc:
|
||||
*/
|
||||
|
||||
namespace Algo_08;
|
||||
|
||||
|
||||
use Algo_06\SingleLinkedListNode;
|
||||
|
||||
class StackOnLinkedList
|
||||
{
|
||||
/**
|
||||
* 头指针
|
||||
*
|
||||
* @var SingleLinkedListNode
|
||||
*/
|
||||
public $head;
|
||||
|
||||
/**
|
||||
* 栈长度
|
||||
*
|
||||
* @var
|
||||
*/
|
||||
public $length;
|
||||
|
||||
/**
|
||||
*
|
||||
* StackOnLinkedList constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
32
php/08_stack/main.php
Normal file
32
php/08_stack/main.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* User: lide01
|
||||
* Date: 2018/10/11 20:01
|
||||
* Desc:
|
||||
*/
|
||||
|
||||
namespace Algo_08;
|
||||
|
||||
require_once '../vendor/autoload.php';
|
||||
|
||||
$stack = new StackOnLinkedList();
|
||||
$stack->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();
|
@ -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 求链表的中间结点
|
||||
* findMiddleNode 求链表的中间结点
|
||||
|
||||
#### 08_stack
|
||||
* 链栈实现
|
78
php/Stack/Compute.php
Normal file
78
php/Stack/Compute.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
// 四则运算 +-*/()
|
||||
function expression($str)
|
||||
{
|
||||
$str = str_replace(' ','',$str);
|
||||
$arr = preg_split('/([\+\-\*\/\(\)])/', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
$numStack = []; // 存放数字
|
||||
$operStack = []; // 存放运算符
|
||||
$operStack[] = NULL;
|
||||
|
||||
for ($i = 0; $i < count($arr); $i++){
|
||||
if (ord($arr[$i]) >= 48 && ord($arr[$i] <= 57)){
|
||||
array_push($numStack, $arr[$i]);
|
||||
continue;
|
||||
}
|
||||
switch ($arr[$i]){
|
||||
case '+':
|
||||
case '-':
|
||||
$arrLen = count($operStack);
|
||||
while ($operStack[$arrLen-1] === '*' || $operStack[$arrLen-1] === '/' || $operStack[$arrLen-1] === '-'){
|
||||
compute($numStack, $operStack);
|
||||
$arrLen--;
|
||||
}
|
||||
array_push($operStack, $arr[$i]);
|
||||
break;
|
||||
case '*':
|
||||
case '/':
|
||||
case '(':
|
||||
array_push($operStack, $arr[$i]);
|
||||
break;
|
||||
case ')':
|
||||
$arrLen = count($operStack);
|
||||
while ($operStack[$arrLen-1] !== '('){
|
||||
compute($numStack, $operStack);
|
||||
$arrLen--;
|
||||
}
|
||||
array_pop($operStack);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception("不支持的运算符", 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$arrLen = count($operStack);
|
||||
while ($operStack[$arrLen-1] !== NULL){
|
||||
compute($numStack, $operStack);
|
||||
$arrLen--;
|
||||
}
|
||||
echo array_pop($numStack);
|
||||
}
|
||||
|
||||
//数字栈长度减一,运算符栈长度减一
|
||||
function compute(&$numStack, &$operStack){
|
||||
$num = array_pop($numStack);
|
||||
switch (array_pop($operStack)) {
|
||||
case '*':
|
||||
array_push($numStack, array_pop($numStack) * $num);
|
||||
break;
|
||||
case '/':
|
||||
array_push($numStack, array_pop($numStack) / $num);
|
||||
break;
|
||||
case '+':
|
||||
array_push($numStack, array_pop($numStack) + $num);
|
||||
break;
|
||||
case '-':
|
||||
array_push($numStack, array_pop($numStack) - $num);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
expression('-1+2-(1+2*3)');
|
||||
echo PHP_EOL;
|
||||
eval('echo -1+2-(1+2*3);');
|
@ -6,7 +6,8 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Algo_06\\": "06_linkedlist/",
|
||||
"Algo_07\\": "07_linkedlist/"
|
||||
"Algo_07\\": "07_linkedlist/",
|
||||
"Algo_08\\": "08_stack/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
51
python/09_queue/dynamic_array_queue.py
Normal file
51
python/09_queue/dynamic_array_queue.py
Normal file
@ -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)
|
58
python/09_queue/linked_queue.py
Normal file
58
python/09_queue/linked_queue.py
Normal file
@ -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)
|
77
swift/05_array/MyArray.swift
Normal file
77
swift/05_array/MyArray.swift
Normal file
@ -0,0 +1,77 @@
|
||||
//
|
||||
// Created by Jiandan on 2018/10/10.
|
||||
// Copyright (c) 2018 Jiandan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// <Element> Swift 泛型,此数组支持不同数据类型
|
||||
public struct MyArray<Element> {
|
||||
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)")
|
||||
}
|
||||
}
|
112
swift/09_queue/ArrayQueue.swift
Normal file
112
swift/09_queue/ArrayQueue.swift
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// Created by Jiandan on 2018/10/11.
|
||||
// Copyright (c) 2018 Jiandan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 用数组实现的队列
|
||||
struct ArrayQueue<T>: 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<T>: 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()
|
||||
}
|
||||
}
|
63
swift/09_queue/CircularQueue.swift
Normal file
63
swift/09_queue/CircularQueue.swift
Normal file
@ -0,0 +1,63 @@
|
||||
//
|
||||
// Created by Jiandan on 2018/10/11.
|
||||
// Copyright (c) 2018 Jiandan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 循环队列
|
||||
struct CircularQueue<T>: 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
|
||||
}
|
||||
}
|
21
swift/09_queue/Queue.swift
Normal file
21
swift/09_queue/Queue.swift
Normal file
@ -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?
|
||||
}
|
61
swift/09_queue/QueueBasedOnLinkedList.swift
Normal file
61
swift/09_queue/QueueBasedOnLinkedList.swift
Normal file
@ -0,0 +1,61 @@
|
||||
//
|
||||
// Created by Jiandan on 2018/10/11.
|
||||
// Copyright (c) 2018 Jiandan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class Node<T> {
|
||||
var value: T?
|
||||
var next: Node?
|
||||
|
||||
init(value: T) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
struct QueueBasedOnLinkedList<T>: Queue {
|
||||
typealias Element = T
|
||||
|
||||
/// 队首
|
||||
var head: Node<Element>?
|
||||
/// 队尾
|
||||
var tail: Node<Element>?
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user