diff --git a/.gitignore b/.gitignore index c456446b..fb159b51 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ hs_err_pid* # editor files .vscode .*.swp + +# WebStorm +.idea/ diff --git a/c-cpp/15_bsearch/bsearch_c/sqrt.c b/c-cpp/15_bsearch/bsearch_c/sqrt.c new file mode 100644 index 00000000..7c7c3d48 --- /dev/null +++ b/c-cpp/15_bsearch/bsearch_c/sqrt.c @@ -0,0 +1,53 @@ +/************************************************************************* + > File Name: sqrt.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-31 + > Desc: + ************************************************************************/ +#include +#include +#include +#include + + +/*求解精度设置*/ +#define E 0.000001 +double mybsearch(double num) +{ + double start = 1.0; + double end = num; + double mid = 0.0; + while(1) + { + mid = (start + end)/2; + if(((mid*mid - num) <= E) && ((mid*mid - num) >= -E)) + { + return mid; + } + + if ((mid*mid - num) > E) + { + end = mid; + } + else + { + start = mid; + } + } + + return 0; +} + + +int main() +{ + double num = 0.0; + + /*这里需要注意:double的输入方式*/ + scanf("%lf",&num); + printf("\r\n num %lf的平方根是%lf",num,mybsearch(num)); + + return 0; +} + diff --git a/c-cpp/16_bsearch/bsearch.c b/c-cpp/16_bsearch/bsearch.c new file mode 100644 index 00000000..17e06fd4 --- /dev/null +++ b/c-cpp/16_bsearch/bsearch.c @@ -0,0 +1,190 @@ +/************************************************************************* + > File Name: bsearch.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-21 + > Desc: + ************************************************************************/ +#include +#include +#include + +/*二分查找算法的变形问题 + *1、查找第一个等于给定数值的元素 + *2、查找最后一个等于给定数值的元素 + *3、查找第一个大于等于给定数值的元素 + *4、查找第一个小于等于给定数值的元素 + * */ + + + /*1、查找第一个等于给定数值的元素*/ +int mybsearch_1(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] < value) + { + left = mid + 1; + } + else if (a[mid] > value) + { + right = mid - 1; + } + else + { + if ((mid == 0) || (a[mid - 1] != value)) + { + return mid; + } + else + { + right = mid - 1; + } + } + } + + return -1; +} + + /*2、查找最后一个等于给定数值的元素*/ +int mybsearch_2(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] < value) + { + left = mid + 1; + } + else if (a[mid] > value) + { + right = mid - 1; + } + else + { + if ((mid == (size - 1)) || (a[mid + 1] != value)) + { + return mid; + } + else + { + left = mid + 1; + } + } + } + + return -1; +} + /*3、查找第一个大于等于给定数值的元素*/ +int mybsearch_3(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] < value) + { + left = mid + 1; + } + else + { + /*a[mid] >= value 当mid==0 或者a[mid-1] > value 说明是第一个大于等于value*/ + if ((mid == 0) || (a[mid - 1] < value)) + { + return mid; + } + else + { + right = mid - 1; + } + } + } + + return -1; +} + + /*4、查找第一个小于等于给定数值的元素*/ +int mybsearch_4(int a[],int size,int value) +{ + int mid = 0; + int left = 0; + int right = size - 1; + + while(left <= right) + { + /*防止size数量太大是,(left + right)数据翻转,导致问题*/ + mid = left + ((right - left)>>1); + + if (a[mid] > value) + { + right = mid - 1; + } + else + { + /*a[mid] <= value 时,当前mid == size -1 数组中最大的数值; + * 或者a[mid + 1] 大于vlaue,就是mid就第一个小于等于value*/ + if ((mid == (size - 1)) || (a[mid + 1] > value)) + { + return mid; + } + else + { + left = mid + 1; + } + } + } + + return -1; +} +int main() +{ + int a[10] = {5,6,6,9,10,11,11,22,33,33}; + int data = 0; + int i = 0; + int res =0; + + printf("\r\n"); + for(i = 0; i < 10 ; i++) + { + printf("%d ",a[i]); + } + printf("\r\n"); + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_1(a,10,data); + printf("第一个等于data[%d],下标是%d",data,res); + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_2(a,10,data); + printf("最后一个等于data[%d],下标是%d",data,res); + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_2(a,10,data); + printf("第一个大于等于data[%d],下标是%d",data,res); + + printf("\r\n输入一个整数"); + scanf("%d",&data); + res = mybsearch_2(a,10,data); + printf("第一个小等于data[%d],下标是%d",data,res); + return; +} diff --git a/c-cpp/17_skiplist/SkipList.cpp b/c-cpp/17_skiplist/SkipList.cpp new file mode 100644 index 00000000..ffef260b --- /dev/null +++ b/c-cpp/17_skiplist/SkipList.cpp @@ -0,0 +1,363 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +/** + * һʵַ + * д洢Ҵ洢Dzظġ + * + * C++汾. + * JAVA汾 ԭ AuthorZHENG + * + * Authorpuhuaqiang + * + * ṹ: + * + * K 1 9 + * K-1 1 5 9 + * K-2 1 3 5 7 9 + * ... .... + * 0(ԭʼ) 1 2 3 4 5 6 7 8 9 + */ + +const int MAX_LEVEL = 16; + +/** + * @brief ڵ +*/ +class CNode +{ +public: + CNode(); + ~CNode(); + + std::string toString(); + /** + * @brief ȡ + */ + CNode** GetIdxList(); + + /** + * @brief + */ + void SetData(int v); + /** + * @brief ȡ + */ + int GetData(); + /** + * @brief + */ + void SetLevel(int l); +private: + /**ǰڵֵ*/ + int m_data; + /** + * ǰڵÿȼһڵ. + * 2 N1 N2 + * 1 N1 N2 + * N1DZڵ, m_lpForwards[x] N2 + * + * [0] ԭʼ. + */ + CNode* m_lpForwards[MAX_LEVEL]; + /**ǰڵڵ*/ + int m_iMaxLevel; +}; + +/** + * @brief +*/ +class CSkipList +{ +public: + CSkipList(); + ~CSkipList(); + /** + * @brief ֵָĽڵ + * @param v + */ + CNode* Find(int v); + /** + * @brief ֵָ + * @param v + */ + void Insert(int v); + /** + * @brief ɾֵָĽڵ + * @param v + */ + int Delete(int v); + void PrintAll(); + /** + * @brief ӡṹ + * @param l -1ʱӡмĽṹ >=0ʱӡָĽṹ + */ + void PrintAll(int l); + /** + * @brief ڵʱ,õK + * @return K + */ + int RandomLevel(); + +private: + int levelCount; + /** + * + * ͷ/(ڵ) + */ + CNode* m_lpHead; +}; + +int main() +{ + CSkipList skipList; + /// ԭʼֵ + for(int i=1; i< 50; i++){ + if((i%3) == 0){ + skipList.Insert(i); + } + } + for(int i=1; i< 50; i++){ + if((i%3) == 1){ + skipList.Insert(i); + } + } + skipList.PrintAll(); + std::cout<GetData()< k-1 -> k-2 ...->0 + */ + for(int i=levelCount-1; i>=0; --i){ + /** + * СvĽڵ(lpNode). + */ + while((NULL != lpNode->GetIdxList()[i]) && (lpNode->GetIdxList()[i]->GetData() < v)){ + lpNode = lpNode->GetIdxList()[i]; + } + } + /** + * lpNode СvĽڵ, lpNodeһڵ͵ڻvĽڵ + */ + if((NULL != lpNode->GetIdxList()[0]) && (lpNode->GetIdxList()[0]->GetData() == v)){ + return lpNode->GetIdxList()[0]; + } + return NULL; +} +void CSkipList::Insert(int v) +{ + /// ½ڵ + CNode* lpNewNode = new CNode(); + if(NULL == lpNewNode){ + return; + } + + /** + * ½ڵֲڵ + * 3, µĽڵ123ϵ + */ + int level = RandomLevel(); + lpNewNode->SetData(v); + lpNewNode->SetLevel(level); + + /** + * ʱ + * ҪǵõµĽڵÿϵλ + */ + CNode *lpUpdateNode[level]; + for(int i=0; i= 0; --i){ + /** + * λ + * eg. 1 1 7 10 + * 6 + * lpFind->GetIdxList()[i]->GetData() : ʾڵlpFindڵ1һڵ + * "lpFind->GetIdxList()[i]->GetData() < v"ʱ, + * ½ڵҪ뵽 lpFindڵĺ, lpFind->GetIdxList()[i] ڵǰ + * lpFind1 lpFind->GetIdxList()[i] 7 + */ + while((NULL != lpFind->GetIdxList()[i]) && (lpFind->GetIdxList()[i]->GetData() < v)){ + lpFind = lpFind->GetIdxList()[i]; + } + /// lpFind ½ڵ iĺһڵ + lpUpdateNode[i] = lpFind; + } + + for(int i=0; iGetIdxList()[i]ڵ7 + * + * 2 6 17֮ + */ + lpNewNode->GetIdxList()[i] = lpUpdateNode[i]->GetIdxList()[i]; + lpUpdateNode[i]->GetIdxList()[i] = lpNewNode; + } + if(levelCount < level){ + levelCount = level; + } +} +int CSkipList::Delete(int v) +{ + int ret = -1; + CNode *lpUpdateNode[levelCount]; + CNode *lpFind = m_lpHead; + for(int i=levelCount-1; i>= 0; --i){ + /** + * СvĽڵ(lpFind). + */ + while((NULL != lpFind->GetIdxList()[i]) && (lpFind->GetIdxList()[i]->GetData() < v)){ + lpFind = lpFind->GetIdxList()[i]; + } + lpUpdateNode[i] = lpFind; + } + /** + * lpFind СvĽڵ, lpFindһڵ͵ڻvĽڵ + */ + if((NULL != lpFind->GetIdxList()[0]) && (lpFind->GetIdxList()[0]->GetData() == v)){ + for(int i=levelCount-1; i>=0; --i){ + if((NULL != lpUpdateNode[i]->GetIdxList()[i]) && (v == lpUpdateNode[i]->GetIdxList()[i]->GetData())){ + lpUpdateNode[i]->GetIdxList()[i] = lpUpdateNode[i]->GetIdxList()[i]->GetIdxList()[i]; + ret = 0; + } + } + } + return ret; +} +void CSkipList::PrintAll() +{ + CNode* lpNode = m_lpHead; + while(NULL != lpNode->GetIdxList()[0]){ + std::cout<GetIdxList()[0]->toString().data()<GetIdxList()[0]; + } +} +void CSkipList::PrintAll(int l) +{ + for(int i=MAX_LEVEL-1; i>=0;--i){ + CNode* lpNode = m_lpHead; + std::cout<<""<= 0) && (l == i))){ + while(NULL != lpNode->GetIdxList()[i]){ + std::cout<GetIdxList()[i]->GetData()<<" "; + lpNode = lpNode->GetIdxList()[i]; + } + std::cout<= 0){ + break; + } + } + } +} +int GetRandom() +{ + static int _count = 1; + std::default_random_engine generator(time(0) + _count); + std::uniform_int_distribution distribution(1,99999/*0x7FFFFFFF*/); + int dice_roll = distribution(generator); + _count += 100; + return dice_roll; +} +int CSkipList::RandomLevel() +{ + int level = 1; + for(int i=1; i +#include +#include +#include +#include + +// https://www.youtube.com/watch?v=2g9OSRKJuzM&t=17s + +#define MAX_LEVEL 15 + +struct node { + int val; + int max_level; + struct node *forward[MAX_LEVEL]; +}; + +struct skip_list { + struct node head; + int max_level; + int max_level_nodes; +}; + +void node_init(struct node* node) +{ + memset(node, 0, sizeof(struct node)); +} + +void skip_list_init(struct skip_list* sl) +{ + node_init(&sl->head); + sl->max_level = 0; + sl->max_level_nodes = 0; +} + +void random_init() +{ + static bool done = false; + + if (done) + return; + + srandom(time(NULL)); + done = true; +} + +int random_level(void) +{ + int i, level = 1; + + random_init(); + + for (i = 1; i < MAX_LEVEL; i++) + if (random() % 2 == 1) + level++; + + return level; +} + +void random_level_test() +{ + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); + printf("random level %d\n", random_level()); +} + +void insert(struct skip_list *sl, int val) +{ + int level = random_level(); + struct node *update[MAX_LEVEL]; + struct node *new, *p; + int i; + + new = (struct node*)malloc(sizeof(struct node)); + if (!new) + return; + + new->max_level = level; + new->val = val; + + for (int i = 0; i < MAX_LEVEL; i++) + update[i] = &sl->head; + + p = &sl->head; + for (i = level - 1; i >= 0; i--) { + while(p->forward[i] && p->forward[i]->val < val) + p = p->forward[i]; + + update[i] = p; + } + + for (i = 0; i < level; i++) { + new->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = new; + } + + if (sl->max_level < level) { + sl->max_level = level; + sl->max_level_nodes = 1; + } else if (sl->max_level == level) + sl->max_level_nodes++; +} + +struct node *find(struct skip_list* sl, int val) +{ + struct node *node = &sl->head; + int i; + + for (i = sl->max_level - 1; i >= 0; i--) { + while (node->forward[i] && node->forward[i]->val < val) + node = node->forward[i]; + } + + if (node->forward[0] && node->forward[0]->val == val) { + return node->forward[0]; + } + else + return NULL; +} + +void delete(struct skip_list* sl, int val) +{ + struct node *update[MAX_LEVEL]; + struct node *p; + int i; + + p = &sl->head; + + for (i = sl->max_level; i >= 0; i--) { + while (p->forward[i] && p->forward[i]->val < val) + p = p->forward[i]; + + update[i] = p; + } + + if (p->forward[0] == NULL || p->forward[0]->val != val) + return; + + if (p->forward[0]->max_level == sl->max_level) + sl->max_level_nodes--; + + for (i = sl->max_level-1; i >= 0; i--) { + if (update[i]->forward[i] && update[i]->forward[i]->val == val) + update[i]->forward[i] = update[i]->forward[i]->forward[i]; + } + + // fixup max_level and max_level_nodes + if (sl->max_level_nodes == 0) { + //sl->max_level--; + p = &sl->head; + // skip (max_level - 1), direct test (max_level - 2) + // since no nodes on (max_level - 1) + for (i = sl->max_level - 2; i >= 0; i--) { + while (p->forward[i]) { + sl->max_level_nodes++; + p = p->forward[i]; + } + + if (sl->max_level_nodes) { + sl->max_level = i + 1; + break; + } else + sl->max_level = i; + } + } +} + + +void print_sl(struct skip_list* sl) +{ + struct node *node; + int level; + + printf("%d level skip list with %d nodes on top\n", + sl->max_level, sl->max_level_nodes); + + for (level = sl->max_level - 1; level >= 0; level--) { + node = &sl->head; + printf("Level[%02d]:", level); + while (node->forward[level]) { + printf("%4d", node->forward[level]->val); + node = node->forward[level]; + } + printf("\n"); + } +} + +int main() +{ + struct skip_list sl; + struct node *node = NULL; + int i; + + skip_list_init(&sl); + print_sl(&sl); + + for (i = 0; i < 10; i++) + insert(&sl, i); + print_sl(&sl); + + node = find(&sl, 8); + if (node) + printf("find 8 in sl %d\n", node->val); + else + printf("8 not in sl\n"); + + for (i = 0; i < 10; i++) { + delete(&sl, i); + print_sl(&sl); + } + + return 0; +} diff --git a/c-cpp/17_skiplist/skiplist_c/skiplist.c b/c-cpp/17_skiplist/skiplist_c/skiplist.c new file mode 100644 index 00000000..843d575e --- /dev/null +++ b/c-cpp/17_skiplist/skiplist_c/skiplist.c @@ -0,0 +1,346 @@ +/************************************************************************* + > File Name: skiplist.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-31 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include"./skiplist.h" + + +/*创建node节点*/ +node* skip_list_create_node(int level,int key,int value) +{ + node * tmp = NULL; + + tmp =(node *)malloc(sizeof(node) + level*sizeof(node *)); + assert(tmp != NULL); + + memset(tmp,0,sizeof(node) + level*sizeof(node*)); + tmp->key = key; + tmp->value = value; + tmp->max_level = level; + + return tmp; +} + +/*创建跳表的表头,max_level层数*/ +skiplist * skip_list_create(int max_level) +{ + int i = 0; + skiplist * list = NULL; + + list = (skiplist *)malloc (sizeof(skiplist)); + assert(list != NULL); + + list->level = 1; + list->count = 0; + + list->head = skip_list_create_node(max_level,0,0); + if(list->head == NULL) + { + + free(list); + return NULL; + } + + return list; +} + +/*skiplist 销毁*/ +void skip_list_destory(skiplist * list) +{ + int i = 0; + node * tmp = NULL; + + if((list == NULL) || (list->head == NULL)) + { + return; + } + while(list->head->next[0] != NULL) + { + tmp = list->head->next[0]; + list->head->next[0] = tmp->next[0]; + free(tmp); + } + + free(list->head); + free(list); + return; +} + +/*插入元素获得层数,是随机产生的*/ +int skip_list_level(skiplist * list) +{ + int i = 0; + int level = 1; + for (i = 1; i < list->head->max_level; i++) + { + if ((rand()%2) == 1) + { + level++; + } + } + + return level; +} +int skip_list_insert(skiplist *list,int key,int value) +{ + int i = 0; + int level = 0; + node **update = NULL;/*用来更新每层的指针*/ + node *tmp = NULL; + node *prev = NULL; + + if (list == NULL) + { + return 1; + } + + /*申请update空间用于保存每层的指针*/ + update = (node **)malloc(sizeof(node *)*list->head->max_level); + if (update == NULL) + { + return 2; + } + + /*逐层查询节点的*/ + prev = list->head; + for (i = (list->level -1); i >= 0; i--) + { + /*初始化每level层的头指针*/ + while(((tmp = prev->next[i]) != NULL) && (tmp->key < key)) + { + prev = tmp; + } + update[i] = prev; + } + + /*当前key已经存在,返回错误*/ + if ((tmp!= NULL) && (tmp->key == key)) + { + return 3; + } + /*获取插入元素的随机层数,并更新跳表的最大层数*/ + level = skip_list_level(list); + /*创建当前数据节点*/ + tmp = skip_list_create_node(level,key,value); + if (tmp == NULL) + { + return 4; + } + + /*更新最大层数*/ + if (level > list->level) + { + for (i = list->level;i < level; i ++) + { + update[i] = list->head; + } + list->level = level; + } + + /*逐层更新节点的指针*/ + for(i = 0; i < level; i++) + { + tmp->next[i] = update[i]->next[i]; + update[i]->next[i] = tmp; + } + + list->count++; + return 0; +} + +int skip_list_delete(skiplist * list, int key ,int *value) +{ + int i = 0; + node **update = NULL;/*用来更新每层的指针*/ + node *tmp = NULL; + node *prev = NULL; + + if ((list == NULL) && (value == NULL)&& (list->count == 0)) + { + return 1; + } + /*申请update空间用于保存每层的指针*/ + update = (node **)malloc(sizeof(node *)*list->level); + if (update == NULL) + { + return 2; + } + /*逐层查询节点的*/ + prev = list->head; + for (i = (list->level -1); i >= 0; i--) + { + /*初始化每level层的头指针*/ + while(((tmp = prev->next[i]) != NULL) && (tmp->key < key)) + { + prev = tmp; + } + update[i] = prev; + } + + if ((tmp != NULL) + && (tmp->key == key)) + { + *value = tmp->value; + /*逐层删除*/ + for(i = 0; i < list->level; i++) + { + if(update[i]->next[i] == tmp) + { + update[i]->next[i] = tmp->next[i]; + } + } + + free(tmp); + tmp = NULL; + + /*更新level的层数*/ + for (i = list->level - 1; i >= 0; i++) + { + if (list->head->next[i] == NULL ) + { + list->level--; + } + else + { + break; + } + } + + list->count--; + + } + else + { + return 3;/*未找到节点*/ + } + + return 0 ; +} + +/*查询当前key是否在跳表中,如果存在返回查询的value数值,不存在返回-1*/ +int skip_list_search(skiplist *list,int key,int *value) +{ + int i = 0; + node *prev = NULL; + node *tmp = NULL; + + if((list == NULL) || (list->count == 0) || (value == NULL)) + { + return 1; + } + prev = list->head; + for(i = list->level - 1; i >= 0; i--) + { + while(((tmp = prev->next[i]) != NULL) && (tmp->key <= key)) + { + if (tmp->key == key) + { + *value = tmp->value; + return 0; + } + prev = tmp; + } + } + + return -1; +} + +void skip_list_dump(skiplist *list) +{ + int i = 0; + node *ptmp = NULL; + printf("\r\n----------------------------------------------"); + printf("\r\n skip list level[%d],count[%d]",list->level,list->count); + for(i = list->level - 1; i >= 0; i --) + { + ptmp = list->head->next[i]; + printf("\r\n level[%d]:",i); + while(ptmp != NULL) + { + printf("%d-%d ",ptmp->key,ptmp->value); + ptmp = ptmp->next[i]; + } + } + printf("\r\n----------------------------------------------"); + return; +} + +int main() +{ + int res = 0; + int key = 0; + int value = 0; + skiplist *list = NULL; + + + list = skip_list_create(5); + assert(list != NULL); + + while(1) + { + printf("\r\n 请输入key 和 value,当key = 1000时,退出输入:"); + scanf("%d%d",&key,&value); + if (key == 1000) + { + break; + } + res = skip_list_insert(list,key,value); + if (res != 0) + { + printf("\r\n skip list insert %d,failed,res=%d.",key,res); + } + } + skip_list_dump(list); + + while(1) + { + printf("\r\n 通过key 查询value的数值,当key = 1000时,退出查询"); + scanf("%d",&key); + if(key == 1000) + { + break; + } + res = skip_list_search(list,key,&value); + if (res != 0) + { + printf("\r\n skip list search %d,failed,res=%d.",key,res); + } + else + { + printf("\r\n skip list search %d,sucessful,value=%d.",key,value); + + } + } + skip_list_dump(list); + while(1) + { + printf("\r\n 通过key 删除节点,当key = 1000时,退出删除"); + scanf("%d",&key); + if(key == 1000) + { + break; + } + res = skip_list_delete(list,key,&value); + if (res != 0) + { + printf("\r\n skip list search %d,failed,res=%d.",key,res); + } + else + { + printf("\r\n skip list search %d,sucessful,value=%d.",key,value); + + } + } + + skip_list_dump(list); + skip_list_destory(list); + + return 0; +} diff --git a/c-cpp/17_skiplist/skiplist_c/skiplist.h b/c-cpp/17_skiplist/skiplist_c/skiplist.h new file mode 100644 index 00000000..217c9df0 --- /dev/null +++ b/c-cpp/17_skiplist/skiplist_c/skiplist.h @@ -0,0 +1,33 @@ +/************************************************************************* + > File Name: skiplist.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-31 + > Desc: + ************************************************************************/ +#ifndef __SKIP_LIST_H__ +#define __SKIP_LIST_H__ + + +typedef struct _node +{ + int key; /*key是唯一的*/ + int value; /*存储的内容*/ + int max_level; /*当前节点最大层数*/ + struct _node *next[0];/*level层链表结构*/ +}node; + +typedef struct _skiplist +{ + int level; + int count; + node *head; +}skiplist; + +/*根据当前结构体元素的地址,获取到结构体首地址*/ +#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container(ptr,type,member) ({\ + const typeof( ((type *)0)->member) *__mptr = (ptr);\ + (type *) ( (char *)__mptr - offsetof(type,member));}) + +#endif diff --git a/c-cpp/17_skiplist/skiplist_tr.hpp b/c-cpp/17_skiplist/skiplist_tr.hpp index 9ea72b23..8e931d7f 100644 --- a/c-cpp/17_skiplist/skiplist_tr.hpp +++ b/c-cpp/17_skiplist/skiplist_tr.hpp @@ -101,16 +101,13 @@ class skiplist { void init_internally() { const hash_type tail_key = std::numeric_limits::max(); node_type tail(tail_key); - tail.forwards.resize(max_lv_); - std::fill(tail.forwards.begin(), tail.forwards.end(), cont_.end()); - cont_.insert(cont_.begin(), std::move(tail)); + tail.forwards.resize(max_lv_, cont_.end()); + iterator tail_iter = cont_.insert(cont_.begin(), std::move(tail)); const hash_type head_key = std::numeric_limits::min(); node_type head(head_key); - head.forwards.resize(max_lv_); + head.forwards.resize(max_lv_, tail_iter); cont_.insert(cont_.begin(), std::move(head)); - std::fill(cont_.begin()->forwards.begin(), cont_.begin()->forwards.end(), - std::next(cont_.begin())); #ifdef LIAM_UT_DEBUG_ assert(cont_.begin()->key == head_key); @@ -363,4 +360,3 @@ class skiplist { }; #endif // SKIPLIST_SKIPLIST_TR_HPP_ - diff --git a/c-cpp/18_hash/listhash/listhash.c b/c-cpp/18_hash/listhash/listhash.c new file mode 100644 index 00000000..395590c9 --- /dev/null +++ b/c-cpp/18_hash/listhash/listhash.c @@ -0,0 +1,364 @@ +/************************************************************************* + > File Name: listhash.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-07 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include"listhash.h" + +#ifdef MEMORY_TEST +#include +#endif + +hashtab * hashtab_create(int size,hash_key_func hash_value, + keycmp_func keycmp,hash_node_free_func hash_node_free) +{ + hashtab * h = NULL; + int i = 0; + + if ((size < 0) || (hash_value == NULL) || (keycmp == NULL)) + { + return NULL; + } + + h = (hashtab *)malloc(sizeof(hashtab)); + if (h == NULL) + { + return NULL; + } + + h->htables = (hashtab_node **)malloc(size * sizeof(hashtab_node*)); + if (h->htables == NULL) + { + return NULL; + } + + h->size = size; + h->nel = 0; + h->hash_value = hash_value; + h->keycmp = keycmp; + h->hash_node_free = hash_node_free; + + for (i = 0; i < size; i++) + { + h->htables[i] = NULL; + } + + return h; +} + +void hashtab_destory(hashtab *h) +{ + int i = 0; + hashtab_node * cur = NULL; + hashtab_node * tmp = NULL; + + if (h == NULL) + { + return; + } + + for (i = 0; i size; i++) + { + cur = h->htables[i]; + while (cur != NULL) + { + tmp = cur; + cur = cur->next; + h->hash_node_free(tmp); + } + h->htables[i] = NULL; + } + + free(h->htables); + free(h); + return; +} + +int hashtab_insert(hashtab * h,void *key,void *data) +{ + unsigned int hvalue = 0; + int i = 0; + hashtab_node *cur = NULL; + hashtab_node *prev = NULL; + hashtab_node *newnode = NULL; + + if ((h == NULL) || (key == NULL) || (data == NULL)) + { + return 1; + } + + /*获取hash 数值*/ + hvalue = h->hash_value(h,key); + cur = h->htables[hvalue]; + + /*hash桶中元素是从小到大排列的,找到要插入的位置*/ + while((cur != NULL) && (h->keycmp(h,key,cur->key) > 0)) + { + prev = cur; + cur = cur->next; + } + + /*如果key和当前key比对一致,直接返回,数据已经存在*/ + if ((cur != NULL) && (h->keycmp(h,key,cur->key) == 0)) + { + return 2; + } + + newnode = (hashtab_node *)malloc(sizeof(hashtab_node)); + if (newnode == NULL) + { + return 3; + } + + newnode->key = key; + newnode->data = data; + if (prev == NULL) + { + newnode->next = h->htables[hvalue]; + h->htables[hvalue] = newnode; + } + else + { + newnode->next = prev->next; + prev->next = newnode; + } + + h->nel++; + return 0; +} + +hashtab_node *hashtab_delete(hashtab *h, void *key) +{ + int hvalue = 0; + int i = 0; + hashtab_node *cur = NULL; + hashtab_node *prev = NULL; + + if ((h == NULL) || (key == NULL)) + { + return NULL; + } + + /*获取hash 数值*/ + hvalue = h->hash_value(h,key); + cur = h->htables[hvalue]; + /*hash桶中元素是从小到大排列的,找到要插入的位置*/ + while((cur != NULL) && (h->keycmp(h,key,cur->key) >= 0)) + { + if (h->keycmp(h,key,cur->key) == 0) + { + if (prev == NULL) + { + h->htables[hvalue] = cur->next; + } + else + { + prev->next = cur->next; + } + return cur; + } + prev = cur; + cur = cur->next; + } + + return NULL; +} + +void *hashtab_search(hashtab*h,void *key) +{ + int hvalue = 0; + int i = 0; + hashtab_node *cur = NULL; + + if ((h == NULL) || (key == NULL)) + { + return NULL; + } + + /*获取hash 数值*/ + hvalue = h->hash_value(h,key); + cur = h->htables[hvalue]; + /*hash桶中元素是从小到大排列的,找到要插入的位置*/ + while((cur != NULL) && (h->keycmp(h,key,cur->key) >= 0)) + { + if (h->keycmp(h,key,cur->key) == 0) + { + return cur->data; + } + cur = cur->next; + } + + return NULL; +} + +void hashtab_dump(hashtab *h) +{ + int i = 0; + hashtab_node * cur = NULL; + + if (h == NULL) + { + return ; + } + + printf("\r\n----开始--size[%d],nel[%d]------------",h->size,h->nel); + for( i = 0; i < h->size; i ++) + { + printf("\r\n htables[%d]:",i); + cur = h->htables[i]; + while((cur != NULL)) + { + printf("key[%s],data[%s] ",cur->key,cur->data); + cur = cur->next; + } + } + + printf("\r\n----结束--size[%d],nel[%d]------------",h->size,h->nel); +} + +struct test_node +{ + char key[80]; + char data[80]; +}; + +unsigned int siample_hash(const char *str) +{ + register unsigned int hash = 0; + register unsigned int seed = 131; + + while(*str) + { + hash = hash*seed + *str++; + } + + return hash & (0x7FFFFFFF); +} + +int hashtab_hvalue(hashtab *h,const void *key) +{ + return (siample_hash(key) % h->size); +} + +int hashtab_keycmp(hashtab *h,const void *key1,const void *key2) +{ + return strcmp(key1,key2); +} + +void hashtab_node_free(hashtab_node*node) +{ + struct test_node * ptmp = NULL; + + ptmp = container(node->key,struct test_node,key); + + free(ptmp); + free(node); +} + +int main () +{ + + int i = 0; + int res = 0; + char *pres = NULL; + hashtab_node * node = NULL; + struct test_node *p = NULL; + hashtab *h = NULL; + #ifdef MEMORY_TEST + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + #endif + + h = hashtab_create(5,hashtab_hvalue,hashtab_keycmp,hashtab_node_free); + assert(h!= NULL); + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 和value,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + scanf("%s",p->data); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + + res = hashtab_insert(h,p->key,p->data); + if (res != 0) + { + free(p); + printf("\r\n key[%s],data[%s] insert failed %d",p->key,p->data,res); + } + else + { + printf("\r\n key[%s],data[%s] insert success %d",p->key,p->data,res); + } + } + + hashtab_dump(h); + + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 查询value的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + pres = hashtab_search(h,p->key); + if (pres == NULL) + { + printf("\r\n key[%s] search data failed",p->key); + } + else + { + printf("\r\n key[%s],search data[%s] success",p->key,pres); + } + free(p); + } + hashtab_dump(h); + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 删除节点的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + node = hashtab_delete(h,p->key); + if (node == NULL) + { + printf("\r\n key[%s] delete node failed ",p->key); + } + else + { + printf("\r\n key[%s],delete data[%s] success",node->key,node->data); + h->hash_node_free(node); + } + free(p); + hashtab_dump(h); + } + + hashtab_destory(h); + #ifdef MEMORY_TEST + muntrace(); + #endif + return 0; + +} diff --git a/c-cpp/18_hash/listhash/listhash.h b/c-cpp/18_hash/listhash/listhash.h new file mode 100755 index 00000000..2e42adab --- /dev/null +++ b/c-cpp/18_hash/listhash/listhash.h @@ -0,0 +1,53 @@ +/************************************************************************* + > File Name: listhash.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-06 + > Desc: 根据linux内核模块hashtab编写用户层hashtab接口 + linux-4.19.1\security\selinux\ss\hashtab.c + linux-4.19.1\security\selinux\ss\hashtab.h + ************************************************************************/ + + +#ifndef __HASHTAB_H__ +#define __HASHTAB_H__ + + +typedef struct _hashtab_node +{ + void * key; + void * data; + struct _hashtab_node *next; +}hashtab_node; + +typedef struct _hashtab +{ + hashtab_node **htables; /*哈希桶*/ + int size; /*哈希桶的最大数量*/ + int nel; /*哈希桶中元素的个数*/ + int (*hash_value)(struct _hashtab *h,const void *key); /*哈希函数*/ + int (*keycmp)(struct _hashtab *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ + void (*hash_node_free)(hashtab_node *node); +}hashtab; + + +#define HASHTAB_MAX_NODES (0xffffffff) + +typedef int (*hash_key_func)(struct _hashtab *h,const void *key); /*哈希函数*/ +typedef int (*keycmp_func)(struct _hashtab *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ +typedef void (*hash_node_free_func)(hashtab_node *node); +/*根据当前结构体元素的地址,获取到结构体首地址*/ +#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container(ptr,type,member) ({\ + const typeof( ((type *)0)->member) *__mptr = (ptr);\ + (type *) ( (char *)__mptr - offsetof(type,member));}) + + +hashtab * hashtab_create(int size,hash_key_func hash_value, + keycmp_func keycmp,hash_node_free_func hash_node_free); +void hashtab_destory(hashtab *h); +int hashtab_insert(hashtab * h,void *key,void *data); +hashtab_node *hashtab_delete(hashtab *h, void *key); +void *hashtab_search(hashtab*h,void *key); + +#endif diff --git a/c-cpp/18_hashtable/hashtable.c b/c-cpp/18_hashtable/hashtable.c new file mode 100644 index 00000000..03f7035a --- /dev/null +++ b/c-cpp/18_hashtable/hashtable.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include + +/* One implementation of hash table with linear probing. */ + +#define HASH_SHIFT 4 +#define HASH_SIZE (1 << HASH_SHIFT) +#define HASH_MASK (HASH_SIZE - 1) + +struct hash_table { + unsigned int used; + unsigned long entry[HASH_SIZE]; +}; + +void hash_table_reset(struct hash_table *table) +{ + int i; + + table->used = 0; + for (i = 0; i < HASH_SIZE; i++) + table->entry[i] = ~0; +} + +unsigned int hash_function(unsigned long value) +{ + return value & HASH_MASK; +} + +void dump_hash_table(struct hash_table *table) +{ + int i; + + for (i = 0; i < HASH_SIZE; i++) { + if (table->entry[i] == ~0) + printf("%2u: nil \n", i); + else + printf("%2u:%10lu -> %2u\n", + i, table->entry[i], + hash_function(table->entry[i])); + } +} + +void hash_function_test() +{ + int i; + + srandom(time(NULL)); + + for (i = 0; i < 10; i++) { + unsigned long val = random(); + printf("%10lu -> %2u\n", val, hash_function(val));; + } +} + +unsigned int next_probe(unsigned int prev_key) +{ + return (prev_key + 1) & HASH_MASK; +} + +void next_probe_test() +{ + int i; + unsigned int key1, key2; + + key1 = 0; + for (i = 0; i < HASH_SIZE; i++) { + key2 = next_probe(key1); + printf("%2u -> %2u\n", key1, key2); + key1 = key2; + } +} + +void hash_table_add(struct hash_table *table, unsigned long value) +{ + unsigned int key = hash_function(value); + + if (table->used >= HASH_SIZE) + return; + + while (table->entry[key] != ~0) + key = next_probe(key); + + table->entry[key] = value; + table->used++; +} + +unsigned int hash_table_slot(struct hash_table *table, unsigned long value) +{ + int i; + unsigned int key = hash_function(value); + + for (i = 0; i < HASH_SIZE; i++) { + if (table->entry[key] == value || table->entry[key] == ~0) + break; + key = next_probe(key); + } + + return key; +} + +bool hash_table_find(struct hash_table *table, unsigned long value) +{ + return table->entry[hash_table_slot(table, value)] == value; +} + +void hash_table_del(struct hash_table *table, unsigned long value) +{ + unsigned int i, j, k; + + if (!hash_table_find(table, value)) + return; + + i = j = hash_table_slot(table, value); + + while (true) { + table->entry[i] = ~0; + + do { + j = next_probe(j); + if (table->entry[j] == ~0) + return; + k = hash_function(table->entry[j]); + } while ((i <= j) ? (i < k && k <= j) : (i < k || k <= j)); + + table->entry[i] = table->entry[j]; + i = j; + } + table->used++; +} + +void hash_table_add_test() +{ + struct hash_table table; + + hash_table_reset(&table); + hash_table_add(&table, 87645); + + printf("Table has%s 87645\n", + hash_table_find(&table, 87645) ? "":"n't"); + printf("Table has%s 87647\n", + hash_table_find(&table, 87647) ? "":"n't"); +} + +void hash_table_del_test1() +{ + struct hash_table table; + + hash_table_reset(&table); + hash_table_add(&table, 0x1ff0); + hash_table_add(&table, 0x2ff0); + hash_table_add(&table, 0x3ff0); + dump_hash_table(&table); + + printf("=== Remove 0x1ff0\n"); + hash_table_del(&table, 0x1ff0); + dump_hash_table(&table); +} + +void hash_table_del_test2() +{ + struct hash_table table; + + hash_table_reset(&table); + hash_table_add(&table, 0x1ff0); + hash_table_add(&table, 0x1ff1); + hash_table_add(&table, 0x1ff2); + hash_table_add(&table, 0x2ff0); + dump_hash_table(&table); + + printf("=== Remove 0x1ff0\n"); + hash_table_del(&table, 0x1ff0); + dump_hash_table(&table); +} + +int main() +{ + //hash_function_test(); + //next_probe_test(); + //hash_table_add_test(); + hash_table_del_test2(); + + return 0; +} diff --git a/c-cpp/19_Dlisthash/Dlist.h b/c-cpp/19_Dlisthash/Dlist.h new file mode 100755 index 00000000..a95d2f3e --- /dev/null +++ b/c-cpp/19_Dlisthash/Dlist.h @@ -0,0 +1,114 @@ +/************************************************************************* + > File Name: Dlist.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-08 + > Desc: linux内核源码双向链表实现include/linux/list.h + ************************************************************************/ +#ifndef _LIST_HEAD_H +#define _LIST_HEAD_H + +// 双向链表节点 +struct list_head { + struct list_head *next, *prev; +}; + +// 初始化节点:设置name节点的前继节点和后继节点都是指向name本身。 +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +// 定义表头(节点):新建双向链表表头name,并设置name的前继节点和后继节点都是指向name本身。 +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +// 初始化节点:将list节点的前继节点和后继节点都是指向list本身。 +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +// 添加节点:将new插入到prev和next之间。 +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +// 添加new节点:将new添加到head之后,是new称为head的后继节点。 +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +// 添加new节点:将new添加到head之前,即将new添加到双链表的末尾。 +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +// 从双链表中删除entry节点。 +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +// 从双链表中删除entry节点。 +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +// 从双链表中删除entry节点。 +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +// 从双链表中删除entry节点,并将entry节点的前继节点和后继节点都指向entry本身。 +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +// 用new节点取代old节点 +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +// 双链表是否为空 +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +// 获取"MEMBER成员"在"结构体TYPE"中的位置偏移 +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +// 根据"结构体(type)变量"中的"域成员变量(member)的指针(ptr)"来获取指向整个结构体变量的指针 +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +// 遍历双向链表 +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#endif diff --git a/c-cpp/19_Dlisthash/LinkedHashMap.c b/c-cpp/19_Dlisthash/LinkedHashMap.c new file mode 100755 index 00000000..e1ec1828 --- /dev/null +++ b/c-cpp/19_Dlisthash/LinkedHashMap.c @@ -0,0 +1,398 @@ +/************************************************************************* + > File Name: LinkedHashMap.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-08 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include "Dlist.h" +#include "LinkedHashMap.h" + + +LinkedHashMap *LinkedHashMap_Create(int size,int nel_max, + hash_value_func hash_value,keycmp_func keycmp, + hash_node_free_func hash_node_free) +{ + int i = 0; + LinkedHashMap *h = NULL; + + if ((size <= 0) || (hash_value == NULL) || (keycmp == NULL)) + { + return NULL; + } + + h = (LinkedHashMap *)malloc(sizeof(LinkedHashMap)); + if (h == NULL) + { + return NULL; + } + + h->hTabs = (LiskedHashMapNode**)malloc(sizeof(LiskedHashMapNode*) *size); + if (h->hTabs == NULL) + { + return NULL; + } + h->size = size; + h->nel = 0; + h->nel_max = nel_max; + h->hash_value = hash_value; + h->keycmp = keycmp; + h->hash_node_free = hash_node_free; + + for (i = 0; i < size; i++) + { + h->hTabs[i] = NULL; + } + + INIT_LIST_HEAD(&(h->header)); + + return h; +} + +void LinkedHashMap_destory(LinkedHashMap *h) +{ + struct list_head * pos = NULL; + struct list_head * next = NULL; + LiskedHashMapNode * ptmp = NULL; + + if (h == NULL) + { + return; + } + + list_for_each_safe(pos,next,&h->header) + { + ptmp = container_of(pos,LiskedHashMapNode,Dlist_node); + /*从双向链表中删除*/ + list_del_init(pos); + if (h->hash_node_free != NULL) + { + h->hash_node_free(ptmp,1); + } + } + + free(h->hTabs); + free(h); + + return; +} + +int LinkedHashMap_insert(LinkedHashMap *h,void *key,void *data) +{ + int i = 0; + int hPos = 0; + struct list_head *pos = NULL; + LiskedHashMapNode *cur = NULL; + LiskedHashMapNode *prev = NULL; + + hPos = h->hash_value(h,key); + cur = h->hTabs[hPos]; + while((cur != NULL)&& (h->keycmp(h,key,cur->key) != 0)) + { + prev = cur; + cur = cur->next; + } + + if(cur == NULL) + { + /*链表节点满时,取表头节点,从当前哈希表和双向链表中都删除*/ + if(h->nel_max == h->nel) + { + cur = LinkedHashMap_delete(h,list_entry(h->header.next,LiskedHashMapNode,Dlist_node)->key); + + assert(cur != NULL); + /*释放节点key 和data的内容*/ + h->hash_node_free(cur,0); + } + else/*链表不满时,创建新的节点*/ + { + cur = (LiskedHashMapNode *)malloc(sizeof(LiskedHashMapNode)); + if (cur == NULL) + { + return 1; + + } + } + /*插入到hash桶中*/ + if(prev == NULL) + { + cur->next = h->hTabs[hPos]; + h->hTabs[hPos] = cur; + } + else + { + cur->next = prev->next; + prev->next= cur; + } + h->nel++; + } + else + { + /*从双向链表中删除*/ + list_del_init(&(cur->Dlist_node)); + /*只删除key 和data的内存*/ + h->hash_node_free(cur,0); + } + + /*赋值*/ + cur->key = key; + cur->data = data; + + + /*加的双向链表尾部*/ + list_add_tail(&(cur->Dlist_node),&(h->header)); + + return 0; +} + +LiskedHashMapNode * LinkedHashMap_delete(LinkedHashMap *h,void *key) +{ + int hPos = 0; + struct list_head *pos = NULL; + LiskedHashMapNode *cur = NULL; + LiskedHashMapNode *prev = NULL; + + /*查找当前节点*/ + hPos = h->hash_value(h,key); + cur = h->hTabs[hPos]; + while((cur != NULL)&& (h->keycmp(h,key,cur->key) != 0)) + { + prev = cur; + cur = cur->next; + } + + if (cur == NULL) + { + return NULL; + } + + /*从哈希桶中删除*/ + if(prev == NULL) + { + h->hTabs[hPos] = cur->next; + } + else + { + prev->next = cur->next; + } + + /*从双向链表中删除*/ + list_del_init(&(cur->Dlist_node)); + h->nel--; + + return cur; +} + +void *LinkedHashMap_search(LinkedHashMap *h,void *key) +{ + int hPos = 0; + LiskedHashMapNode *cur = NULL; + + /*查找当前节点*/ + hPos = h->hash_value(h,key); + cur = h->hTabs[hPos]; + while((cur != NULL)&& (h->keycmp(h,key,cur->key) != 0)) + { + cur = cur->next; + } + + if (cur == NULL) + { + return NULL; + } + + /*从双向链表中删除节点,加入尾部*/ + if (h->header.prev != &(cur->Dlist_node)) + { + list_del_init(&(cur->Dlist_node)); + list_add_tail(&(cur->Dlist_node),&(h->header)); + } + + return cur->data; +} + +void LinkedHashMap__dump(LinkedHashMap *h) +{ + int i = 0; + LiskedHashMapNode * cur = NULL; + struct list_head *pos = NULL; + + if (h == NULL) + { + return ; + } + + printf("\r\n----开始--size[%d],nel[%d]------------",h->size,h->nel); + for( i = 0; i < h->size; i ++) + { + printf("\r\n htables[%d]:",i); + cur = h->hTabs[i]; + while((cur != NULL)) + { + printf("key[%s],data[%s] ",cur->key,cur->data); + cur = cur->next; + } + } + + printf("\r\n--------------------------------------------------------\r\n"); + + list_for_each(pos,&(h->header)) + { + cur = list_entry(pos,LiskedHashMapNode,Dlist_node); + printf("key[%s] ",cur->key); + + } + + printf("\r\n----结束--size[%d],nel[%d]------------",h->size,h->nel); +} + + + + + +struct test_node +{ + char key[80]; + char data[80]; +}; + +unsigned int siample_hash(const char *str) +{ + register unsigned int hash = 0; + register unsigned int seed = 131; + + while(*str) + { + hash = hash*seed + *str++; + } + + return hash & (0x7FFFFFFF); +} + +int hashtab_hvalue(LinkedHashMap *h,const void *key) +{ + return (siample_hash(key) % h->size); +} + +int hashtab_keycmp(LinkedHashMap *h,const void *key1,const void *key2) +{ + return strcmp(key1,key2); +} + +void hashtab_node_free(LiskedHashMapNode *node,int flg) +{ + struct test_node * ptmp = NULL; + + ptmp = list_entry(node->key,struct test_node,key); + + free(ptmp); + if (flg) + { + free(node); + } +} + + +int main () +{ + + int i = 0; + int res = 0; + char *pres = NULL; + LiskedHashMapNode * node = NULL; + struct test_node *p = NULL; + LinkedHashMap *h = NULL; + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + + h = LinkedHashMap_Create(3,6,hashtab_hvalue,hashtab_keycmp,hashtab_node_free); + assert(h!= NULL); + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 和value,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + scanf("%s",p->data); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + + res = LinkedHashMap_insert(h,p->key,p->data); + if (res != 0) + { + free(p); + printf("\r\n key[%s],data[%s] insert failed %d",p->key,p->data,res); + } + else + { + printf("\r\n key[%s],data[%s] insert success %d",p->key,p->data,res); + } + LinkedHashMap__dump(h); + } + + + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 查询value的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + pres = LinkedHashMap_search(h,p->key); + if (pres == NULL) + { + printf("\r\n key[%s] search data failed",p->key); + } + else + { + printf("\r\n key[%s],search data[%s] success",p->key,pres); + } + free(p); + LinkedHashMap__dump(h); + } + + while(1) + { + p = (struct test_node*)malloc(sizeof(struct test_node)); + assert(p != NULL); + printf("\r\n 请输入key 删除节点的数值,当可以等于\"quit\"时退出"); + scanf("%s",p->key); + + if(strcmp(p->key,"quit") == 0) + { + free(p); + break; + } + node = LinkedHashMap_delete(h,p->key); + if (node == NULL) + { + printf("\r\n key[%s] delete node failed ",p->key); + } + else + { + printf("\r\n key[%s],delete data[%s] success",node->key,node->data); + h->hash_node_free(node,1); + } + free(p); + LinkedHashMap__dump(h); + } + + LinkedHashMap_destory(h); + muntrace(); + return 0; + +} + diff --git a/c-cpp/19_Dlisthash/LinkedHashMap.h b/c-cpp/19_Dlisthash/LinkedHashMap.h new file mode 100755 index 00000000..e61b8fcb --- /dev/null +++ b/c-cpp/19_Dlisthash/LinkedHashMap.h @@ -0,0 +1,40 @@ +/************************************************************************* + > File Name: LinkedHashMap.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-08 + > Desc: + ************************************************************************/ + + +#ifndef __LINKED_HASH_MAP__ +#define __LINKED_HASH_MAP__ + +/*数据存放节点*/ +typedef struct _lisked_hash_map_node +{ + void *key; /*键*/ + void *data; /*数据*/ZZ + struct _lisked_hash_map_node *next; /*哈希冲突时,用来挂接后续节点*/ + struct list_head Dlist_node;/*用来挂接双向链表*/ +}LiskedHashMapNode; + +typedef struct _lisked_hash_map +{ + LiskedHashMapNode **hTabs;/*哈希桶*/ + struct list_head header;/*双向循环链表头*/ + int size; /**/ + int nel_max; /*支持最大节点数*/ + int nel; /*当前节点数*/ + int (*hash_value)(struct _lisked_hash_map *h,const void *key); /*哈希函数*/ + int (*keycmp)(struct _lisked_hash_map *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ + void (*hash_node_free)(LiskedHashMapNode *node,int flg);/*用来释放节点内存*/ + +}LinkedHashMap; + +typedef int (*hash_value_func)(struct _lisked_hash_map *h,const void *key); /*哈希函数*/ +typedef int (*keycmp_func)(struct _lisked_hash_map *h,const void *key1,const void *key2);/*哈希key比较函数,当哈希数值一致时使用*/ +typedef void (*hash_node_free_func)(LiskedHashMapNode *node,int flg); + +LiskedHashMapNode * LinkedHashMap_delete(LinkedHashMap *h,void *key); +#endif diff --git a/c-cpp/23_binarytree/binarytree.c b/c-cpp/23_binarytree/binarytree.c new file mode 100644 index 00000000..4143cd17 --- /dev/null +++ b/c-cpp/23_binarytree/binarytree.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +/* Implement binary tree in array */ + +#define MAX_TREE_NODES (1 << 8) + +struct node { + int data; +}; + +struct binary_tree { + union { + unsigned long nodes; + struct node *n[MAX_TREE_NODES]; + }; +}; + +void init_binary_tree(struct binary_tree *tree) +{ + int i; + + for(i = 0; i < MAX_TREE_NODES; i++) { + tree->n[i] = NULL; + } +} + +struct node* create_node(int data) +{ + struct node* n; + + n = malloc(sizeof(struct node)); + + if (n) + n->data = data; + + return n; +} + +void fake_a_tree(struct binary_tree* tree) +{ + /* data is in ordered */ + int i, data[10] = {7, 4, 9, 2, 6, 8, 10, 1, 3, 5}; + + init_binary_tree(tree); + + /* root start at 1 */ + for (i = 0; i < 10; i++) + tree->n[i+1] = create_node(data[i]); + + tree->nodes = 10; +} + +void _in_order(struct binary_tree* tree, int index) +{ + if (!tree->n[index]) + return; + + /* left child at (index << 1) */ + _in_order(tree, index << 1); + + printf("[%2d]: %4d\n", index, tree->n[index]->data); + + /* right child at (index << 1) + 1 */ + _in_order(tree, (index << 1) + 1); +} + +void in_order(struct binary_tree* tree) +{ + _in_order(tree, 1); +} + +int main() +{ + struct binary_tree tree; + + fake_a_tree(&tree); + in_order(&tree); + return 0; +} diff --git a/c-cpp/23_binarytree/tree/binarytree.c b/c-cpp/23_binarytree/tree/binarytree.c new file mode 100644 index 00000000..8a5e66b9 --- /dev/null +++ b/c-cpp/23_binarytree/tree/binarytree.c @@ -0,0 +1,213 @@ +/************************************************************************* + > File Name: binarytree.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-12 + > Desc: + ************************************************************************/ +#include + +#include +#include +#include +#include"list_queue.h" + +typedef struct _treenode +{ + int data; + struct _treenode *lchild; + struct _treenode *rchild; +}Tnode,Tree; + +void binarytree_create(Tree **Root) +{ + int a = 0; + printf("\r\n输入节点数值((当输入为100时,当前节点创建完成))):"); + scanf("%d",&a); + + + if (a == 100) + { + *Root = NULL; + } + else + { + *Root = (Tnode *)malloc(sizeof(Tnode)); + if (*Root == NULL) + { + return; + } + + (*Root)->data = a; + printf("\r\n create %d 的左孩子:",a); + binarytree_create(&((*Root)->lchild)); + printf("\r\n create %d 的右孩子:",a); + binarytree_create(&((*Root)->rchild)); + } + + return ; +} + +void binarytree_destory(Tree *root) +{ + if (root == NULL) + { + return; + } + + binarytree_destory(root->lchild); + binarytree_destory(root->rchild); + free(root); +} + +/*先序遍历:根结点--》左子树---》右子树*/ +void binarytree_preorder(Tree *root) +{ + if (root == NULL) + { + return; + } + printf(" %d ",root->data); + binarytree_preorder(root->lchild); + binarytree_preorder(root->rchild); + return; +} +/*中序遍历:左子树--》跟节点---》右子树*/ +void binarytree_inorder(Tree *root) +{ + if (root == NULL) + { + return; + } + binarytree_inorder(root->lchild); + printf(" %d ",root->data); + binarytree_inorder(root->rchild); + return; +} +/*后序遍历:左子树---》右子树-》根节点*/ +void binarytree_postorder(Tree *root) +{ + if (root == NULL) + { + return; + } + binarytree_postorder(root->lchild); + binarytree_postorder(root->rchild); + printf(" %d ",root->data); + return; +} + +void binarytree_levelorder(Tree * root) +{ + list_queue *queue = NULL; + Tnode * node = NULL; + + if(root == NULL) + { + return; + } + + queue = list_queue_create(); + + /*根节点先入队*/ + list_queue_enqueue(queue,(void *)root); + + while(!list_queue_is_empty(queue)) + { + list_queue_dequeue(queue,(void *)&node); + printf(" %d ",node->data); + + if(node->lchild != NULL) + { + list_queue_enqueue(queue,(void *)node->lchild); + } + + if(node->rchild != NULL) + { + list_queue_enqueue(queue,(void *)node->rchild); + } + } + + free(queue); + +} +/*打印叶子节点*/ +void binarytree_printfleaf(Tree *root) +{ + if (root == NULL) + { + return; + } + + if ((root->lchild == NULL) && (root->rchild == NULL)) + { + printf(" %d ",root->data); + } + else + { + binarytree_printfleaf(root->lchild); + binarytree_printfleaf(root->rchild); + } +} +/*打印叶子的个数*/ +int binarytree_getleafnum(Tree*root) +{ + if (root == NULL) + { + return 0; + } + + if ((root->lchild == NULL) && (root->rchild == NULL)) + { + return 1; + } + + return binarytree_getleafnum(root->lchild) + binarytree_getleafnum(root->rchild); + +} +/*打印数的高度*/ +int binarytree_gethigh(Tree *root) +{ + int lhigh = 0; + int rhigh = 0; + + if (root == NULL) + { + return 0; + } + + lhigh = binarytree_gethigh(root->lchild); + rhigh = binarytree_gethigh(root->rchild); + + return ((lhigh > rhigh)?(lhigh + 1):(rhigh + 1)); +} + +int main() +{ + Tree *root = NULL; + + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + + printf("\r\n创建二叉树:"); + binarytree_create(&root); + printf("\r\n先序遍历二叉树:"); + binarytree_preorder(root); + printf("\r\n中序遍历二叉树:"); + binarytree_inorder(root); + printf("\r\n后序遍历二叉树:"); + binarytree_postorder(root); + printf("\r\n层次遍历二叉树:"); + binarytree_levelorder(root); + + printf("\r\n打印二叉树叶子节点:"); + binarytree_printfleaf(root); + printf("\r\n打印二叉树叶子节点个数:%d",binarytree_getleafnum(root)); + printf("\r\n打印二叉树高度:%d",binarytree_gethigh(root)); + + binarytree_destory(root); + + muntrace(); + return 0; +} + diff --git a/c-cpp/23_binarytree/tree/list_queue.c b/c-cpp/23_binarytree/tree/list_queue.c new file mode 100644 index 00000000..2dbc9f91 --- /dev/null +++ b/c-cpp/23_binarytree/tree/list_queue.c @@ -0,0 +1,85 @@ +/************************************************************************* + > File Name: list_queue.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-13 + > Desc: + ************************************************************************/ +#include +#include +#include +#include"./list_queue.h" + +/*创建队列头*/ +list_queue *list_queue_create() +{ + list_queue * queue = NULL; + + queue = (list_queue *)malloc(sizeof(list_queue)); + if(queue == NULL) + { + return NULL; + } + + queue->num = 0; + queue->head = NULL; + queue->tail = NULL; + + return queue; +} +int list_queue_enqueue(list_queue *queue,void *data) +{ + queue_node *ptmp = NULL; + + if(queue == NULL) + { + return -1; + } + + ptmp = (queue_node *)malloc(sizeof(queue_node)); + if (ptmp == NULL) + { + return -1; + } + + ptmp->data = data; + ptmp->next = NULL; + if (queue->head == NULL) + { + queue->head = ptmp; + } + else + { + queue->tail->next = ptmp; + + } + queue->tail = ptmp; + queue->num++; + + return 0; +} + +/*出队*/ +int list_queue_dequeue(list_queue *queue,void **data) +{ + queue_node * ptmp = NULL; + + if ((queue == NULL) || (data == NULL) || list_queue_is_empty(queue)) + { + return -1; + } + + *data = queue->head->data; + ptmp = queue->head; + queue->head = queue->head->next; + queue->num--; + + if (queue->head == NULL) + { + queue->tail = NULL; + } + + + free(ptmp); + return 0; +} diff --git a/c-cpp/23_binarytree/tree/list_queue.h b/c-cpp/23_binarytree/tree/list_queue.h new file mode 100644 index 00000000..a6991855 --- /dev/null +++ b/c-cpp/23_binarytree/tree/list_queue.h @@ -0,0 +1,30 @@ +/************************************************************************* + > File Name: list_queue.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-10-13 + > Desc: + ************************************************************************/ + +#ifndef LINK_LIST_QUEUE_H +#define LINK_LIST_QUEUE_H + +typedef struct _list_queue_node +{ + void *data; + struct _list_queue_node *next; +}queue_node; + +typedef struct _list_queue +{ + int num; + queue_node *head; + queue_node *tail; +}list_queue; + +#define list_queue_is_empty(queue) ((queue->num) == 0) +list_queue *list_queue_create(); +int list_queue_enqueue(list_queue *queue,void *data); +int list_queue_dequeue(list_queue *queue,void **data); + +#endif diff --git a/c-cpp/24_binarysearchtree/binarysearchtree.c b/c-cpp/24_binarysearchtree/binarysearchtree.c new file mode 100644 index 00000000..f069de39 --- /dev/null +++ b/c-cpp/24_binarysearchtree/binarysearchtree.c @@ -0,0 +1,322 @@ +/************************************************************************* + > File Name: binarysearchtree.c + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-12 + > Desc: + ************************************************************************/ +#include +#include +#include +#include +#include"binarysearchtree.h" + + +bstree *bstree_create(compare_fuc compare,destory_fuc destory) +{ + bstree *tree = NULL; + + tree = (bstree*)malloc(sizeof(bstree)); + if (tree == NULL) + { + return NULL; + } + + tree->size = 0; + tree->compare = compare; + tree->destory = destory; + tree->root = NULL; + return tree; +} + +bstree_node *bstree_search(bstree *tree,mytype data) +{ + bstree_node *node = NULL; + int res = 0; + + if ((tree == NULL) || (bstree_is_empty(tree))) + { + return NULL; + } + node = tree->root; + + while(node != NULL) + { + res = tree->compare(data,node->data); + if(res == 0) + { + return node; + } + else if (res > 0) + { + node = node->rchild; + } + else + { + node = node->lchild; + } + } + + return NULL; +} + +int bstree_insert(bstree * tree, mytype data) +{ + bstree_node *node = NULL; + bstree_node *tmp = NULL; + int res = 0; + + if (tree == NULL) + { + return -1; + } + + node = (bstree_node *)malloc(sizeof(bstree_node)); + if (node == NULL) + { + return -2; + } + + node->data = data; + node->lchild = NULL; + node->rchild = NULL; + + /*如果二叉树为空,直接挂到根节点*/ + if (bstree_is_empty(tree)) + { + tree->root = node; + tree->size++; + return 0; + } + + tmp = tree->root; + + while(tmp != NULL) + { + res = tree->compare(data,tmp->data); + if (res > 0) /*去右孩子查找*/ + { + if (tmp->rchild == NULL) + { + tmp->rchild = node; + tree->size++; + return 0; + } + tmp = tmp->rchild; + } + else /*去左孩子查找*/ + { + if(tmp->lchild == NULL) + { + tmp->lchild = node; + tree->size++; + return 0; + } + tmp = tmp->lchild; + } + } + + return -3; +} + +int bstree_delete(bstree *tree,mytype data) +{ + bstree_node *node = NULL;/*要删除的节点*/ + bstree_node *pnode = NULL;/*要删除节点的父节点*/ + bstree_node *minnode = NULL;/*要删除节点的父节点*/ + bstree_node *pminnode = NULL;/*要删除节点的父节点*/ + mytype tmp = 0; + int res = 0; + + if ((tree == NULL) || (bstree_is_empty(tree))) + { + return -1; + } + + node = tree->root; + while ((node != NULL) && ((res = tree->compare(data,node->data)) != 0)) + { + pnode = node; + if(res > 0) + { + node = node->rchild; + } + else + { + node = node->lchild; + } + } + /*说明要删除的节点不存在*/ + if (node == NULL) + { + return -2; + } + + /*1、如果要删除node有2个子节点,需要找到右子树的最小节点minnode, + * 更新minnode和node节点数据,这样minnode节点就是要删除的节点 + * 再更新node和pnode节点指向要删除的节点*/ + if ((node->lchild != NULL) && (node->rchild != NULL)) + { + minnode = node->rchild; + pminnode = node; + + while(minnode->lchild != NULL) + { + pminnode = minnode; + minnode = minnode->lchild; + } + + /*node 节点和minnode节点数据互换*/ + tmp = node->data; + node->data = minnode->data; + minnode->data = tmp; + /*更新要删除的节点和其父节点*/ + node = minnode; + pnode = pminnode; + } + + /*2、当前要删除的节点只有左孩子或者右孩子时,直接父节点的直向删除的节点*/ + if (node->lchild != NULL) + { + minnode = node->lchild; + } + else if (node->rchild != NULL) + { + minnode = node->rchild; + } + else + { + minnode = NULL; + } + + if (pnode == NULL)/*当要删除的时根节点时,*/ + { + tree->root = minnode; + } + else if (pnode->lchild == node) + { + pnode->lchild = minnode; + } + else + { + pnode->rchild = minnode; + } + tree->size--; + free (node); + + return 0; +} + +/*采用递归方式删除节点*/ +void bstree_destory_node(bstree *tree,bstree_node *root) +{ + if (root == NULL) + { + return; + } + + bstree_destory_node(tree,root->lchild); + bstree_destory_node(tree,root->rchild); + free(root); +} + +/*二叉搜索树销毁*/ +void bstree_destory(bstree *tree) +{ + bstree_destory_node(tree,tree->root); + free(tree); + return; +} + +/*中序遍历打印树节点*/ +void bstree_inorder_node(bstree_node *root) +{ + bstree_node *node = NULL; + if (root == NULL) + { + return; + } + + bstree_inorder_node(root->lchild); + printf(" %d ",root->data); + bstree_inorder_node(root->rchild); + return; +} + +void bstree_dump(bstree *tree) +{ + bstree_node *node = NULL; + if ((tree == NULL) || (bstree_is_empty(tree))) + { + printf("\r\n 当前树是空树"); + } + printf("\r\nSTART-----------------%d------------\r\n",tree->size); + bstree_inorder_node(tree->root); + printf("\r\nEND---------------------------------",tree->size); + +} + +int bstree_compare(mytype key1,mytype key2) +{ + if (key1 == key2) + { + return 0; + } + else if (key1 > key2) + { + return 1; + } + else + { + return -1; + } +} + +int main() +{ + bstree *tree = NULL; + bstree_node *node = NULL; + mytype data = 0; + int res = 0; + + setenv("MALLOC_TRACE","1.txt",1); + mtrace(); + + tree = bstree_create(bstree_compare,NULL); + assert(tree != NULL); + + while(1) + { + printf("\r\n插入一个数字,输入100时退出:"); + scanf("%d",&data); + if(data == 100)break; + res = bstree_insert(tree,data); + printf("\r\n %d 插入%s成功",data,(res != 0)?("不"):(" ")); + } + bstree_dump(tree); + + while(1) + { + printf("\r\n查询一个数字,输入100时退出:"); + scanf("%d",&data); + if(data == 100)break; + node = bstree_search(tree,data); + printf("\r\n %d %s存在树中",data,(node == NULL)?("不"):(" ")); + } + bstree_dump(tree); + while(1) + { + printf("\r\n删除一个数字,输入100时退出:"); + scanf("%d",&data); + if(data == 100)break; + res = bstree_delete(tree,data); + printf("\r\n %d 删除%s成功",data,(res != 0)?("不"):(" ")); + bstree_dump(tree); + } + + bstree_destory(tree); + + muntrace(); + + return 0; +} diff --git a/c-cpp/24_binarysearchtree/binarysearchtree.h b/c-cpp/24_binarysearchtree/binarysearchtree.h new file mode 100644 index 00000000..b4e06119 --- /dev/null +++ b/c-cpp/24_binarysearchtree/binarysearchtree.h @@ -0,0 +1,34 @@ +/************************************************************************* + > File Name: binarysearchtree.h + > Author: jinshaohui + > Mail: jinshaohui789@163.com + > Time: 18-11-12 + > Desc: + ************************************************************************/ +#ifndef __BINARY_SEARCH_TREE__ +#define __BINARY_SEARCH_TREE__ +typedef int mytype; + +typedef struct _bstree_node +{ + mytype data; + struct _bstree_node *lchild; + struct _bstree_node *rchild; +}bstree_node; + +typedef struct _bstree +{ + int size; + int (*compare)(mytype key1,mytype key2); + int (*destory)(mytype data); + bstree_node *root; +}bstree; + +typedef int (*compare_fuc)(mytype key1,mytype key2); +typedef int (*destory_fuc)(mytype data); + +#define bstree_is_empty(tree) (tree->size == 0) + +bstree *bstree_create(compare_fuc compare,destory_fuc destory); + +#endif diff --git a/c-cpp/24_binarysearchtree/bst.c b/c-cpp/24_binarysearchtree/bst.c new file mode 100644 index 00000000..7fdfd877 --- /dev/null +++ b/c-cpp/24_binarysearchtree/bst.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +enum child_dir { + left_child, + right_child, + root, +}; + +struct node { + unsigned long data; + struct node *left; + struct node *right; +}; + +struct root { + struct node *r; +}; + +void dump(struct node *node, int level, enum child_dir dir) +{ + if (!node) + return; + + dump(node->right, level + 1, right_child); + + if (dir == left_child) + printf("%*s\n", level*3, "|"); + + printf("%*s - %05lu\n", level*3, " ", node->data); + + if (dir == right_child) + printf("%*s\n", level*3, "|"); + + dump(node->left, level + 1, left_child); +} + +struct node* find(struct root *root, unsigned long data) +{ + struct node* n = root->r; + + while (n) { + if (n->data == data) + return n; + if (data < n->data) + n = n->left; + else + n = n->right; + } + + return NULL; +} + +struct node* new_node(unsigned long data) +{ + struct node *n; + + n = malloc(sizeof(struct node)); + + n->data = data; + n->left = n->right = NULL; + return n; +} + +void insert(struct root *root, struct node *new) +{ + struct node *parent; + + if (!root->r) { + root->r = new; + return; + } + + parent = root->r; + + while (true) { + /* Don't support duplicate data */ + if (new->data == parent->data) + break; + + if (new->data < parent->data) { + if (!parent->left) { + parent->left = new; + break; + } + parent = parent->left; + } else { + if (!parent->right) { + parent->right = new; + break; + } + parent = parent->right; + } + } +} + +struct node* delete(struct root *root, unsigned long data) +{ + struct node *n = root->r, **p = &root->r; + struct node *child; + + while (n && n->data != data) { + if (data < n->data) { + p = &n->left; + n = n->left; + } else { + p = &n->right; + n = n->right; + } + } + + if (!n) + return NULL; + + if (n->left && n->right) { + struct node *rn = n->right, **rp = &n->right; + + while (rn->left) { + rp = &rn->left; + rn = rn->left; + } + + n->data = rn->data; + n = rn; + p = rp; + } + + child = n->left ? n->left : n->right; + *p = child; + + return NULL; +} + +void insert_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + n = find(&tree, 18); + if (n && n->data == 18) + printf("Get 18\n"); + +} + +void delete_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + delete(&tree, 20); + printf("Delete 20\n"); + dump(tree.r, 0, root); + + delete(&tree, 9); + printf("Delete 9\n"); + dump(tree.r, 0, root); +} + +int main() +{ + //insert_test(); + delete_test(); + return 0; +} diff --git a/c-cpp/28_heap/heap.c b/c-cpp/28_heap/heap.c new file mode 100644 index 00000000..6bd872df --- /dev/null +++ b/c-cpp/28_heap/heap.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include + +/* Implement heap */ + +#define MAX_HEAP_SIZE (1 << 8) + +struct element { + int data; +}; + +struct heap { + union { + unsigned long elements; + struct element *elem[MAX_HEAP_SIZE]; + }; +}; + +void init_heap(struct heap *heap) +{ + int i; + + for(i = 0; i < MAX_HEAP_SIZE; i++) { + heap->elem[i] = NULL; + } +} + +void dump_heap(struct heap *heap, int index) +{ + struct element *elem; + int level; + + if (index > heap->elements) + return; + + elem = heap->elem[index]; + level = fls(index); + + dump_heap(heap, index * 2 + 1); + + if (!(index % 2) && index != 1) + printf("%*s\n", level*3, "|"); + + printf("%*s - %05d\n", level*3, " ", elem->data); + + if (index % 2 && index != 1) + printf("%*s\n", level*3, "|"); + + dump_heap(heap, index * 2); +} + +void dump(struct heap *heap, int elements) +{ + int i; + + for (i = 1; i <= elements; i++) + printf("[%02d]: %4d\n", i, heap->elem[i]->data); + +} + +struct element* create_element(int data) +{ + struct element *elem; + + elem = malloc(sizeof(struct element)); + + if (elem) + elem->data = data; + + return elem; +} + +void fake_a_heap(struct heap *heap) +{ + /* data is in ordered */ + int i, data[10] = {7, 4, 9, 2, 6, 8, 10, 1, 3, 5}; + + init_heap(heap); + + /* root start at 1 */ + for (i = 0; i < 10; i++) + heap->elem[i+1] = create_element(data[i]); + + heap->elements = 10; +} + +void swap(struct heap *heap, int i, int j) +{ + struct element *tmp; + + tmp = heap->elem[j]; + heap->elem[j] = heap->elem[i]; + heap->elem[i] = tmp; +} + +void heapify(struct heap *heap, int parent) +{ + struct element **elem = heap->elem; + int elements = heap->elements; + int left, right, max; + + while (true) { + left = parent * 2; + right = left + 1; + + max = parent; + if (left <= elements && elem[max]->data < elem[left]->data) + max = left; + if (right <= elements && elem[max]->data < elem[right]->data) + max = right; + + if (max == parent) + break; + + swap(heap, max, parent); + parent = max; + } +} + +void build_heap(struct heap *heap) +{ + int i; + + for (i = heap->elements / 2; i >= 1; i--) + heapify(heap, i); +} + +int heap_sort(struct heap *heap) +{ + int elements = heap->elements; + + while (heap->elements) { + swap(heap, 1, heap->elements); + heap->elements--; + heapify(heap, 1); + } + + return elements; +} + +int main() +{ + struct heap heap; + int elements; + + fake_a_heap(&heap); + dump_heap(&heap, 1); + + printf("After Heapify:\n"); + build_heap(&heap); + dump_heap(&heap, 1); + + printf("After Heap sort:\n"); + elements = heap_sort(&heap); + dump(&heap, elements); + return 0; +} diff --git a/c-cpp/30_Graph/graph.c b/c-cpp/30_Graph/graph.c new file mode 100644 index 00000000..0f00c7b6 --- /dev/null +++ b/c-cpp/30_Graph/graph.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include + +struct vertex; +struct vertex_adjs { + struct vertex *v; + struct vertex_adjs *next; +}; + +struct vertex { + int data; + struct vertex_adjs *adj; +}; + +#define MAX_GRAPH_VERTEX (1 << 8) +struct graph { + struct vertex *vxs[MAX_GRAPH_VERTEX]; +}; + +void init_graph(struct graph *graph) +{ + int i; + + for (i = 0; i < MAX_GRAPH_VERTEX; i++) + graph->vxs[i] = NULL; +} + +struct vertex *create_vertex(int data) +{ + struct vertex *v; + + v = malloc(sizeof(struct vertex)); + + if (v) { + v->data = data; + v->adj = NULL; + } + + return v; +} + +struct vertex_adjs *create_vertex_adj(struct vertex *v) +{ + struct vertex_adjs *v_adj; + + v_adj = malloc(sizeof(struct vertex_adjs)); + + if (!v_adj) + return NULL; + + v_adj->v = v; + v_adj->next = NULL; + return v_adj; +} + +void insert_adj(struct vertex *v, struct vertex *adj) +{ + struct vertex_adjs **v_adj; + + v_adj = &v->adj; + + while (*v_adj) + v_adj = &(*v_adj)->next; + + *v_adj = create_vertex_adj(adj); +} + +void dump_raw(struct graph *graph) +{ + int i; + + for (i = 0; i < MAX_GRAPH_VERTEX; i++) { + struct vertex *v = graph->vxs[i]; + struct vertex_adjs *adj; + if (v == NULL) + continue; + + printf("Vertex[%02d]: %8d ->", i, v->data); + + adj = v->adj; + while (adj) { + printf(" %8d,", adj->v->data); + adj = adj->next; + } + printf("\n"); + } +} + +/* + 1 ----- 2 ----- 3 + | / | / + | / | / + | / | / + | / | / + | / | / + 4 ----- 5 +*/ +void fake_a_graph(struct graph *graph) +{ + int i; + + init_graph(graph); + + for (i = 0; i < 5; i++) + graph->vxs[i] = create_vertex(i+1); + + /* connect 1 -> 2, 1 -> 4 */ + insert_adj(graph->vxs[0], graph->vxs[1]); + insert_adj(graph->vxs[0], graph->vxs[3]); + /* connect 2 -> 1, 2 -> 3, 2 -> 5, 2 -> 4 */ + insert_adj(graph->vxs[1], graph->vxs[0]); + insert_adj(graph->vxs[1], graph->vxs[2]); + insert_adj(graph->vxs[1], graph->vxs[4]); + insert_adj(graph->vxs[1], graph->vxs[3]); + /* connect 3 -> 2, 3 -> 5 */ + insert_adj(graph->vxs[2], graph->vxs[1]); + insert_adj(graph->vxs[2], graph->vxs[4]); + /* connect 4 -> 1, 4 -> 2, 4 -> 5 */ + insert_adj(graph->vxs[3], graph->vxs[0]); + insert_adj(graph->vxs[3], graph->vxs[1]); + insert_adj(graph->vxs[3], graph->vxs[4]); + /* connect 5 -> 4, 5 -> 2, 5 -> 3 */ + insert_adj(graph->vxs[4], graph->vxs[3]); + insert_adj(graph->vxs[4], graph->vxs[1]); + insert_adj(graph->vxs[4], graph->vxs[3]); +} + +int main() +{ + struct graph g; + + fake_a_graph(&g); + dump_raw(&g); + return 0; +} diff --git a/c-cpp/bst.c b/c-cpp/bst.c new file mode 100644 index 00000000..7fdfd877 --- /dev/null +++ b/c-cpp/bst.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +enum child_dir { + left_child, + right_child, + root, +}; + +struct node { + unsigned long data; + struct node *left; + struct node *right; +}; + +struct root { + struct node *r; +}; + +void dump(struct node *node, int level, enum child_dir dir) +{ + if (!node) + return; + + dump(node->right, level + 1, right_child); + + if (dir == left_child) + printf("%*s\n", level*3, "|"); + + printf("%*s - %05lu\n", level*3, " ", node->data); + + if (dir == right_child) + printf("%*s\n", level*3, "|"); + + dump(node->left, level + 1, left_child); +} + +struct node* find(struct root *root, unsigned long data) +{ + struct node* n = root->r; + + while (n) { + if (n->data == data) + return n; + if (data < n->data) + n = n->left; + else + n = n->right; + } + + return NULL; +} + +struct node* new_node(unsigned long data) +{ + struct node *n; + + n = malloc(sizeof(struct node)); + + n->data = data; + n->left = n->right = NULL; + return n; +} + +void insert(struct root *root, struct node *new) +{ + struct node *parent; + + if (!root->r) { + root->r = new; + return; + } + + parent = root->r; + + while (true) { + /* Don't support duplicate data */ + if (new->data == parent->data) + break; + + if (new->data < parent->data) { + if (!parent->left) { + parent->left = new; + break; + } + parent = parent->left; + } else { + if (!parent->right) { + parent->right = new; + break; + } + parent = parent->right; + } + } +} + +struct node* delete(struct root *root, unsigned long data) +{ + struct node *n = root->r, **p = &root->r; + struct node *child; + + while (n && n->data != data) { + if (data < n->data) { + p = &n->left; + n = n->left; + } else { + p = &n->right; + n = n->right; + } + } + + if (!n) + return NULL; + + if (n->left && n->right) { + struct node *rn = n->right, **rp = &n->right; + + while (rn->left) { + rp = &rn->left; + rn = rn->left; + } + + n->data = rn->data; + n = rn; + p = rp; + } + + child = n->left ? n->left : n->right; + *p = child; + + return NULL; +} + +void insert_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + n = find(&tree, 18); + if (n && n->data == 18) + printf("Get 18\n"); + +} + +void delete_test() +{ + struct root tree; + struct node* n; + + tree.r = NULL; + + insert(&tree, new_node(9)); + + insert(&tree, new_node(5)); + insert(&tree, new_node(2)); + insert(&tree, new_node(8)); + + insert(&tree, new_node(18)); + insert(&tree, new_node(13)); + insert(&tree, new_node(21)); + insert(&tree, new_node(20)); + + dump(tree.r, 0, root); + + delete(&tree, 20); + printf("Delete 20\n"); + dump(tree.r, 0, root); + + delete(&tree, 9); + printf("Delete 9\n"); + dump(tree.r, 0, root); +} + +int main() +{ + //insert_test(); + delete_test(); + return 0; +} diff --git a/go/05_array/array.go b/go/05_array/array.go index ce2e05a4..c1a861d3 100644 --- a/go/05_array/array.go +++ b/go/05_array/array.go @@ -34,7 +34,7 @@ func (this *Array) Len() uint { //判断索引是否越界 func (this *Array) isIndexOutOfRange(index uint) bool { - if index >= this.length { + if index >= uint(cap(this.data)) { return true } return false diff --git a/go/24_tree/BinarySearchTree.go b/go/24_tree/BinarySearchTree.go new file mode 100644 index 00000000..0e39e35c --- /dev/null +++ b/go/24_tree/BinarySearchTree.go @@ -0,0 +1,145 @@ +package _4_tree + +type BST struct { + *BinaryTree + //比对函数,0:v==nodeV,正数:v>nodeV,负数:v 0 { //v > nodeV + p = p.right + } else { //v < nodeV + p = p.left + } + } + return nil +} + +func (this *BST) Insert(v interface{}) bool { + p := this.root + for nil != p { + compareResult := this.compareFunc(v, p.data) + if compareResult == 0 { + return false + } else if compareResult > 0 { + if nil == p.right { + p.right = NewNode(v) + break + } + p = p.right + } else { + if nil == p.left { + p.left = NewNode(v) + break + } + p = p.left + } + } + return true +} + +func (this *BST) Delete(v interface{}) bool { + var pp *Node = nil + p := this.root + deleteLeft := false + for nil != p { + compareResult := this.compareFunc(v, p.data) + if compareResult > 0 { + pp = p + p = p.right + deleteLeft = false + } else if compareResult < 0 { + pp = p + p = p.left + deleteLeft = true + } else { + break + } + } + + if nil == p { //需要删除的节点不存在 + return false + } else if nil == p.left && nil == p.right { //删除的是一个叶子节点 + if nil != pp { + if deleteLeft { + pp.left = nil + } else { + pp.right = nil + } + } else { //根节点 + this.root = nil + } + } else if nil != p.right { //删除的是一个有右孩子,不一定有左孩子的节点 + //找到p节点右孩子的最小节点 + pq := p + q := p.right //向右走一步 + fromRight := true + for nil != q.left { //向左走到底 + pq = q + q = q.left + fromRight = false + } + if fromRight { + pq.right = nil + } else { + pq.left = nil + } + q.left = p.left + q.right = p.right + if nil == pp { //根节点被删除 + this.root = q + } else { + if deleteLeft { + pq.left = q + } else { + pq.right = q + } + } + } else { //删除的是一个只有左孩子的节点 + if nil != pp { + if deleteLeft { + pp.left = p.left + } else { + pp.right = p.left + } + } else { + if deleteLeft { + this.root = p.left + } else { + this.root = p.left + } + } + } + + return true + +} + +func (this *BST) Min() *Node { + p := this.root + for nil != p.left { + p = p.left + } + return p +} + +func (this *BST) Max() *Node { + p := this.root + for nil != p.right { + p = p.right + } + return p +} diff --git a/go/24_tree/BinarySearchTree_test.go b/go/24_tree/BinarySearchTree_test.go new file mode 100644 index 00000000..f9dbb616 --- /dev/null +++ b/go/24_tree/BinarySearchTree_test.go @@ -0,0 +1,145 @@ +package _4_tree + +import "testing" + +var compareFunc = func(v, nodeV interface{}) int { + vInt := v.(int) + nodeVInt := nodeV.(int) + + if vInt > nodeVInt { + return 1 + } else if vInt < nodeVInt { + return -1 + } + return 0 +} + +func TestBST_Find(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Find(2)) +} + +func TestBST_Insert(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + bst.InOrderTraverse() +} + +func TestBST_Min(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Min()) +} + +func TestBST_Max(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(1) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Max()) +} + +func TestBST_DeleteA(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Delete(7)) + + bst.InOrderTraverse() +} + +func TestBST_DeleteB(t *testing.T) { + bst := NewBST(1, compareFunc) + + t.Log(bst.Delete(1)) + t.Log(bst.root) + + bst.InOrderTraverse() +} + +func TestBST_DeleteC(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(7) + bst.Insert(5) + + t.Log(bst.Delete(1)) + + bst.InOrderTraverse() +} + +func TestBST_DeleteD(t *testing.T) { + bst := NewBST(1, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(5) + + t.Log(bst.Delete(1)) + + bst.InOrderTraverse() +} +func TestBST_DeleteE(t *testing.T) { + bst := NewBST(5, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(4) + bst.Insert(1) + + t.Log(bst.Delete(5)) + bst.InOrderTraverse() +} + +func TestBST_DeleteF(t *testing.T) { + bst := NewBST(5, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(4) + bst.Insert(1) + + t.Log(bst.Delete(2)) + bst.InOrderTraverse() +} + +func TestBST_DeleteG(t *testing.T) { + bst := NewBST(5, compareFunc) + + bst.Insert(3) + bst.Insert(2) + bst.Insert(4) + bst.Insert(1) + + t.Log(bst.Delete(1)) + bst.InOrderTraverse() +} diff --git a/go/24_tree/BinaryTree.go b/go/24_tree/BinaryTree.go new file mode 100644 index 00000000..cd2417db --- /dev/null +++ b/go/24_tree/BinaryTree.go @@ -0,0 +1,97 @@ +package _4_tree + +import "fmt" + +type BinaryTree struct { + root *Node +} + +func NewBinaryTree(rootV interface{}) *BinaryTree { + return &BinaryTree{NewNode(rootV)} +} + +func (this *BinaryTree) InOrderTraverse() { + p := this.root + s := NewArrayStack() + + for !s.IsEmpty() || nil != p { + if nil != p { + s.Push(p) + p = p.left + } else { + tmp := s.Pop().(*Node) + fmt.Printf("%+v ", tmp.data) + p = tmp.right + } + } + fmt.Println() +} + +func (this *BinaryTree) PreOrderTraverse() { + p := this.root + s := NewArrayStack() + + for !s.IsEmpty() || nil != p { + if nil != p { + fmt.Printf("%+v ", p.data) + s.Push(p) + p = p.left + } else { + p = s.Pop().(*Node).right + } + } + + fmt.Println() +} + +func (this *BinaryTree) PostOrderTraverse() { + s1 := NewArrayStack() + s2 := NewArrayStack() + s1.Push(this.root) + for !s1.IsEmpty() { + p := s1.Pop().(*Node) + s2.Push(p) + if nil != p.left { + s1.Push(p.left) + } + if nil != p.right { + s1.Push(p.right) + } + } + + for !s2.IsEmpty() { + fmt.Printf("%+v ", s2.Pop().(*Node).data) + } +} + +//use one stack, pre cursor to traverse from post order +func (this *BinaryTree) PostOrderTraverse2() { + r := this.root + s := NewArrayStack() + + //point to last visit node + var pre *Node + + s.Push(r) + + for !s.IsEmpty() { + r = s.Top().(*Node) + if (r.left == nil && r.right == nil) || + (pre != nil && (pre == r.left || pre == r.right)) { + + fmt.Printf("%+v ", r.data) + s.Pop() + pre = r + } else { + if r.right != nil { + s.Push(r.right) + } + + if r.left != nil { + s.Push(r.left) + } + + } + + } +} diff --git a/go/24_tree/BinaryTree_test.go b/go/24_tree/BinaryTree_test.go new file mode 100644 index 00000000..6f8bf154 --- /dev/null +++ b/go/24_tree/BinaryTree_test.go @@ -0,0 +1,39 @@ +package _4_tree + +import "testing" + +func TestBinaryTree_InOrderTraverse(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.InOrderTraverse() +} + +func TestBinaryTree_PreOrderTraverse(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.PreOrderTraverse() +} + +func TestBinaryTree_PostOrderTraverse(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.PostOrderTraverse() +} + +func TestBinaryTree_PostOrderTraverse2(t *testing.T) { + binaryTree := NewBinaryTree(1) + binaryTree.root.left = NewNode(3) + binaryTree.root.right = NewNode(4) + binaryTree.root.right.left = NewNode(5) + + binaryTree.PostOrderTraverse2() +} diff --git a/go/24_tree/StackBasedOnArray.go b/go/24_tree/StackBasedOnArray.go new file mode 100644 index 00000000..e1c585f6 --- /dev/null +++ b/go/24_tree/StackBasedOnArray.go @@ -0,0 +1,72 @@ +package _4_tree + +import "fmt" + +/* +基于数组实现的栈 +*/ + +type ArrayStack struct { + //数据 + data []interface{} + //栈顶指针 + top int +} + +func NewArrayStack() *ArrayStack { + return &ArrayStack{ + data: make([]interface{}, 0, 32), + top: -1, + } +} + +func (this *ArrayStack) IsEmpty() bool { + if this.top < 0 { + return true + } + return false +} + +func (this *ArrayStack) Push(v interface{}) { + if this.top < 0 { + this.top = 0 + } else { + this.top += 1 + } + + if this.top > len(this.data)-1 { + this.data = append(this.data, v) + } else { + this.data[this.top] = v + } +} + +func (this *ArrayStack) Pop() interface{} { + if this.IsEmpty() { + return nil + } + v := this.data[this.top] + this.top -= 1 + return v +} + +func (this *ArrayStack) Top() interface{} { + if this.IsEmpty() { + return nil + } + return this.data[this.top] +} + +func (this *ArrayStack) Flush() { + this.top = -1 +} + +func (this *ArrayStack) Print() { + if this.IsEmpty() { + fmt.Println("empty statck") + } else { + for i := this.top; i >= 0; i-- { + fmt.Println(this.data[i]) + } + } +} diff --git a/go/24_tree/TreeNode.go b/go/24_tree/TreeNode.go new file mode 100644 index 00000000..775cf46c --- /dev/null +++ b/go/24_tree/TreeNode.go @@ -0,0 +1,17 @@ +package _4_tree + +import "fmt" + +type Node struct { + data interface{} + left *Node + right *Node +} + +func NewNode(data interface{}) *Node { + return &Node{data: data} +} + +func (this *Node) String() string { + return fmt.Sprintf("v:%+v, left:%+v, right:%+v", this.data, this.left, this.right) +} diff --git a/go/28_heap/heap.go b/go/28_heap/heap.go new file mode 100644 index 00000000..0d9327ee --- /dev/null +++ b/go/28_heap/heap.go @@ -0,0 +1,83 @@ +package heap + +type Heap struct { + a []int + n int + count int +} + +//init heap +func NewHeap(capacity int) *Heap { + heap := &Heap{} + heap.n = capacity + heap.a = make([]int, capacity+1) + heap.count = 0 + return heap +} + +//top-max heap -> heapify from down to up +func (heap *Heap) insert(data int) { + //defensive + if heap.count == heap.n { + return + } + + heap.count++ + heap.a[heap.count] = data + + //compare with parent node + i := heap.count + parent := i / 2 + for parent > 0 && heap.a[parent] < heap.a[i] { + swap(heap.a, parent, i) + i = parent + parent = i / 2 + } +} + +//heapfify from up to down +func (heap *Heap) removeMax() { + + //defensive + if heap.count == 0 { + return + } + + //swap max and last + swap(heap.a, 1, heap.count) + heap.count-- + + //heapify from up to down + heapifyUpToDown(heap.a, heap.count) +} + +//heapify +func heapifyUpToDown(a []int, count int) { + + for i := 1; i <= count/2; { + + maxIndex := i + if a[i] < a[i*2] { + maxIndex = i * 2 + } + + if i*2+1 <= count && a[maxIndex] < a[i*2+1] { + maxIndex = i*2 + 1 + } + + if maxIndex == i { + break + } + + swap(a, i, maxIndex) + i = maxIndex + } + +} + +//swap two elements +func swap(a []int, i int, j int) { + tmp := a[i] + a[i] = a[j] + a[j] = tmp +} diff --git a/go/28_heap/heap_sort.go b/go/28_heap/heap_sort.go new file mode 100644 index 00000000..76171335 --- /dev/null +++ b/go/28_heap/heap_sort.go @@ -0,0 +1,54 @@ +package heap + +//build a heap +func buidHeap(a []int, n int) { + + //heapify from the last parent node + for i := n / 2; i >= 1; i-- { + heapifyUpToDown(a, i, n) + } + +} + +//sort by ascend, a index begin from 1, has n elements +func sort(a []int, n int) { + buidHeap(a, n) + + k := n + for k >= 1 { + swap(a, 1, k) + heapifyUpToDown(a, 1, k-1) + k-- + } +} + +//heapify from up to down , node index = top +func heapifyUpToDown(a []int, top int, count int) { + + for i := top; i <= count/2; { + + maxIndex := i + if a[i] < a[i*2] { + maxIndex = i * 2 + } + + if i*2+1 <= count && a[maxIndex] < a[i*2+1] { + maxIndex = i*2 + 1 + } + + if maxIndex == i { + break + } + + swap(a, i, maxIndex) + i = maxIndex + } + +} + +//swap two elements +func swap(a []int, i int, j int) { + tmp := a[i] + a[i] = a[j] + a[j] = tmp +} diff --git a/go/31_graph/graph_search.go b/go/31_graph/graph_search.go new file mode 100644 index 00000000..d5f61955 --- /dev/null +++ b/go/31_graph/graph_search.go @@ -0,0 +1,152 @@ +package graph + +import ( + "container/list" + "fmt" +) + +//adjacency table, 无向图 +type Graph struct { + adj []*list.List + v int +} + +//init graphh according to capacity +func newGraph(v int) *Graph { + graphh := &Graph{} + graphh.v = v + graphh.adj = make([]*list.List, v) + for i := range graphh.adj { + graphh.adj[i] = list.New() + } + return graphh +} + +//insert as add edge,一条边存2次 +func (self *Graph) addEdge(s int, t int) { + self.adj[s].PushBack(t) + self.adj[t].PushBack(s) +} + +//search path by BFS +func (self *Graph) BFS(s int, t int) { + + //todo + if s == t { + return + } + + //init prev + prev := make([]int, self.v) + for index := range prev { + prev[index] = -1 + } + + //search by queue + var queue []int + visited := make([]bool, self.v) + queue = append(queue, s) + visited[s] = true + isFound := false + for len(queue) > 0 && !isFound { + top := queue[0] + queue = queue[1:] + linkedlist := self.adj[top] + for e := linkedlist.Front(); e != nil; e = e.Next() { + k := e.Value.(int) + if !visited[k] { + prev[k] = top + if k == t { + isFound = true + break + } + queue = append(queue, k) + visited[k] = true + } + } + } + + if isFound { + printPrev(prev, s, t) + } else { + fmt.Printf("no path found from %d to %d\n", s, t) + } + +} + +//search by DFS +func (self *Graph) DFS(s int, t int) { + + prev := make([]int, self.v) + for i := range prev { + prev[i] = -1 + } + + visited := make([]bool, self.v) + visited[s] = true + + isFound := false + self.recurse(s, t, prev, visited, isFound) + + printPrev(prev, s, t) +} + +//recursivly find path +func (self *Graph) recurse(s int, t int, prev []int, visited []bool, isFound bool) { + + if isFound { + return + } + + visited[s] = true + + if s == t { + isFound = true + return + } + + linkedlist := self.adj[s] + for e := linkedlist.Front(); e != nil; e = e.Next() { + k := e.Value.(int) + if !visited[k] { + prev[k] = s + self.recurse(k, t, prev, visited, false) + } + } + +} + +//print path recursively +func printPrev(prev []int, s int, t int) { + + if t == s || prev[t] == -1 { + fmt.Printf("%d ", t) + } else { + printPrev(prev, s, prev[t]) + fmt.Printf("%d ", t) + } + +} + +//func main() { +// graph := newGraph(8) +// graph.addEdge(0, 1) +// graph.addEdge(0, 3) +// graph.addEdge(1, 2) +// graph.addEdge(1, 4) +// graph.addEdge(2, 5) +// graph.addEdge(3, 4) +// graph.addEdge(4, 5) +// graph.addEdge(4, 6) +// graph.addEdge(5, 7) +// graph.addEdge(6, 7) +// +// graph.BFS(0, 7) +// fmt.Println() +// graph.BFS(1, 3) +// fmt.Println() +// graph.DFS(0, 7) +// fmt.Println() +// graph.DFS(1, 3) +// fmt.Println() +//} diff --git a/go/32_string/string_bf.go b/go/32_string/string_bf.go new file mode 100644 index 00000000..edc37286 --- /dev/null +++ b/go/32_string/string_bf.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" +) + +//BF search pattern index, return the first match subs start index +func bfSearch(main string, pattern string) int { + + //defensive + if len(main) == 0 || len(pattern) == 0 || len(main) < len(pattern) { + return -1 + } + + for i := 0; i <= len(main)-len(pattern); i++ { + subStr := main[i : i+len(pattern)] + if subStr == pattern { + return i + } + } + + return -1 +} + +func main() { + + main := "abcd227fac" + pattern := "ac" + fmt.Println(bfSearch(main, pattern)) +} diff --git a/go/32_string/string_bm.go b/go/32_string/string_bm.go new file mode 100644 index 00000000..c64f7e6a --- /dev/null +++ b/go/32_string/string_bm.go @@ -0,0 +1,140 @@ +package main + +import ( + "fmt" + "math" +) + +//bc: pattern char index hash mapping +func generateBC(pattern string) []int { + + bc := make([]int, 256) + + for index := range bc { + bc[index] = -1 + } + + for index, char := range pattern { + bc[int(char)] = index + } + + return bc +} + +//generate suffix and prefix array for pattern +func generateGS(pattern string) ([]int, []bool) { + m := len(pattern) + suffix := make([]int, m) + prefix := make([]bool, m) + + //init + for i := 0; i < m; i++ { + suffix[i] = -1 + prefix[i] = false + } + + for i := 0; i < m-1; i++ { + j := i + k := 0 + for j >= 0 && pattern[j] == pattern[m-1-k] { + j-- + k++ + suffix[k] = j + 1 + } + + if j == -1 { + prefix[k] = true + } + } + + return suffix, prefix +} + +//todo +func moveByGS(patternLength int, badCharStartIndex int, suffix []int, prefix []bool) int { + + //length of good suffix + k := patternLength - badCharStartIndex - 1 + + //complete match + if suffix[k] != -1 { + return badCharStartIndex + 1 - suffix[k] + } + + //partial match + for t := patternLength - 1; t > badCharStartIndex+1; t-- { + if prefix[t] { + return t + } + } + + //no match + return patternLength + +} + +func bmSearch(main string, pattern string) int { + //defensive + if len(main) == 0 || len(pattern) == 0 || len(pattern) > len(main) { + return -1 + } + + bc := generateBC(pattern) + suffix, prefix := generateGS(pattern) + + n := len(main) + m := len(pattern) + + // i : start index of main string + step := 1 + for i := 0; i <= n-m; i = i + step { + subStr := main[i : i+m] + k, j := findBadChar(subStr, pattern, bc) + + stepForBC := j - k + //j is bad char occur index + if j == -1 { + return i + } + + stepForGS := -1 + if j < m-1 { + stepForGS = moveByGS(m, j, suffix, prefix) + } + + //k is bad char index in pattern + step = int(math.Max(float64(stepForBC), float64(stepForGS))) + } + + return -1 +} + +func findBadChar(subStr string, pattern string, bc []int) (int, int) { + + j := -1 + k := -1 + badChar := rune(0) + + for index := len(subStr) - 1; index >= 0; index-- { + if subStr[index] != pattern[index] { + j = index + badChar = rune(subStr[index]) + break + } + } + + //if bad character exist, then find it's index at pattern + if j > 0 { + k = bc[int(badChar)] + } + + return k, j +} + +func main() { + + main := "abcacabcbcabcabc" + pattern := "cabcab" + + fmt.Println(bmSearch(main, pattern)) +} diff --git a/go/binarysearch2.go b/go/binarysearch2.go index ef2549eb..9e3f71e2 100644 --- a/go/binarysearch2.go +++ b/go/binarysearch2.go @@ -6,7 +6,7 @@ func BinarySearch2(nums []int, value int) int { start := 0 end := length - 1 for start <= end { - mid := (start + end) / 2 + mid := start + ((end - start) >> 1) if nums[mid] > value { end = mid - 1 } else if nums[mid] < value { @@ -29,7 +29,7 @@ func BinarySearch3(nums []int, value int) int { start := 0 end := len(nums) - 1 for start <= end { - mid := (start + end) / 2 + mid := start + ((end - start) >> 1) if nums[mid] > value { end = mid - 1 } else if nums[mid] < value { diff --git a/java/05_array/GenericArray.java b/java/05_array/GenericArray.java index 07dc5dc6..631a1bae 100644 --- a/java/05_array/GenericArray.java +++ b/java/05_array/GenericArray.java @@ -1,164 +1,163 @@ -/** - * - * 1)泛型动态数组 - * - * Author: shi - */ - - public class GenericArray { - private T[] data; - private int size; - - // 根据传入容量,构造Array - public GenericArray(int capacity) { - data = (T[]) new Object[capacity]; - size = 0; - } - - // 无参构造方法,默认数组容量为10 - public GenericArray() { - this(10); - } - - // 获取数组容量 - public int getCapacity() { - return data.length; - } - - // 获取当前元素个数 - public int count() { - return size; - } - - // 判断数组是否为空 - public boolean isEmpty() { - return size == 0; - } - - // 修改 index 位置的元素 - public void set(int index, T e) { - checkIndex(index); - data[index] = e; - } - - // 获取对应 index 位置的元素 - public T get(int index) { - checkIndex(index); - return data[index]; - } - - // 查看数组是否包含元素e - public boolean contains(T e) { - for (int i = 0; i < size; i++) { - if (data[i].equals(e)) { - return true; - } - } - return false; - } - - // 获取对应元素的下标, 未找到,返回 -1 - public int find(T e) { - for ( int i = 0; i < size; i++) { - if (data[i].equals(e)) { - return i; - } - } - return -1; - } - - - // 在 index 位置,插入元素e, 时间复杂度 O(m+n) - public void add(int index, T e) { - checkIndex(index); - // 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍 - if (size == data.length) { - resize(2 * data.length); - } - - for (int i = size - 1; i >= index; i--) { - data[i + 1] = data[i]; - } - data[index] = e; - size++; - } - - // 向数组头插入元素 - public void addFirst(T e) { - add(0, e); - } - - // 向数组尾插入元素 - public void addLast(T e) { - add(size, e); - } - - // 删除 index 位置的元素,并返回 - public T remove(int index) { - checkIndex(index); - - T ret = data[index]; - for (int i = index + 1; i < size; i++) { - data[i - 1] = data[i]; - } - size --; - data[size] = null; - - // 缩容 - if (size == data.length / 4 && data.length / 2 != 0) { - resize(data.length / 2); - } - - return ret; - } - - // 删除第一个元素 - public T removeFirst() { - return remove(0); - } - - // 删除末尾元素 - public T removeLast() { - return remove(size - 1); - } - - // 从数组中删除指定元素 - public void removeElement(T e) { - int index = find(e); - if (index != -1) { - remove(index); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length)); - builder.append('['); - for (int i = 0; i < size; i++) { - builder.append(data[i]); - if (i != size - 1) { - builder.append(", "); - } - } - builder.append(']'); - return builder.toString(); - } - - - // 扩容方法,时间复杂度 O(n) - private void resize(int capacity) { - T[] newData = (T[]) new Object[capacity]; - - for (int i = 0; i < size; i++) { - newData[i] = data[i]; - } - data = newData; - } - - private void checkIndex(int index) { +public class GenericArray { + private T[] data; + private int size; + + // 根据传入容量,构造Array + public GenericArray(int capacity) { + data = (T[]) new Object[capacity]; + size = 0; + } + + // 无参构造方法,默认数组容量为10 + public GenericArray() { + this(10); + } + + // 获取数组容量 + public int getCapacity() { + return data.length; + } + + // 获取当前元素个数 + public int count() { + return size; + } + + // 判断数组是否为空 + public boolean isEmpty() { + return size == 0; + } + + // 修改 index 位置的元素 + public void set(int index, T e) { + checkIndex(index); + data[index] = e; + } + + // 获取对应 index 位置的元素 + public T get(int index) { + checkIndex(index); + return data[index]; + } + + // 查看数组是否包含元素e + public boolean contains(T e) { + for (int i = 0; i < size; i++) { + if (data[i].equals(e)) { + return true; + } + } + return false; + } + + // 获取对应元素的下标, 未找到,返回 -1 + public int find(T e) { + for ( int i = 0; i < size; i++) { + if (data[i].equals(e)) { + return i; + } + } + return -1; + } + + + // 在 index 位置,插入元素e, 时间复杂度 O(m+n) + public void add(int index, T e) { + checkIndex(index); + // 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍 + if (size == data.length) { + resize(2 * data.length); + } + + for (int i = size - 1; i >= index; i--) { + data[i + 1] = data[i]; + } + data[index] = e; + size++; + } + + // 向数组头插入元素 + public void addFirst(T e) { + add(0, e); + } + + // 向数组尾插入元素 + public void addLast(T e) { + add(size, e); + } + + // 删除 index 位置的元素,并返回 + public T remove(int index) { + checkIndexForRemove(index); + + T ret = data[index]; + for (int i = index + 1; i < size; i++) { + data[i - 1] = data[i]; + } + size --; + data[size] = null; + + // 缩容 + if (size == data.length / 4 && data.length / 2 != 0) { + resize(data.length / 2); + } + + return ret; + } + + // 删除第一个元素 + public T removeFirst() { + return remove(0); + } + + // 删除末尾元素 + public T removeLast() { + return remove(size - 1); + } + + // 从数组中删除指定元素 + public void removeElement(T e) { + int index = find(e); + if (index != -1) { + remove(index); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length)); + builder.append('['); + for (int i = 0; i < size; i++) { + builder.append(data[i]); + if (i != size - 1) { + builder.append(", "); + } + } + builder.append(']'); + return builder.toString(); + } + + + // 扩容方法,时间复杂度 O(n) + private void resize(int capacity) { + T[] newData = (T[]) new Object[capacity]; + + for (int i = 0; i < size; i++) { + newData[i] = data[i]; + } + data = newData; + } + + private void checkIndex(int index) { if (index < 0 || index > size) { throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size."); } - } - } + } + + private void checkIndexForRemove(int index) { + if(index < 0 || index >= size) { + throw new IllegalArgumentException("remove failed! Require index >=0 and index < size."); + } + } +} \ No newline at end of file diff --git a/java/06_linkedlist/LRUBasedArray.java b/java/06_linkedlist/LRUBasedArray.java new file mode 100644 index 00000000..160a8926 --- /dev/null +++ b/java/06_linkedlist/LRUBasedArray.java @@ -0,0 +1,173 @@ +package linkedlist; + +import java.util.HashMap; +import java.util.Map; +/** + * Created by SpecialYang in 2018/12/7 2:00 PM. + * + * 基于数组实现的LRU缓存 + * 1. 空间复杂度为O(n) + * 2. 时间复杂度为O(n) + * 3. 不支持null的缓存 + */ +public class LRUBasedArray { + + private static final int DEFAULT_CAPACITY = (1 << 3); + + private int capacity; + + private int count; + + private T[] value; + + private Map holder; + + public LRUBasedArray() { + this(DEFAULT_CAPACITY); + } + + public LRUBasedArray(int capacity) { + this.capacity = capacity; + value = (T[]) new Object[capacity]; + count = 0; + holder = new HashMap(capacity); + } + + /** + * 模拟访问某个值 + * @param object + */ + public void offer(T object) { + if (object == null) { + throw new IllegalArgumentException("该缓存容器不支持null!"); + } + Integer index = holder.get(object); + if (index == null) { + if (isFull()) { + removeAndCache(object); + } else { + cache(object, count); + } + } else { + update(index); + } + } + + /** + * 若缓存中有指定的值,则更新位置 + * @param end + */ + public void update(int end) { + T target = value[end]; + rightShift(end); + value[0] = target; + holder.put(target, 0); + } + + /** + * 缓存数据到头部,但要先右移 + * @param object + * @param end 数组右移的边界 + */ + public void cache(T object, int end) { + rightShift(end); + value[0] = object; + holder.put(object, 0); + count++; + } + + /** + * 缓存满的情况,踢出后,再缓存到数组头部 + * @param object + */ + public void removeAndCache(T object) { + value[--count] = null; + cache(object, count); + } + + /** + * end左边的数据统一右移一位 + * @param end + */ + private void rightShift(int end) { + for (int i = end - 1; i >= 0; i--) { + value[i + 1] = value[i]; + holder.put(value[i], i + 1); + } + } + + public boolean isContain(T object) { + return holder.containsKey(object); + } + + public boolean isEmpty() { + return count == 0; + } + + public boolean isFull() { + return count == capacity; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < count; i++) { + sb.append(value[i]); + sb.append(" "); + } + return sb.toString(); + } + + static class TestLRUBasedArray { + + public static void main(String[] args) { + testDefaultConstructor(); + testSpecifiedConstructor(4); +// testWithException(); + } + + private static void testWithException() { + LRUBasedArray lru = new LRUBasedArray(); + lru.offer(null); + } + + public static void testDefaultConstructor() { + System.out.println("======无参测试========"); + LRUBasedArray lru = new LRUBasedArray(); + lru.offer(1); + lru.offer(2); + lru.offer(3); + lru.offer(4); + lru.offer(5); + System.out.println(lru); + lru.offer(6); + lru.offer(7); + lru.offer(8); + lru.offer(9); + System.out.println(lru); + } + + public static void testSpecifiedConstructor(int capacity) { + System.out.println("======有参测试========"); + LRUBasedArray lru = new LRUBasedArray(capacity); + lru.offer(1); + System.out.println(lru); + lru.offer(2); + System.out.println(lru); + lru.offer(3); + System.out.println(lru); + lru.offer(4); + System.out.println(lru); + lru.offer(2); + System.out.println(lru); + lru.offer(4); + System.out.println(lru); + lru.offer(7); + System.out.println(lru); + lru.offer(1); + System.out.println(lru); + lru.offer(2); + System.out.println(lru); + } + } +} diff --git a/java/06_linkedlist/SinglyLinkedList.java b/java/06_linkedlist/SinglyLinkedList.java index 0931d133..c6d36e2f 100644 --- a/java/06_linkedlist/SinglyLinkedList.java +++ b/java/06_linkedlist/SinglyLinkedList.java @@ -8,160 +8,329 @@ */ public class SinglyLinkedList { - private Node head = null; + private Node head = null; - public Node findByValue(int value) { - Node p = head; - while (p != null && p.data != value) { - p = p.next; + public Node findByValue(int value) { + Node p = head; + while (p != null && p.data != value) { + p = p.next; + } + + return p; } - return p; - } + public Node findByIndex(int index) { + Node p = head; + int pos = 0; + while (p != null && pos != index) { + p = p.next; + ++pos; + } - public Node findByIndex(int index) { - Node p = head; - int pos = 0; - while (p != null && pos != index) { - p = p.next; - ++pos; + return p; } - return p; - } + //无头结点 + //表头部插入 + //这种操作将于输入的顺序相反,逆序 + public void insertToHead(int value) { + Node newNode = new Node(value, null); + insertToHead(newNode); + } - public void insertToHead(int value) { - Node newNode = new Node(value, null); - insertToHead(newNode); - } + public void insertToHead(Node newNode) { + if (head == null) { + head = newNode; + } else { + newNode.next = head; + head = newNode; + } + } - public void insertToHead(Node newNode) { - if (head == null) { - head = newNode; - } else { - newNode.next = head; - head = newNode; + //顺序插入 + //链表尾部插入 + public void insertTail(int value){ + + Node newNode = new Node(value, null); + //空链表,可以插入新节点作为head,也可以不操作 + if (head == null){ + head = newNode; + + }else{ + Node q = head; + while(q.next != null){ + q = q.next; + } + newNode.next = q.next; + q.next = newNode; + } + } + public void insertAfter(Node p, int value) { + Node newNode = new Node(value, null); + insertAfter(p, newNode); } - } - public void insertAfter(Node p, int value) { - Node newNode = new Node(value, null); - insertAfter(p, newNode); - } + public void insertAfter(Node p, Node newNode) { + if (p == null) return; - public void insertAfter(Node p, Node newNode) { - if (p == null) return; + newNode.next = p.next; + p.next = newNode; + } - newNode.next = p.next; - p.next = newNode; - } + public void insertBefore(Node p, int value) { + Node newNode = new Node(value, null); + insertBefore(p, newNode); + } - public void insertBefore(Node p, int value) { - Node newNode = new Node(value, null); - insertBefore(p, newNode); - } + public void insertBefore(Node p, Node newNode) { + if (p == null) return; + if (head == p) { + insertToHead(newNode); + return; + } - public void insertBefore(Node p, Node newNode) { - if (p == null) return; - if (head == p) { - insertToHead(newNode); - return; - } + Node q = head; + while (q != null && q.next != p) { + q = q.next; + } - Node q = head; - while (q != null && q.next != p) { - q = q.next; - } + if (q == null) { + return; + } + + newNode.next = p; + q.next = newNode; - if (q == null) { - return; } - newNode.next = p; - q.next = newNode; + public void deleteByNode(Node p) { + if (p == null || head == null) return; - } + if (p == head) { + head = head.next; + return; + } - public void deleteByNode(Node p) { - if (p == null || head == null) return; + Node q = head; + while (q != null && q.next != p) { + q = q.next; + } - if (p == head) { - head = head.next; - return; + if (q == null) { + return; + } + + q.next = q.next.next; } - Node q = head; - while (q != null && q.next != p) { - q = q.next; + public void deleteByValue(int value) { + if (head == null) return; + + Node p = head; + Node q = null; + while (p != null && p.data != value) { + q = p; + p = p.next; + } + + if (p == null) return; + + if (q == null) { + head = head.next; + } else { + q.next = q.next.next; + } + + // 可重复删除指定value的代码 + /* + if (head != null && head.data == value) { + head = head.next; + } + + Node pNode = head; + while (pNode != null) { + if (pNode.next.data == data) { + pNode.next = pNode.next.next; + continue; + } + pNode = pNode.next; + } + */ } - if (q == null) { - return; + public void printAll() { + Node p = head; + while (p != null) { + System.out.print(p.data + " "); + p = p.next; + } + System.out.println(); } - q.next = q.next.next; - } + //判断true or false + public boolean TFResult(Node left, Node right){ + Node l = left; + Node r = right; + + System.out.println("left_:"+l.data); + System.out.println("right_:"+r.data); + while(l != null && r != null){ + if (l.data == r.data){ + l = l.next; + r = r.next; + continue; + }else{ + break; + } + + } + + System.out.println("什么结果"); + if (l==null && r==null){ + System.out.println("什么结果"); + return true; + }else{ + return false; + } + } + // 判断是否为回文 + + public boolean palindrome(){ + if (head == null){ + return false; + }else{ + System.out.println("开始执行找到中间节点"); + Node p = head; + Node q = head; + if (p.next == null){ + System.out.println("只有一个元素"); + return true; + } + while( q.next != null && q.next.next != null){ + p = p.next; + q = q.next.next; + + } + + System.out.println("中间节点" + p.data); + System.out.println("开始执行奇数节点的回文判断"); + Node leftLink = null; + Node rightLink = null; + if(q.next == null){ + // p 一定为整个链表的中点,且节点数目为奇数 + rightLink = p.next; + leftLink = inverseLinkList(p).next; + System.out.println("左边第一个节点"+leftLink.data); + System.out.println("右边第一个节点"+rightLink.data); + + }else{ + //p q 均为中点 + rightLink = p.next; + leftLink = inverseLinkList(p); + } + return TFResult(leftLink, rightLink); + + } + } - public void deleteByValue(int value) { - if (head == null) return; + //带结点的链表翻转 + public Node inverseLinkList_head(Node p){ + // Head 为新建的一个头结点 + Node Head = new Node(9999,null); + // p 为原来整个链表的头结点,现在Head指向 整个链表 + Head.next = p; + /* + 带头结点的链表翻转等价于 + 从第二个元素开始重新头插法建立链表 + */ + Node Cur = p.next; + p.next = null; + Node next = null; + + while(Cur != null){ + next = Cur.next; + Cur.next = Head.next; + Head.next = Cur; + System.out.println("first " + Head.data); + + Cur = next; + } + + // 返回左半部分的中点之前的那个节点 + // 从此处开始同步像两边比较 + return Head; - Node p = head; - Node q = null; - while (p != null && p.data != value) { - q = p; - p = p.next; } - if (p == null) return; + //无头结点的链表翻转 + public Node inverseLinkList(Node p){ - if (q == null) { - head = head.next; - } else { - q.next = q.next.next; - } + Node pre = null; + Node r = head; + System.out.println("z---" + r.data); + Node next= null; + while(r !=p){ + next = r.next; - // 可重复删除指定value的代码 - /* - if (head != null && head.data == value) { - head = head.next; - } + r.next = pre; + pre = r; + r = next; + } - Node pNode = head; - while (pNode != null) { - if (pNode.next.data == data) { - pNode.next = pNode.next.next; - continue; - } - pNode = pNode.next; - } - */ - } + r.next = pre; + // 返回左半部分的中点之前的那个节点 + // 从此处开始同步像两边比较 + return r; - public void printAll() { - Node p = head; - while (p != null) { - System.out.print(p.data + " "); - p = p.next; } - System.out.println(); - } + + public static Node createNode(int value) { + return new Node(value, null); + } - public static Node createNode(int value) { - return new Node(value, null); - } + public static class Node { + private int data; + private Node next; - public static class Node { - private int data; - private Node next; + public Node(int data, Node next) { + this.data = data; + this.next = next; + } - public Node(int data, Node next) { - this.data = data; - this.next = next; + public int getData() { + return data; + } } - - public int getData() { - return data; + public static void main(String[]args){ + + SinglyLinkedList link = new SinglyLinkedList(); + System.out.println("hello"); + //int data[] = {1}; + //int data[] = {1,2}; + //int data[] = {1,2,3,1}; + //int data[] = {1,2,5}; + //int data[] = {1,2,2,1}; + // int data[] = {1,2,5,2,1}; + int data[] = {1,2,5,3,1}; + + for(int i =0; i < data.length; i++){ + //link.insertToHead(data[i]); + link.insertTail(data[i]); + } + // link.printAll(); + // Node p = link.inverseLinkList_head(link.head); + // while(p != null){ + // System.out.println("aa"+p.data); + // p = p.next; + // } + + System.out.println("打印原始:"); + link.printAll(); + if (link.palindrome()){ + System.out.println("回文"); + }else{ + System.out.println("不是回文"); + } } - } } diff --git a/java/11_sorts/InsertionSortAdd.java b/java/11_sorts/InsertionSortAdd.java new file mode 100644 index 00000000..31c436ea --- /dev/null +++ b/java/11_sorts/InsertionSortAdd.java @@ -0,0 +1,48 @@ +package sorts; + +import java.util.Arrays; + +/** + * 插入排序(插入位置,从头至尾搜索) + * @Author: ooooor + */ +public class InsertionSortAdd { + + public static void main(String[] args) { + int[] data = new int[]{4, 6, 5, 3, 7, 1, 2}; + fromStartToEnd(Arrays.copyOf(data, data.length)); + System.out.println(Arrays.toString(data)); + } + + /** + * 查询插入位置时, 从头至尾搜索 + * @param data + */ + private static void fromStartToEnd(int[] data) { + for (int i=1; i < data.length; i++) { + int value = data[i]; + + int[] tmp = new int[2]; + int change = i; + for (int j=0; j < i; j++) { + if(value >= data[j]) { + continue; + } + + int index = j%2; + if (change == i) { + tmp[Math.abs(index-1)] = data[j]; + change = j; + } + tmp[index] = data[j+1]; + if (0 == index) { + data[j+1] = tmp[index+1]; + } else { + data[j+1] = tmp[index-1]; + } + } + data[change] = value; + } + } + +} diff --git a/java/11_sorts/Sorts.java b/java/11_sorts/Sorts.java index e55efd7d..9460291f 100644 --- a/java/11_sorts/Sorts.java +++ b/java/11_sorts/Sorts.java @@ -49,31 +49,16 @@ public static void insertionSort(int[] a, int n) { // 选择排序,a表示数组,n表示数组大小 public static void selectionSort(int[] a, int n) { if (n <= 1) return; -<<<<<<< HEAD - for (int i = 0; i < n; ++i) { - // 查找最小值 - int minIndex = i; - int minValue = a[i]; - for (int j = i; j < n; ++j) { - if (a[j] < minValue) { - minValue = a[j]; -======= + for (int i = 0; i < n - 1; ++i) { // 查找最小值 int minIndex = i; for (int j = i + 1; j < n; ++j) { if (a[j] < a[minIndex]) { ->>>>>>> upstream/master minIndex = j; } } - -<<<<<<< HEAD -======= - if (minIndex == i) - continue; - ->>>>>>> upstream/master + // 交换 int tmp = a[i]; a[i] = a[minIndex]; diff --git a/java/17_skiplist/SkipList.java b/java/17_skiplist/SkipList.java index 8e62c20f..a5f2dc5b 100644 --- a/java/17_skiplist/SkipList.java +++ b/java/17_skiplist/SkipList.java @@ -43,19 +43,22 @@ public void insert(int value) { update[i] = head; } + // record every level largest value which smaller than insert value in update[] Node p = head; for (int i = level - 1; i >= 0; --i) { while (p.forwards[i] != null && p.forwards[i].data < value) { p = p.forwards[i]; } - update[i] = p; + update[i] = p;// use update save node in search path } + // in search path node next node become new node forwords(next) for (int i = 0; i < level; ++i) { newNode.forwards[i] = update[i].forwards[i]; update[i].forwards[i] = newNode; } + // update node hight if (levelCount < level) levelCount = level; } @@ -78,7 +81,8 @@ public void delete(int value) { } } - private int randomLevel() { + // 随机 level 次,如果是奇数层数 +1,防止伪随机 + private int randomLevel() { int level = 1; for (int i = 1; i < MAX_LEVEL; ++i) { if (r.nextInt() % 2 == 1) { diff --git a/java/24_tree/BinarySearchTree.java b/java/24_tree/BinarySearchTree.java new file mode 100644 index 00000000..69850d11 --- /dev/null +++ b/java/24_tree/BinarySearchTree.java @@ -0,0 +1,99 @@ +public class BinarySearchTree { + private Node tree; + + public Node find(int data) { + Node p = tree; + while (p != null) { + if (data < p.data) p = p.left; + else if (data > p.data) p = p.right; + else return p; + } + return null; + } + + public void insert(int data) { + if (tree == null) { + tree = new Node(data); + return; + } + + Node p = tree; + while (p != null) { + if (data > p.data) { + if (p.right == null) { + p.right = new Node(data); + return; + } + p = p.right; + } else { // data < p.data + if (p.left == null) { + p.left = new Node(data); + return; + } + p = p.left; + } + } + } + + public void delete(int data) { + Node p = tree; // p指向要删除的节点,初始化指向根节点 + Node pp = null; // pp记录的是p的父节点 + while (p != null && p.data != data) { + pp = p; + if (data > p.data) p = p.right; + else p = p.left; + } + if (p == null) return; // 没有找到 + + // 要删除的节点有两个子节点 + if (p.left != null && p.right != null) { // 查找右子树中最小节点 + Node minP = p.right; + Node minPP = p; // minPP表示minP的父节点 + while (minP.left != null) { + minPP = minP; + minP = minP.left; + } + p.data = minP.data; // 将minP的数据替换到p中 + p = minP; // 下面就变成了删除minP了 + pp = minPP; + } + + // 删除节点是叶子节点或者仅有一个子节点 + Node child; // p的子节点 + if (p.left != null) child = p.left; + else if (p.right != null) child = p.right; + else child = null; + + if (pp == null) tree = child; // 删除的是根节点 + else if (pp.left == p) pp.left = child; + else pp.right = child; + } + + public Node findMin() { + if (tree == null) return null; + Node p = tree; + while (p.left != null) { + p = p.left; + } + return p; + } + + public Node findMax() { + if (tree == null) return null; + Node p = tree; + while (p.right != null) { + p = p.right; + } + return p; + } + + public static class Node { + private int data; + private Node left; + private Node right; + + public Node(int data) { + this.data = data; + } + } +} diff --git a/javascript/17_skiplist/SkipList.js b/javascript/17_skiplist/SkipList.js new file mode 100644 index 00000000..e123f71f --- /dev/null +++ b/javascript/17_skiplist/SkipList.js @@ -0,0 +1,95 @@ +/** + * author dreamapplehappy + * 关于代码的一些解释可以看一下这里:https://github.com/dreamapplehappy/blog/tree/master/2018/12/02 + */ + +const MAX_LEVEL = 16; + +class Node{ + data = -1; + maxLevel = 0; + refer = new Array(MAX_LEVEL); +} + +class SkipList{ + levelCount = 1; + head = new Node(); + + static randomLevel() { + let level = 1; + for(let i = 1; i < MAX_LEVEL; i++) { + if(Math.random() < 0.5) { + level++; + } + } + return level; + } + + insert(value) { + const level = SkipList.randomLevel(); + const newNode = new Node(); + newNode.data = value; + newNode.maxLevel = level; + const update = new Array(level).fill(new Node()); + let p = this.head; + for(let i = level - 1; i >= 0; i--) { + while(p.refer[i] !== undefined && p.refer[i].data < value) { + p = p.refer[i]; + } + update[i] = p; + } + for(let i = 0; i < level; i++) { + newNode.refer[i] = update[i].refer[i]; + update[i].refer[i] = newNode; + } + if(this.levelCount < level) { + this.levelCount = level; + } + } + + find(value) { + if(!value){return null} + let p = this.head; + for(let i = this.levelCount - 1; i >= 0; i--) { + while(p.refer[i] !== undefined && p.refer[i].data < value) { + p = p.refer[i]; + } + } + + if(p.refer[0] !== undefined && p.refer[0].data === value) { + return p.refer[0]; + } + return null; + } + + remove(value) { + let _node; + let p = this.head; + const update = new Array(new Node()); + for(let i = this.levelCount - 1; i >= 0; i--) { + while(p.refer[i] !== undefined && p.refer[i].data < value){ + p = p.refer[i]; + } + update[i] = p; + } + + if(p.refer[0] !== undefined && p.refer[0].data === value) { + _node = p.refer[0]; + for(let i = 0; i <= this.levelCount - 1; i++) { + if(update[i].refer[i] !== undefined && update[i].refer[i].data === value) { + update[i].refer[i] = update[i].refer[i].refer[i]; + } + } + return _node; + } + return null; + } + + printAll() { + let p = this.head; + while(p.refer[0] !== undefined) { + // console.log(p.refer[0].data) + p = p.refer[0]; + } + } +} diff --git a/javascript/18_hashmap/HashTable.html b/javascript/18_hashmap/HashTable.html new file mode 100644 index 00000000..de046069 --- /dev/null +++ b/javascript/18_hashmap/HashTable.html @@ -0,0 +1,61 @@ + + + + + Title + + + + + diff --git a/javascript/28_heapsort/heap-sort.js b/javascript/28_heapsort/heap-sort.js new file mode 100644 index 00000000..572ddf06 --- /dev/null +++ b/javascript/28_heapsort/heap-sort.js @@ -0,0 +1,65 @@ +/** + * 堆排序 + * + * Author: nameczz + */ + +// 忽视数组的第一位 +class HeapSort { + constructor(originArray) { + this.originArray = originArray + console.log(this.originArray) + } + buildHeap() { + const arr = this.originArray + const startIndex = Math.floor(arr.length) + for (let i = startIndex; i >= 1; i--) { + this.heapify(arr, arr.length, i) + } + return arr + } + + heapify(arr, len, i) { + while (true) { + let maxPos = i + // 如果index i拥有叶左节点 并且左节点较大 + if (i * 2 <= len && arr[i] < arr[i * 2]) { + maxPos = i * 2 + } + // 如果index i拥有叶右节点 与Max节点比较大小,选出父/左/右中最大的一个 + if (i * 2 + 1 <= len && arr[maxPos] < arr[i * 2 + 1]) { + maxPos = i * 2 + 1 + } + if (maxPos === i) break // 循环直到i节点为最大值 + this.swap(arr, i, maxPos) // 交换位置, 父节点为父/左/右中最大的一个 + i = maxPos // i为左/右节点,并尝试向下查找更大的值 + } + } + + sort() { + const arr = this.buildHeap() // 先建堆 + let len = arr.length - 1 + while (len > 1) { + this.swap(arr, 1, len) // 交换顶元素和最后一位。顶元素永远是最大的。 + len-- + this.heapify(arr, len, 1) //剩下的元素重新建堆 直到len === 1 停止 + } + console.log(arr) + } + + swap(arr, i, max) { + let temp = arr[i] + arr[i] = arr[max] + arr[max] = temp + } +} + +const arr = [null] +let i = 0 +while (i <= 10) { + const num = Math.floor(Math.random() * 100) + arr.push(num) + i++ +} +const testHeap = new HeapSort(arr) +testHeap.sort() \ No newline at end of file diff --git a/notes/18_hashtable/.gitkeep b/notes/18_hashtable/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/notes/18_hashtable/readme.md b/notes/18_hashtable/readme.md new file mode 100644 index 00000000..f7092093 --- /dev/null +++ b/notes/18_hashtable/readme.md @@ -0,0 +1,69 @@ +# 散列表 + +散列表是数组的一种扩展,利用数组下标的随机访问特性。 + +## 散列思想 + +* 键/关键字/Key:用来标识一个数据 +* 散列函数/哈希函数/Hash:将 Key 映射到数组下标的函数 +* 散列值/哈希值:Key 经过散列函数得到的数值 + +![](https://static001.geekbang.org/resource/image/92/73/92c89a57e21f49d2f14f4424343a2773.jpg) + +本质:利用散列函数将关键字映射到数组下标,而后利用数组随机访问时间复杂度为 $\Theta(1)$ 的特性快速访问。 + +## 散列函数 + +* 形式:`hash(key)` +* 基本要求 + 1. 散列值是非负整数 + 1. 如果 `key1 == key2`,那么 `hash(key1) == hash(key2)` + 1. 如果 `key1 != key2`,那么 `hash(key1) != hash(key2)` + +第 3 个要求,实际上不可能对任意的 `key1` 和 `key2` 都成立。因为通常散列函数的输出范围有限而输入范围无限。 + +## 散列冲突¡ + +* 散列冲突:`key1 != key2` 但 `hash(key1) == hash(key2)` + +散列冲突会导致不同键值映射到散列表的同一个位置。为此,我们需要解决散列冲突带来的问题。 + +### 开放寻址法 + +如果遇到冲突,那就继续寻找下一个空闲的槽位。 + +#### 线性探测 + +插入时,如果遇到冲突,那就依次往下寻找下一个空闲的槽位。(橙色表示已被占用的槽位,黄色表示空闲槽位) + +![](https://static001.geekbang.org/resource/image/5c/d5/5c31a3127cbc00f0c63409bbe1fbd0d5.jpg) + +查找时,如果目标槽位上不是目标数据,则依次往下寻找;直至遇见目标数据或空槽位。 + +![](https://static001.geekbang.org/resource/image/91/ff/9126b0d33476777e7371b96e676e90ff.jpg) + +删除时,标记为 `deleted`,而不是直接删除。 + +#### 平方探测(Quadratic probing) + +插入时,如果遇到冲突,那就往后寻找下一个空闲的槽位,其步长为 $1^2$, $2^2$, $3^2$, $\ldots$。 + +查找时,如果目标槽位上不是目标数据,则依次往下寻找,其步长为 $1^2$, $2^2$, $3^2$, $\ldots$;直至遇见目标数据或空槽位。 + +删除时,标记为 `deleted`,而不是直接删除。 + +#### 装载因子(load factor) + +$\text{load factor} = \frac{size()}{capacity()}$ + +### 链表法 + +所有散列值相同的 key 以链表的形式存储在同一个槽位中。 + +![](https://static001.geekbang.org/resource/image/a4/7f/a4b77d593e4cb76acb2b0689294ec17f.jpg) + +插入时,不论是否有冲突,直接插入目标位置的链表。 + +查找时,遍历目标位置的链表来查询。 + +删除时,遍历目标位置的链表来删除。 diff --git a/notes/19_hashtable/.gitkeep b/notes/19_hashtable/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/notes/19_hashtable/readme.md b/notes/19_hashtable/readme.md new file mode 100644 index 00000000..d530c058 --- /dev/null +++ b/notes/19_hashtable/readme.md @@ -0,0 +1,59 @@ +# 散列表 + +核心:散列表的效率并不总是 $O(1)$,仅仅是在理论上能达到 $O(1)$。实际情况中,恶意攻击者可以通过精心构造数据,使得散列表的性能急剧下降。 + +如何设计一个工业级的散列表? + +## 散列函数 + +* 不能过于复杂——避免散列过程耗时 +* 散列函数的结果要尽可能均匀——最小化散列冲突 + +## 装载因子过大怎么办 + +动态扩容。涉及到 rehash,效率可能很低。 + +![](https://static001.geekbang.org/resource/image/67/43/67d12e07a7d673a9c1d14354ad029443.jpg) + +如何避免低效扩容? + +——将 rehash 的步骤,均摊到每一次插入中去: + +* 申请新的空间 +* 不立即使用 +* 每次来了新的数据,往新表插入数据 +* 同时,取出旧表的一个数据,插入新表 + +![](https://static001.geekbang.org/resource/image/6d/cb/6d6736f986ec4b75dabc5472965fb9cb.jpg) + +## 解决冲突 + +开放寻址法,优点: + +* 不需要额外空间 +* 有效利用 CPU 缓存 +* 方便序列化 + +开放寻址法,缺点: + +* 查找、删除数据时,涉及到 `delete` 标志,相对麻烦 +* 冲突的代价更高 +* 对装载因子敏感 + +链表法,优点: + +* 内存利用率较高——链表的优点 +* 对装载因子不敏感 + +链表法,缺点: + +* 需要额外的空间(保存指针) +* 对 CPU 缓存不友好 + +——将链表改造成更高效的数据结构,例如跳表、红黑树 + +## 举个栗子(JAVA 中的 HashMap) + +* 初始大小:16 +* 装载因子:超过 0.75 时动态扩容 +* 散列冲突:优化版的链表法(当槽位冲突元素超过 8 时使用红黑树,否则使用链表) diff --git a/object-c/33_bm_match/BM.h b/object-c/33_bm_match/BM.h new file mode 100644 index 00000000..0b1f9f49 --- /dev/null +++ b/object-c/33_bm_match/BM.h @@ -0,0 +1,19 @@ +// +// BM.h +// BM-Match +// +// Created by Smallfly on 2018/12/9. +// Copyright © 2018 Smallfly. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface BM : NSObject +- (instancetype)initWithA:(NSString *)a andB:(NSString *)b; +- (NSInteger)startMatch; +- (void)startMatchCompeletion:(void (^)(NSInteger))completion; +@end + +NS_ASSUME_NONNULL_END diff --git a/object-c/33_bm_match/BM.m b/object-c/33_bm_match/BM.m new file mode 100644 index 00000000..4c42e62b --- /dev/null +++ b/object-c/33_bm_match/BM.m @@ -0,0 +1,131 @@ +// +// BM.m +// BM-Match +// +// Created by Smallfly on 2018/12/9. +// Copyright © 2018 Smallfly. All rights reserved. +// + +#import "BM.h" + +#define SIZE 256 + +@interface BM() +@property (nonatomic, strong) NSString *a; // 主串 +@property (nonatomic, strong) NSString *b; // 匹配串 + +@property (nonatomic, strong) NSMutableArray *bc; // 匹配串,哈希表,存储字符在匹配串中的下标 + +@property (nonatomic, strong) NSMutableArray *suffix; +@property (nonatomic, strong) NSMutableArray *prifix; + +@end + +@implementation BM + +- (instancetype)initWithA:(NSString *)a andB:(NSString *)b { + self = [super init]; + if (!self) return nil; + _a = a; + _b = b; + _bc = [NSMutableArray new]; + _suffix = [NSMutableArray new]; + _prifix = [NSMutableArray new]; + [self generateBC]; + [self generateGS]; + return self; +} + +// 构建坏字符哈希表,记录每个字符在匹配串中最后出现的位置 +- (void)generateBC { + for (int i = 0; i < SIZE; ++i) { + [_bc addObject:@-1]; + } + for (int i = 0; i < _b.length; ++i) { + int ascii = (int)[_b characterAtIndex:i]; // char to ASCII + _bc[ascii] = [NSNumber numberWithInteger:i]; // save b's char index + } +} + +- (NSInteger)bm { + NSInteger i = 0; // 主串和匹配串对齐的第一个字符 + NSUInteger n = _a.length; + NSUInteger m = _b.length; + while (i <= n - m) { + NSInteger j; + // 从后往前匹配 + for (j = m - 1; j >= 0; --j) { + int aValue = (int)[_a characterAtIndex:(i + j)]; + int bValue = (int)[_b characterAtIndex:j]; + if (aValue != bValue) break; // 找到坏字符下标 j 停止 + } + if (j < 0) { + return i; // 匹配成功,返回所在的位置 + } + + // 坏字符在匹配串中最后出现的位置 + id numberInHashTableBC = _bc[(int)[_a characterAtIndex:(i + j)]]; + NSInteger x = j - [numberInHashTableBC integerValue]; + NSInteger y = 0; + if (j < m - 1) { + y = [self moveByGSBy:j]; + } + i = i + MAX(x, y); + + // 这一步比较难理解,不直接滑到过 j,是因为在 j 之前可能存在于坏字符相同的字符 + // 这个于坏字符相同的字符,在匹配串中的最大下标是 numberInHashTableBC +// i = i + (j - [numberInHashTableBC integerValue]); + } + + return -1; +} + +// 好后缀匹配移动 +- (NSInteger)moveByGSBy:(NSInteger)j { + NSUInteger m = _b.length; + NSInteger k = m - 1 - j; // 好后缀的长度 + NSInteger t = [_suffix[k] integerValue]; + if (t != -1) return j - t + 1; // 匹配串的前缀,是否匹配好后缀,关键 + for (NSInteger r = j+1; r <= m-1; ++r) { + if ([_prifix[m-r] boolValue]) { // 关键 + return r; + } + } + return m; +} + +- (void)generateGS { + NSUInteger m = _b.length; + for (NSInteger i = 0; i < m; ++i) { + _prifix[i] = @(NO); + _suffix[i] = @(-1); + } + for (NSInteger i = 0; i < m - 1; ++i) { // 从 b 中取两个字符对比 + NSInteger j = i; + NSInteger k = 0; // 公共后缀的长度 + int jValue = (int)[_b characterAtIndex:j]; + int bmValue = (int)[_b characterAtIndex:(m-1-k)]; + while (j >= 0 && jValue == bmValue) { // 与 b[0, m-1] 求公共子串 + ++k; + --j; + _suffix[k] = [NSNumber numberWithInteger:(j+1)]; //j+1 代表公共子串在 b 中的起始下标 + } + if (j == -1) _prifix[k] = @(YES); + } +} + +#pragma mark - + +// 同步 +- (NSInteger)startMatch { + return [self bm]; +} + +// 异步 +- (void)startMatchCompeletion:(void (^)(NSInteger))completion { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + completion([self bm]); + }); +} + +@end diff --git a/object-c/33_bm_match/main.m b/object-c/33_bm_match/main.m new file mode 100644 index 00000000..ebddc71a --- /dev/null +++ b/object-c/33_bm_match/main.m @@ -0,0 +1,23 @@ +// +// main.m +// BM-Match +// +// Created by Smallfly on 2018/12/9. +// Copyright © 2018 Smallfly. All rights reserved. +// + +#import +#import "BM.h" + +int main(int argc, const char * argv[]) { + @autoreleasepool { + BM *bm = [[BM alloc] initWithA:@"abacadc" andB:@"adc"]; + + [bm startMatchCompeletion:^(NSInteger index) { + NSLog(@"异步查找到下标:%ld\n", index); + }]; + + NSLog(@"同步查找到下标:%ld\n", [bm startMatch]); + } + return 0; +} diff --git a/php/08_stack/Compute.php b/php/08_stack/Compute.php index 7e0a3379..d9b8eb42 100644 --- a/php/08_stack/Compute.php +++ b/php/08_stack/Compute.php @@ -28,8 +28,6 @@ function expression($str) array_push($operStack, $arr[$i]); break; case '*': -<<<<<<< HEAD -======= $arrLen = count($operStack); while ($operStack[$arrLen-1] === '/'){ compute($numStack, $operStack); @@ -38,7 +36,6 @@ function expression($str) array_push($operStack, $arr[$i]); break; ->>>>>>> upstream/master case '/': case '(': array_push($operStack, $arr[$i]); @@ -81,13 +78,9 @@ function compute(&$numStack, &$operStack){ case '-': array_push($numStack, array_pop($numStack) - $num); break; -<<<<<<< HEAD - -======= case '(': throw new \Exception("不匹配的(", 2); break; ->>>>>>> upstream/master } } expression('-1+2-(1+2*3)'); diff --git a/php/13_sort/bucketSort.php b/php/13_sort/bucketSort.php new file mode 100644 index 00000000..5b59a86b --- /dev/null +++ b/php/13_sort/bucketSort.php @@ -0,0 +1,50 @@ + $value) { + $index = ceil(($value-$min)/$length); + $buckets[$index][] = $value; + } + + $result = []; + for($i=0;$i<$bucketNumber;$i++) { + $bucket = $buckets[$i]; + $length = count($bucket); + //如果桶内元素为空,跳过这个桶 + if($length == 0) { + continue; + } + if( $length > 10) { + $bucket = bucketSort($bucket,$length); + } + + quickSort($bucket,0,count($bucket)-1); + $result = array_merge($result,$bucket); + } + return $result; +} + diff --git a/php/13_sort/countingSort.php b/php/13_sort/countingSort.php new file mode 100644 index 00000000..edef0b89 --- /dev/null +++ b/php/13_sort/countingSort.php @@ -0,0 +1,43 @@ + $value) { + $countScore[$value]++; + } + + /** + * 顺序求和 + */ + for($i=1;$i<=5;$i++) { + $countScore[$i] += $countScore[$i-1]; + } + /** + * 排序 + */ + foreach ($score as $key => $value) { + $countScore[$value] --; + $temp[$countScore[$value]] = $value; + } + //copy + for($i=0;$i<$length;$i++) { + $score[$i] = $temp[$i]; + } + return $score; +} \ No newline at end of file diff --git a/php/13_sort/radixSort.php b/php/13_sort/radixSort.php new file mode 100644 index 00000000..3f4164be --- /dev/null +++ b/php/13_sort/radixSort.php @@ -0,0 +1,48 @@ +toArray(); + foreach ($numbers as $key => $value) { + $index = ($value/$divisor)%10;//计算该数字在哪个桶中 + $buckets[$index][] = $value; + } + /** + * 从桶中取出数字 + */ + $k=0; + for($i=0;$i<10;$i++) { + while(count($buckets[$i]) > 0) { + $numbers[$k++] = array_shift($buckets[$i]); + } + } +} diff --git a/php/15_binary/binary.php b/php/15_binary/binary.php new file mode 100644 index 00000000..e5084518 --- /dev/null +++ b/php/15_binary/binary.php @@ -0,0 +1,98 @@ + $high) { + return -1; + } + + /** + * notice2 mid计算 + */ + $mid = $low + (($high - $low) >> 1); + if ($numbers[$mid] > $find) { + //notice3 high值更新 + return search($numbers, $low, $mid -1, $find); + } elseif ($numbers[$mid] < $find) { + //notice4 low值更新 + return search($numbers, $mid + 1, $high, $find); + } else { + return $mid; + } +} + +/** + * 求数字的平方根,保留6位小数 + * @param [type] $number + * + * @return void + * @date 2018/11/26 + * @author yuanliandu + */ +function squareRoot($number) +{ + if ($number < 0) { + return -1; + } elseif ($number < 1) { + $min = $number; + $max = 1; + } else { + $min = 1; + $max = $number; + } + $mid = $min + ($max - $min) / 2; + while (getDecimalPlaces($mid) < 6) { + $square = $mid * $mid; + if ($square > $number) { + $max = $mid; + } elseif ($square == $number) { + return $mid; + } else { + $min = $mid; + } + $mid = $min + ($max - $min) / 2; + } + return $mid; +} + +/** + * 计算数字小数点后有几位数字 + * @param [type] $number + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function getDecimalPlaces($number) +{ + $temp = explode('.', $number); + return strlen($temp[1]); +} + +// 测试二分查找给定值 +$numbers = [0, 1, 2, 3, 3, 4, 5, 6, 7, 9]; +$find = 1; +var_dump(binarySearch($numbers,$find)); + +//测试求平方根 +var_dump(squareRoot(3)); \ No newline at end of file diff --git a/php/16_binary/binary.php b/php/16_binary/binary.php new file mode 100644 index 00000000..fc27a4cb --- /dev/null +++ b/php/16_binary/binary.php @@ -0,0 +1,191 @@ + + */ +function findFirstEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] > $find) { + $high = $mid - 1; + }else if($numbers[$mid] < $find) { + $low = $mid + 1; + }else { + /** + * 如果是第一个元素,或之前一个元素不等于我们要找的值 + * 我们就找到了第一个=find的element + */ + if($mid==0 || $numbers[$mid-1]!=$find) { + return $mid; + }else { + $high = $mid - 1; + } + } + } + + return -1; +} + +/** + * 找到最后一个=find的元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function findLastEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] > $find) { + $high = $mid - 1; + }else if($numbers[$mid] < $find) { + $low = $mid + 1; + }else { + /** + * 如果mid是最后一个元素的index + * 或mid后一个元素!=我们要找的值 + * 则找到了最后一个=find的value + */ + if($mid==$length-1 || $numbers[$mid+1]!=$find) { + return $mid; + }else { + $low = $mid + 1; + } + } + } + + return -1; +} + +/** + * 找到第一个大于等于find的元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function findFirstGreaterEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] >= $find) { + if ($mid == 0 || $numbers[$mid-1] < $find) { + return $mid; + }else { + $high = $mid - 1; + } + }else { + $low = $mid + 1; + } + } + return -1; +} + +/** + * 找到最后一个小于等于find的元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function findLastLessEqual(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] <= $find) { + if($mid==$length-1 || $numbers[$mid+1]> $find) { + return $mid; + } + $low = $mid + 1; + }else { + $high = $mid - 1; + } + } + return -1; +} + + + + + +/** + * 循环数组中找指定元素 + * @param array $numbers + * @param [type] $find + * + * @return void + * @date 2018/11/27 + * @author yuanliandu + */ +function searchCircularArray(array $numbers,$find) { + $length = count($numbers); + $low = 0; + $high = $length - 1; + + while($low <= $high) { + $mid = $low + (($high-$low)>>1); + if($numbers[$mid] === $find) { + return $mid; + } + + if($numbers[$low] > $numbers[$mid]) { + // 后半部分是有序数组 + if(($numbers[$mid] < $find) && ($numbers[$high] >= $find)) { + if($numbers[$high] === $find) return $high; + //在后半个区间内 + $low = $mid + 1; + }else { + $high = $mid - 1; + } + }else { + // 前半部分是有序的 + if(($numbers[$low] <= $find) && ($numbers[$mid] > $find)) { + // 在有序区间内 + if($numbers[$low] === $find) return $low; + $high = $mid - 1; + }else { + $low = $mid + 1; + } + } + + } + return -1; +} + +/*** + * 测试 + */ +$numbers = [1,2,3,3,3,4,5,6,8,11,13]; +$find = 3; + +var_dump(findFirstEqual($numbers,$find));//找到第一个等于find的元素 +var_dump(findFirstGreaterEqual($numbers,$find));//找到第一个大于等于find的元素 +var_dump(findLastEqual($numbers,$find));//找到最后一个=find的元素 +var_dump(findLastLessEqual($numbers,$find));//找到最后一个小于等于find的元素 + + +//测试在循环数组中找到指定数字 +$numbers = [9,10,1,2,3,4,5,6,7,8]; +$find = 2; +var_dump(searchCircularArray($numbers,$find)); diff --git a/php/README.md b/php/README.md index 6e3a2773..aabcd3ce 100644 --- a/php/README.md +++ b/php/README.md @@ -17,11 +17,7 @@ * findMiddleNode 求链表的中间结点 #### 08_stack -<<<<<<< HEAD -* 链栈实现 -======= * 链栈实现 #### 09_stack * 队列链表实现 ->>>>>>> upstream/master diff --git a/php/composer.json b/php/composer.json index 12bea697..eef8f49f 100644 --- a/php/composer.json +++ b/php/composer.json @@ -7,12 +7,8 @@ "psr-4": { "Algo_06\\": "06_linkedlist/", "Algo_07\\": "07_linkedlist/", -<<<<<<< HEAD - "Algo_08\\": "08_stack/" -======= "Algo_08\\": "08_stack/", "Algo_09\\": "09_queue/" ->>>>>>> upstream/master } } } diff --git a/python/05_array/myarray.py b/python/05_array/myarray.py index 6ff05629..f85a33b2 100644 --- a/python/05_array/myarray.py +++ b/python/05_array/myarray.py @@ -1,4 +1,6 @@ from typing import Optional + + # # 1) Insertion, deletion and random access of array # 2) Assumes int for element type @@ -15,7 +17,7 @@ def __init__(self, capacity: int): self._data = [] self._count = 0 self._capacity = capacity - + def __getitem__(self, position: int) -> int: """Support for subscript. @@ -25,45 +27,75 @@ def __getitem__(self, position: int) -> int: def find(self, index: int) -> Optional[int]: - if index >= self._count or index <= -self._count: return None + if index >= self._count or index <= -self._count: + return None return self._data[index] def delete(self, index: int) -> bool: - - if index >= self._count or index <= -self._count: return False - - self._data[index:-1] = self._data[index+1:] + + if index >= self._count or index <= -self._count: + return False + + self._data[index:-1] = self._data[index + 1:] self._count -= 1 # 真正将数据删除并覆盖原来的数据 ,这个需要增加 self._data = self._data[0:self._count] - print ('delet function',self._data) + print('delete function', self._data) return True def insert(self, index: int, value: int) -> bool: - #if index >= self._count or index <= -self._count: return False - if self._capacity == self._count: return False + # if index >= self._count or index <= -self._count: return False + if self._capacity == self._count: + return False # 如果还有空间,那么插入位置大于当前的元素个数,可以插入最后的位置 if index >= self._count: self._data.append(value) # 同上,如果位置小于0 可以插入第0个位置. if index < 0: - print (index) + print(index) self._data.insert(0, value) self._count += 1 return True + def insert_v2(self, index: int, value: int) -> bool: + """ + 支持任意位置插入 + :param index: + :param value: + :return: + """ + # 数组空间已满 + if self._capacity == self._count: + return False + + # 插入位置大于当前的元素个数,可以插入最后的位置 + if index >= self._count: + self._data.append(value) + elif index < 0: + # 位置小于 0 可以插入第 0 个位置 + self._data.insert(0, value) + else: + # 挪动 index 至 _count 位到 index+1 至 _count+1 位 + # 插入第 index + self._data[index+1:self._count+1] = self._data[index:self._count] + self._data[index] = value + + self._count += 1 + return True + def insert_to_tail(self, value: int) -> bool: - if self._count == self._capacity: return False + if self._count == self._capacity: + return False if self._count == len(self._data): - self._data.append(value) + self._data.append(value) else: self._data[self._count] = value self._count += 1 return True - + def __repr__(self) -> str: return " ".join(str(num) for num in self._data[:self._count]) @@ -71,25 +103,31 @@ def __repr__(self) -> str: def print_all(self): for num in self._data[:self._count]: - print("{num}", end=" ") + print(f"{num}", end=" ") print("\n", flush=True) + +def test_myarray(): + array_a = MyArray(6) + for num in range(6): + array_a.insert_to_tail(num) + assert array_a.find(0) == 0 + assert array_a[0] == 0 + array_a.delete(0) + assert array_a[0] == 1 + + if __name__ == "__main__": a = MyArray(6) for i in range(6): a.insert_to_tail(i) - -<<<<<<< HEAD a.delete(2) print(a) a.insert_to_tail(7) print(a) -======= - print('origin',a) + print('origin', a) a.delete(4) - print ('delete ',a) + print('delete ', a) - a.insert(100,10000) - print (a) - ->>>>>>> upstream/master + a.insert(100, 10000) + print(a) diff --git a/python/06_linkedlist/singlyLinkedList.py b/python/06_linkedlist/singlyLinkedList.py new file mode 100644 index 00000000..030434f5 --- /dev/null +++ b/python/06_linkedlist/singlyLinkedList.py @@ -0,0 +1,284 @@ +# 1.单链表的插入、删除、查找操作; +# 2.链表中存储的数据类型是Int +# +# Author:Lee + +class Node(): + '''链表结构的Node节点''' + + def __init__(self, data, next=None): + '''Node节点的初始化方法. + 参数: + data:存储的数据 + next:下一个Node节点的引用地址 + ''' + self.__data = data + self.__next = next + + @property + def data(self): + '''Node节点存储数据的获取. + 返回: + 当前Node节点存储的数据 + ''' + return self.__data + + @data.setter + def data(self, data): + '''Node节点存储数据的设置方法. + 参数: + data:新的存储数据 + ''' + self.__data = data + + @property + def next(self): + '''获取Node节点的next指针值. + 返回: + next指针数据 + ''' + return self.__next + + @next.setter + def next(self, next): + '''Node节点next指针的修改方法. + 参数: + next:新的下一个Node节点的引用 + ''' + self.__next = next + + +class SinglyLinkedList(): + '''单向链表''' + + def __init__(self): + '''单向列表的初始化方法.''' + self.__head = None + + def find_by_value(self, value): + '''按照数据值在单向列表中查找. + 参数: + value:查找的数据 + 返回: + Node + ''' + node = self.__head + if node != None and node.data != value: + node = node.next + else: + return node + + def find_by_index(self, index): + '''按照索引值在列表中查找. + 参数: + index:索引值 + 返回: + Node + ''' + node = self.__head + pos = 0 + while node != None and pos != index: + node = node.next + pos += 1 + return node + + def insert_to_head(self, value): + '''在链表的头部插入一个存储value数值的Node节点. + 参数: + value:将要存储的数据 + ''' + node = Node(value) + node.next = self.__head + self.__head = node + + def insert_after(self, node, value): + '''在链表的某个指定Node节点之后插入一个存储value数据的Node节点. + 参数: + node:指定的一个Node节点 + value:将要存储在新Node节点中的数据 + ''' + if node == None: # 如果指定在一个空节点之后插入数据节点,则什么都不做 + return + + new_node = Node(value) + new_node.next = node.next + node.next = new_node + + def insert_before(self, node, value): + '''在链表的某个指定Node节点之前插入一个存储value数据的Node节点. + 参数: + node:指定的一个Node节点 + value:将要存储在新的Node节点中的数据 + ''' + if node == None or self.__head == None: # 如果指定在一个空节点之前或者空链表之前插入数据节点,则什么都不做 + return + + if node == self.__head: # 如果是在链表头之前插入数据节点,则直接插入 + self.insert_to_head(value) + return + + new_node = Node(value) + pro = self.__head + not_found = False # 如果在整个链表中都没有找到指定插入的Node节点,则该标记量设置为True + while pro.next != node: # 寻找指定Node之前的一个Node + if pro.next == None: # 如果已经到了链表的最后一个节点,则表明该链表中没有找到指定插入的Node节点 + not_found = True + break + else: + pro = pro.next + if not_found == False: + pro.next = new_node + new_node.next = node + + def delete_by_node(self, node): + '''在链表中删除指定Node的节点. + 参数: + node:指定的Node节点 + ''' + if self.__head == None: # 如果链表是空的,则什么都不做 + return + + if node == self.__head: # 如果指定删除的Node节点是链表的头节点 + self.__head = node.next + return + + pro = self.__head + not_found = False # 如果在整个链表中都没有找到指定删除的Node节点,则该标记量设置为True + while pro.next != node: + if pro.next == None: # 如果已经到链表的最后一个节点,则表明该链表中没有找到指定删除的Node节点 + not_found == True + break + else: + pro = pro.next + if not_found == False: + pro.next = node.next + + def delete_by_value(self, value): + '''在链表中删除指定存储数据的Node节点. + 参数: + value:指定的存储数据 + ''' + if self.__head == None: # 如果链表是空的,则什么都不做 + return + + if self.__head.data == value: # 如果链表的头Node节点就是指定删除的Node节点 + self.__head = self.__head.next + + pro = self.__head + node = self.__head.next + not_found = False + while node.data != value: + if node.next == None: # 如果已经到链表的最后一个节点,则表明该链表中没有找到执行Value值的Node节点 + not_found == True + break + else: + pro = node + node = node.next + if not_found == False: + pro.next = node.next + + def delete_last_N_node(self, n): + '''删除链表中倒数第N个节点. + 主体思路: + 设置快、慢两个指针,快指针先行,慢指针不动;当快指针跨了N步以后,快、慢指针同时往链表尾部移动, + 当快指针到达链表尾部的时候,慢指针所指向的就是链表的倒数第N个节点 + 参数: + n:需要删除的倒数第N个序数 + ''' + fast = self.__head + slow = self.__head + step = 0 + + while step <= n: + fast = fast.next + step += 1 + + while fast.next != None: + tmp = slow + fast = fast.next + slow = slow.next + + tmp.next = slow.next + + def find_mid_node(self): + '''查找链表中的中间节点. + 主体思想: + 设置快、慢两种指针,快指针每次跨两步,慢指针每次跨一步,则当快指针到达链表尾部的时候,慢指针指向链表的中间节点 + 返回: + node:链表的中间节点 + ''' + fast = self.__head + slow = self.__head + + while fast.next != None: + fast = fast.next.next + slow = slow.next + + return slow + + def create_node(self, value): + '''创建一个存储value值的Node节点. + 参数: + value:将要存储在Node节点中的数据 + 返回: + 一个新的Node节点 + ''' + return Node(value) + + def print_all(self): + '''打印当前链表所有节点数据.''' + pos = self.__head + if pos == None: + print('当前链表还没有数据') + return + while pos.next != None: + print(str(pos.data) + ' --> ', end='') + pos = pos.next + print(str(pos.data)) + + def reversed_self(self): + '''翻转链表自身.''' + if self.__head == None or self.__head.next == None: # 如果链表为空,或者链表只有一个节点 + return + + pre = self.__head + node = self.__head.next + while node != None: + pre, node = self.__reversed_with_two_node(pre, node) + + self.__head.next = None + self.__head = pre + + def __reversed_with_two_node(self, pre, node): + '''翻转相邻两个节点. + 参数: + pre:前一个节点 + node:当前节点 + 返回: + (pre,node):下一个相邻节点的元组 + ''' + tmp = node.next + node.next = pre + pre = node # 这样写有点啰嗦,但是能让人更能看明白 + node = tmp + return (pre, node) + + def has_ring(self): + '''检查链表中是否有环. + 主体思想: + 设置快、慢两种指针,快指针每次跨两步,慢指针每次跨一步,如果快指针没有与慢指针相遇而是顺利到达链表尾部 + 说明没有环;否则,存在环 + 返回: + True:有环 + False:没有环 + ''' + fast = self.__head + slow = self.__head + + while fast.next != None and fast != None: + fast = fast.next + slow = slow.next + if fast == slow: + return True + + return False diff --git a/python/06_linkedlist/singly_linked_list.py b/python/06_linkedlist/singly_linked_list.py index f5565f39..4c31f05e 100644 --- a/python/06_linkedlist/singly_linked_list.py +++ b/python/06_linkedlist/singly_linked_list.py @@ -6,23 +6,23 @@ """ from typing import Optional + class Node: - - def __init__(self, data: int, next=None): + + def __init__(self, data: int, next_node=None): self.data = data - self._next = next - + self._next = next_node + class SinglyLinkedList: def __init__(self): self._head = None - + def find_by_value(self, value: int) -> Optional[Node]: p = self._head while p and p.data != value: p = p._next - return p def find_by_index(self, index: int) -> Optional[Node]: @@ -31,22 +31,21 @@ def find_by_index(self, index: int) -> Optional[Node]: while p and position != index: p = p._next position += 1 - return p def insert_value_to_head(self, value: int): new_node = Node(value) self.insert_node_to_head(new_node) - + def insert_node_to_head(self, new_node: Node): if new_node: new_node._next = self._head self._head = new_node - + def insert_value_after(self, node: Node, value: int): new_node = Node(value) self.insert_node_after(node, new_node) - + def insert_node_after(self, node: Node, new_node: Node): if not node or not new_node: return @@ -66,7 +65,7 @@ def insert_node_before(self, node: Node, new_node: Node): current = self._head while current._next and current._next != node: current = current._next - if not current._next: # node is not even in the list + if not current._next: # node is not even in the list return new_node._next = node current._next = new_node @@ -83,13 +82,13 @@ def delete_by_node(self, node: Node): while current and current._next != node: current = current._next if not current: # node not in the list - return + return current._next = None def delete_by_value(self, value: int): if not self._head or not value: return - fake_head = Node(value+1) + fake_head = Node(value + 1) fake_head._next = self._head prev, current = fake_head, self._head while current: @@ -100,7 +99,7 @@ def delete_by_value(self, value: int): if prev._next: prev._next = None self._head = fake_head._next # in case head.data == value - + def __repr__(self) -> str: nums = [] current = self._head @@ -112,6 +111,13 @@ def __repr__(self) -> str: else: return "" + # 重写__iter__方法,方便for关键字调用打印值 + def __iter__(self): + node = self._head + while node: + yield node.data + node = node._next + def print_all(self): current = self._head if current: @@ -136,4 +142,6 @@ def print_all(self): l.delete_by_node(node11) l.delete_by_node(l._head) l.delete_by_value(13) - print(l) \ No newline at end of file + print(l) + for value in l: + print(value) diff --git a/python/11_sorts/sorts.py b/python/11_sorts/sorts.py index 127a6475..aed133e5 100644 --- a/python/11_sorts/sorts.py +++ b/python/11_sorts/sorts.py @@ -7,94 +7,99 @@ from typing import List + # 冒泡排序 def bubble_sort(a: List[int]): - if len(a) <= 1: return - -<<<<<<< HEAD - made_swap = False - for i in range(len(a)): -======= - for i in range(len(a)): + length = len(a) + if length <= 1: + return + + for i in range(length): made_swap = False ->>>>>>> upstream/master - for j in range(len(a) - i - 1): - if a[j] > a[j+1]: - a[j], a[j+1] = a[j+1], a[j] + for j in range(length - i - 1): + if a[j] > a[j + 1]: + a[j], a[j + 1] = a[j + 1], a[j] made_swap = True - if not made_swap: break + if not made_swap: + break + # 插入排序 def insertion_sort(a: List[int]): - if len(a) <= 1: return - - for i in range(1, len(a)): + length = len(a) + if length <= 1: + return + + for i in range(1, length): value = a[i] j = i - 1 while j >= 0 and a[j] > value: - a[j+1] = a[j] + a[j + 1] = a[j] j -= 1 - a[j+1] = value + a[j + 1] = value + # 选择排序 def selection_sort(a: List[int]): - if len(a) <= 1: return - - for i in range(len(a)): + length = len(a) + if length <= 1: + return + + for i in range(length): min_index = i min_val = a[i] - for j in range(i, len(a)): + for j in range(i, length): if a[j] < min_val: min_val = a[j] min_index = j a[i], a[min_index] = a[min_index], a[i] -if __name__ == "__main__": - array = [1, 1, 1, 1] - bubble_sort(array) - print(array) +def test_bubble_sort(): + test_array = [1, 1, 1, 1] + bubble_sort(test_array) + assert test_array == [1, 1, 1, 1] + test_array = [4, 1, 2, 3] + bubble_sort(test_array) + assert test_array == [1, 2, 3, 4] + test_array = [4, 3, 2, 1] + bubble_sort(test_array) + assert test_array == [1, 2, 3, 4] + + +def test_insertion_sort(): + test_array = [1, 1, 1, 1] + insertion_sort(test_array) + assert test_array == [1, 1, 1, 1] + test_array = [4, 1, 2, 3] + insertion_sort(test_array) + assert test_array == [1, 2, 3, 4] + test_array = [4, 3, 2, 1] + insertion_sort(test_array) + assert test_array == [1, 2, 3, 4] + + +def test_selection_sort(): + test_array = [1, 1, 1, 1] + selection_sort(test_array) + assert test_array == [1, 1, 1, 1] + test_array = [4, 1, 2, 3] + selection_sort(test_array) + assert test_array == [1, 2, 3, 4] + test_array = [4, 3, 2, 1] + selection_sort(test_array) + assert test_array == [1, 2, 3, 4] - array = [1, 2, 3, 4] - bubble_sort(array) - print(array) - - array = [4, 3, 2, 1] - bubble_sort(array) - print(array) +if __name__ == "__main__": array = [5, 6, -1, 4, 2, 8, 10, 7, 6] bubble_sort(array) print(array) - array = [1, 1, 1, 1] - insertion_sort(array) - print(array) - - array = [1, 2, 3, 4] - insertion_sort(array) - print(array) - - array = [4, 3, 2, 1] - insertion_sort(array) - print(array) - array = [5, 6, -1, 4, 2, 8, 10, 7, 6] insertion_sort(array) print(array) - array = [1, 1, 1, 1] - selection_sort(array) - print(array) - - array = [1, 2, 3, 4] - selection_sort(array) - print(array) - - array = [4, 3, 2, 1] - selection_sort(array) - print(array) - array = [5, 6, -1, 4, 2, 8, 10, 7, 6] selection_sort(array) - print(array) \ No newline at end of file + print(array) diff --git a/python/23_binarytree/binary_search_tree.py b/python/23_binarytree/binary_search_tree.py new file mode 100644 index 00000000..5500c5c7 --- /dev/null +++ b/python/23_binarytree/binary_search_tree.py @@ -0,0 +1,292 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from queue import Queue +import math + + +class TreeNode: + def __init__(self, val=None): + self.val = val + self.left = None + self.right = None + self.parent = None + + +class BinarySearchTree: + def __init__(self, val_list=[]): + self.root = None + for n in val_list: + self.insert(n) + + def insert(self, data): + """ + 插入 + :param data: + :return: + """ + assert(isinstance(data, int)) + + if self.root is None: + self.root = TreeNode(data) + else: + n = self.root + while n: + p = n + if data < n.val: + n = n.left + else: + n = n.right + + new_node = TreeNode(data) + new_node.parent = p + + if data < p.val: + p.left = new_node + else: + p.right = new_node + + return True + + def search(self, data): + """ + 搜索 + 返回bst中所有值为data的节点列表 + :param data: + :return: + """ + assert(isinstance(data, int)) + + # 所有搜索到的节点 + ret = [] + + n = self.root + while n: + if data < n.val: + n = n.left + else: + if data == n.val: + ret.append(n) + n = n.right + + return ret + + def delete(self, data): + """ + 删除 + :param data: + :return: + """ + assert (isinstance(data, int)) + + # 通过搜索得到需要删除的节点 + del_list = self.search(data) + + for n in del_list: + # 父节点为空,又不是根节点,已经不在树上,不用再删除 + if n.parent is None and n != self.root: + continue + else: + self._del(n) + + def _del(self, node): + """ + 删除 + 所删除的节点N存在以下情况: + 1. 没有子节点:直接删除N的父节点指针 + 2. 有一个子节点:将N父节点指针指向N的子节点 + 3. 有两个子节点:找到右子树的最小节点M,将值赋给N,然后删除M + :param data: + :return: + """ + # 1 + if node.left is None and node.right is None: + # 情况1和2,根节点和普通节点的处理方式不同 + if node == self.root: + self.root = None + else: + if node.val < node.parent.val: + node.parent.left = None + else: + node.parent.right = None + + node.parent = None + # 2 + elif node.left is None and node.right is not None: + if node == self.root: + self.root = node.right + self.root.parent = None + node.right = None + else: + if node.val < node.parent.val: + node.parent.left = node.right + else: + node.parent.right = node.right + + node.right.parent = node.parent + node.parent = None + node.right = None + elif node.left is not None and node.right is None: + if node == self.root: + self.root = node.left + self.root.parent = None + node.left = None + else: + if node.val < node.parent.val: + node.parent.left = node.left + else: + node.parent.right = node.left + + node.left.parent = node.parent + node.parent = None + node.left = None + # 3 + else: + min_node = node.right + # 找到右子树的最小值节点 + if min_node.left: + min_node = min_node.left + + if node.val != min_node.val: + node.val = min_node.val + self._del(min_node) + # 右子树的最小值节点与被删除节点的值相等,再次删除原节点 + else: + self._del(min_node) + self._del(node) + + def get_min(self): + """ + 返回最小值节点 + :return: + """ + if self.root is None: + return None + + n = self.root + while n.left: + n = n.left + return n.val + + def get_max(self): + """ + 返回最大值节点 + :return: + """ + if self.root is None: + return None + + n = self.root + while n.right: + n = n.right + return n.val + + def in_order(self): + """ + 中序遍历 + :return: + """ + if self.root is None: + return [] + + return self._in_order(self.root) + + def _in_order(self, node): + if node is None: + return [] + + ret = [] + n = node + ret.extend(self._in_order(n.left)) + ret.append(n.val) + ret.extend(self._in_order(n.right)) + + return ret + + def __repr__(self): + # return str(self.in_order()) + print(str(self.in_order())) + return self._draw_tree() + + def _bfs(self): + """ + bfs + 通过父子关系记录节点编号 + :return: + """ + if self.root is None: + return [] + + ret = [] + q = Queue() + # 队列[节点,编号] + q.put((self.root, 1)) + + while not q.empty(): + n = q.get() + + if n[0] is not None: + ret.append((n[0].val, n[1])) + q.put((n[0].left, n[1]*2)) + q.put((n[0].right, n[1]*2+1)) + + return ret + + def _draw_tree(self): + """ + 可视化 + :return: + """ + nodes = self._bfs() + + if not nodes: + print('This tree has no nodes.') + return + + layer_num = int(math.log(nodes[-1][1], 2)) + 1 + + prt_nums = [] + + for i in range(layer_num): + prt_nums.append([None]*2**i) + + for v, p in nodes: + row = int(math.log(p ,2)) + col = p % 2**row + prt_nums[row][col] = v + + prt_str = '' + for l in prt_nums: + prt_str += str(l)[1:-1] + '\n' + + return prt_str + + +if __name__ == '__main__': + nums = [4, 2, 5, 6, 1, 7, 3] + bst = BinarySearchTree(nums) + print(bst) + + # 插入 + bst.insert(1) + bst.insert(4) + print(bst) + + # 搜索 + for n in bst.search(2): + print(n.parent.val, n.val) + + # 删除 + bst.insert(6) + bst.insert(7) + print(bst) + bst.delete(7) + print(bst) + bst.delete(6) + print(bst) + bst.delete(4) + print(bst) + + # min max + print(bst.get_max()) + print(bst.get_min()) diff --git a/python/23_binarytree/binary_tree.py b/python/23_binarytree/binary_tree.py new file mode 100644 index 00000000..dae39734 --- /dev/null +++ b/python/23_binarytree/binary_tree.py @@ -0,0 +1,70 @@ +""" + Pre-order, in-order and post-order traversal of binary trees. + + Author: Wenru Dong +""" +from typing import TypeVar, Generic, Generator, Optional + +T = TypeVar("T") + +class TreeNode(Generic[T]): + def __init__(self, value: T): + self.val = value + self.left = None + self.right = None + + +# Pre-order traversal +def pre_order(root: Optional[TreeNode[T]]) -> Generator[T, None, None]: + if root: + yield root.val + yield from pre_order(root.left) + yield from pre_order(root.right) + +# In-order traversal +def in_order(root: Optional[TreeNode[T]]) -> Generator[T, None, None]: + if root: + yield from in_order(root.left) + yield root.val + yield from in_order(root.right) + +# Post-order traversal +def post_order(root: Optional[TreeNode[T]]) -> Generator[T, None, None]: + if root: + yield from post_order(root.left) + yield from post_order(root.right) + yield root.val + + +if __name__ == "__main__": + + singer = TreeNode("Taylor Swift") + + genre_country = TreeNode("Country") + genre_pop = TreeNode("Pop") + + album_fearless = TreeNode("Fearless") + album_red = TreeNode("Red") + album_1989 = TreeNode("1989") + album_reputation = TreeNode("Reputation") + + song_ls = TreeNode("Love Story") + song_wh = TreeNode("White Horse") + song_wanegbt = TreeNode("We Are Never Ever Getting Back Together") + song_ikywt = TreeNode("I Knew You Were Trouble") + song_sio = TreeNode("Shake It Off") + song_bb = TreeNode("Bad Blood") + song_lwymmd = TreeNode("Look What You Made Me Do") + song_g = TreeNode("Gorgeous") + + singer.left, singer.right = genre_country, genre_pop + genre_country.left, genre_country.right = album_fearless, album_red + genre_pop.left, genre_pop.right = album_1989, album_reputation + album_fearless.left, album_fearless.right = song_ls, song_wh + album_red.left, album_red.right = song_wanegbt, song_ikywt + album_1989.left, album_1989.right = song_sio, song_bb + album_reputation.left, album_reputation.right = song_lwymmd, song_g + + print(list(pre_order(singer))) + print(list(in_order(singer))) + print(list(post_order(singer))) diff --git a/python/24_tree/binary_search_tree.py b/python/24_tree/binary_search_tree.py new file mode 100644 index 00000000..f5a3f870 --- /dev/null +++ b/python/24_tree/binary_search_tree.py @@ -0,0 +1,64 @@ +""" + Binary search tree + + Author: Wenru Dong +""" +from typing import Optional + +class TreeNode: + def __init__(self, value: int): + self.val = value + self.left = None + self.right = None + +class BinarySearchTree: + def __init__(self): + self._root = None + + def find(self, value: int) -> Optional[TreeNode]: + node = self._root + while node and node.val != value: + node = node.left if node.val > value else node.right + return node + + def insert(self, value: int): + if not self._root: + self._root = TreeNode(value) + return + parent = None + node = self._root + while node: + parent = node + node = node.left if node.val > value else node.right + new_node = TreeNode(value) + if parent.val > value: + parent.left = new_node + else: + parent.right = new_node + + def delete(self, value: int): + node = self._root + parent = None + while node and node.val != value: + parent = node + node = node.left if node.val > value else node.right + if not node: return + + # 要删除的节点有两个子节点 + if node.left and node.right: + successor = node.right + successor_parent = node + while successor.left: + successor_parent = successor + successor = successor.left + node.val = successor.val + parent, node = successor_parent, successor + + # 删除节点是叶子节点或者仅有一个子节点 + child = node.left if node.left else node.right + if not parent: + self._root = child + elif parent.left == node: + parent.left = child + else: + parent.right = child diff --git a/python/26_red_black_tree/red_black_tree.py b/python/26_red_black_tree/red_black_tree.py new file mode 100644 index 00000000..ed67017f --- /dev/null +++ b/python/26_red_black_tree/red_black_tree.py @@ -0,0 +1,449 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from queue import Queue +import pygraphviz as pgv +import random + +OUTPUT_PATH = 'E:/' + + +class TreeNode: + def __init__(self, val=None, color=None): + self.val = val + assert color in ['r', 'b'] + self.color = 'red' if color == 'r' else 'black' + + self.left = None + self.right = None + self.parent = None + + def is_black(self): + return self.color == 'black' + + def set_black(self): + self.color = 'black' + return + + def set_red(self): + self.color = 'red' + + +class RedBlackTree: + """ + 红黑树实现 + 参考资料: + 1. 《算法导论》 + 第13章 红黑树 + 13.3 插入 p178 + 13.4 删除 p183 + + 2. 红黑树(二):删除 + https://zhuanlan.zhihu.com/p/25402654 + """ + def __init__(self, val_list=None): + self.root = None + self.black_leaf = TreeNode(color='b') # 共用的黑色叶子节点 + + # 可用数组初始化 + if type(val_list) is list: + for n in val_list: + assert type(n) is int + self.insert(n) + + def search(self, val): + """ + 搜索 + :param val: + :return: + """ + if self.root is None: + return None + + n = self.root + while n != self.black_leaf: + if val < n.val: + n = n.left + elif val > n.val: + n = n.right + else: + return n + return None + + def insert(self, val): + """ + 插入 + :param val: + :return: + """ + assert type(val) is int + + new_node = TreeNode(val, 'r') # 新插入的节点为红色 + + # 根节点 + if self.root is None: + self.root = new_node + else: + n = self.root + while n != self.black_leaf: # 黑色叶子节点 + p = n + if val < n.val: + n = n.left + elif val > n.val: + n = n.right + else: + raise KeyError('val:{} already exists') # 该值已存在,插入失败 + + if val < p.val: + p.left = new_node + else: + p.right = new_node + new_node.parent = p + + new_node.left = new_node.right = self.black_leaf + # 插入后调整 + self._insert_fixup(new_node) + + def _insert_fixup(self, node): + """ + 插入调整 + 参考资料:《算法导论》 13.3 p178-179 + :param node: + :return: + """ + n = node + while n is not self.root and not n.parent.is_black(): + # 父p 叔u 祖父g + p = self.parent(n) + u = self.bro(p) + g = self.parent(p) + + if not u.is_black(): # case 1 + p.set_black() # case 1 + u.set_black() # case 1 + g.set_red() # case 1 + n = g # case 1 + continue + + if p == g.left: # p为左结点 + if n == p.right: # case 2 + self.rotate_l(p) # case 2 + n, p = p, n # case 2 + p.set_black() # case 3 + g.set_red() # case 3 + self.rotate_r(g) # case 3 + else: # p为右节点 + if n == p.left: # case 2 + self.rotate_r(p) # case 2 + n, p = p, n # case 2 + p.set_black() # case 3 + g.set_red() # case 3 + self.rotate_l(g) # case 3 + + # 根节点强制置黑,有两种情况根节点是红色: + # 1. 新插入时是红色 + # 2. 经过case 1调整过后变红色 + self.root.color = 'black' + + def delete(self, val): + """ + 删除 + :param val: + :return: + """ + assert type(val) is int + + n = self.search(val) + if n is None: + print('can not find any nodes with value: {}'.format(val)) + return + + self._delete_node(n) + + def _delete_node(self, node): + """ + 删除节点内部实现 + 参考资料:《算法导论》 13.4 p183-184 + 实现方式有微调,当n有2个子节点时,将s拷贝至n,转为删除s(s最多有一个子节点) + :param node: + :return: + """ + n = node + + # n的子节点个数等于2 + if self.children_count(n) == 2: + # 寻找n的后继s + s = n.right + while s.left != self.black_leaf: + s = s.left + n.val = s.val + # 将删除n转化为删除s + n = s + + # n的子节点个数小于2 + if n.left == self.black_leaf: + c = n.right + else: + c = n.left + self._transplant(n, c) + + # 删除的节点是黑色,需要调整 + if n.is_black(): + self._delete_fixup(c) + return + + def _delete_fixup(self, node): + """ + 删除调整 + 参考资料:《算法导论》 13.4 p185-187 + :param node: + :return: + """ + n = node + while n != self.root and n.is_black(): + p = self.parent(n) + b = self.bro(n) + + # 左右节点对称 + if p.left == n: + if not b.is_black(): + b.set_black() # case 1 + p.set_red() # case 1 + self.rotate_l(p) # case 1 + # new bro after rotate + b = self.bro(n) # case 1 + + if b.left.is_black() and b.right.is_black(): + b.set_red() # case 2 + n = p # case 2 + else: + if b.right.is_black(): + b.left.set_black() # case 3 + b.set_red() # case 3 + self.rotate_r(b) # case 3 + # new bro after rotate + b = self.bro(n) # case 3 + + # 注意,因为p可能是红或黑,所以不能直接赋值颜色,只能copy + b.color = p.color # case 4 + p.set_black() # case 4 + b.right.set_black() # case 4 + self.rotate_l(p) # case 4 + # trick, 调整结束跳出while + n = self.root # case 4 + else: + if not b.is_black(): + b.set_black() # case 1 + p.set_red() # case 1 + self.rotate_r(p) # case 1 + # new bro after rotate + b = self.bro(n) # case 1 + + if b.left.is_black() and b.right.is_black(): + b.set_red() # case 2 + n = p # case 2 + else: + if b.left.is_black(): + b.right.set_black() # case 3 + b.set_red() # case 3 + self.rotate_l(b) # case 3 + # new bro after rotate + b = self.bro(n) # case 3 + + # 注意,因为p可能是红或黑,所以不能直接赋值颜色,只能copy + b.color = p.color # case 4 + p.set_black() # case 4 + b.left.set_black() # case 4 + self.rotate_r(p) # case 4 + # trick, 调整结束跳出while + n = self.root # case 4 + + # 将n设为黑色,从上面while循环跳出,情况有两种 + # 1. n是根节点,直接无视附加的黑色 + # 2. n是红色的节点,则染黑 + n.set_black() + + def _transplant(self, n1, n2): + """ + 节点移植, n2 -> n1 + :param n1: 原节点 + :param n2: 移植节点 + :return: + """ + if n1 == self.root: + if n2 != self.black_leaf: + self.root = n2 + n2.parent = None + else: + self.root = None # 只有删除根节点时会进来 + else: + p = self.parent(n1) + if p.left == n1: + p.left = n2 + else: + p.right = n2 + + n2.parent = p + + def rotate_l(self, node): + """ + 左旋 + :param node: + :return: + """ + if node is None: + return + + if node.right is self.black_leaf: + return + # raise Exception('try rotate left , but the node "{}" has no right child'.format(node.val)) + + p = self.parent(node) + x = node + y = node.right + + # node为根节点时,p为None,旋转后要更新根节点指向 + if p is not None: + if x == p.left: + p.left = y + else: + p.right = y + else: + self.root = y + + x.parent, y.parent = y, p + + if y.left != self.black_leaf: + y.left.parent = x + + x.right, y.left = y.left, x + + def rotate_r(self, node): + """ + 右旋 + :param node: + :return: + """ + if node is None: + return + + if node.left is self.black_leaf: + return + # raise Exception('try rotate right , but the node "{}" has no left child'.format(node.val)) + + p = self.parent(node) + x = node + y = node.left + + # 同左旋 + if p is not None: + if x == p.left: + p.left = y + else: + p.right = y + else: + self.root = y + + x.parent, y.parent = y, p + + if y.right is not None: + y.right.parent = x + + x.left, y.right = y.right, x + + @staticmethod + def bro(node): + """ + 获取兄弟节点 + :param node: + :return: + """ + if node is None or node.parent is None: + return None + else: + p = node.parent + if node == p.left: + return p.right + else: + return p.left + + @staticmethod + def parent(node): + """ + 获取父节点 + :param node: + :return: + """ + if node is None: + return None + else: + return node.parent + + def children_count(self, node): + """ + 获取子节点个数 + :param node: + :return: + """ + return 2 - [node.left, node.right].count(self.black_leaf) + + def draw_img(self, img_name='Red_Black_Tree.png'): + """ + 画图 + 用pygraphviz画出节点和箭头 + 箭头的红色和黑色分别代表左和右 + :param img_name: + :return: + """ + if self.root is None: + return + + tree = pgv.AGraph(directed=True, strict=True) + + q = Queue() + q.put(self.root) + + while not q.empty(): + n = q.get() + if n != self.black_leaf: # 黑色叶子的连线由各个节点自己画 + tree.add_node(n.val, color=n.color) + # 画父节点箭头 + # if n.parent is not None: + # tree.add_edge(n.val, n.parent.val) + + for c in [n.left, n.right]: + q.put(c) + color = 'red' if c == n.left else 'black' + if c != self.black_leaf: + tree.add_edge(n.val, c.val, color=color) + else: + tree.add_edge(n.val, 'None', color=color) + + tree.graph_attr['epsilon'] = '0.01' + tree.layout('dot') + tree.draw(OUTPUT_PATH + img_name) + return True + + +if __name__ == '__main__': + rbt = RedBlackTree() + + # insert + nums = list(range(1, 25)) + # random.shuffle(nums) + for num in nums: + rbt.insert(num) + + # search + search_num = 23 + n = rbt.search(search_num) + if n is not None: + print(n) + else: + print('node {} not found'.format(search_num)) + + # delete + rbt.delete(4) + + # draw image + rbt.draw_img('rbt.png') diff --git a/python/28_binary_heap/binary_heap.py b/python/28_binary_heap/binary_heap.py new file mode 100644 index 00000000..5e5ddf09 --- /dev/null +++ b/python/28_binary_heap/binary_heap.py @@ -0,0 +1,217 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import math +import random + + +class BinaryHeap: + """ + 大顶堆 + """ + def __init__(self, data=None, capacity=100): + self._data = [] + self._capacity = capacity + if type(data) is list: + if len(data) > self._capacity: + raise Exception('Heap oversize, capacity:{}, data size:{}'.format(self._capacity, len(data))) + self._type_assert(data) + self._data = data + + self._length = len(self._data) + + def heapify(self): + """ + 堆化 + :return: + """ + self._heapify(self._data, self._length-1) + + def _heapify(self, data, tail_idx): + """ + 堆化内部实现 + :param data: 需要堆化的数据 + :param tail_idx: 尾元素的索引 + :return: + """ + # heapify data[:tail_idx+1] + if tail_idx <= 0: + return + + # idx of the Last Parent node + lp = (tail_idx - 1) // 2 + + for i in range(lp, -1, -1): + self._heap_down(data, i, tail_idx) + + @staticmethod + def _heap_down(data, idx, tail_idx): + """ + 将指定的位置堆化 + :param data: 需要堆化的数据 + :param idx: data: 中需要堆化的位置 + :param tail_idx: 尾元素的索引 + :return: + """ + assert type(data) is list + + lp = (tail_idx - 1) // 2 + # top-down + while idx <= lp: + # Left and Right Child index + lc = 2 * idx + 1 + rc = lc + 1 + + # right child exists + if rc <= tail_idx: + tmp = lc if data[lc] > data[rc] else rc + else: + tmp = lc + + if data[tmp] > data[idx]: + data[tmp], data[idx] = data[idx], data[tmp] + idx = tmp + else: + break + + def insert(self, num): + """ + 插入 + :param num: + :return: + """ + if self._length < self._capacity: + if self._insert(self._data, num): + self._length += 1 + return True + return False + + @staticmethod + def _insert(data, num): + """ + 堆中插入元素的内部实现 + :param data: + :param num: + :return: + """ + assert type(data) is list + assert type(num) is int + + data.append(num) + length = len(data) + + # idx of New Node + nn = length - 1 + # bottom-up + while nn > 0: + p = (nn-1) // 2 + if data[nn] > data[p]: + data[nn], data[p] = data[p], data[nn] + nn = p + else: + break + + return True + + def get_top(self): + """ + 取堆顶 + :return: + """ + if self._length <= 0: + return None + return self._data[0] + + def remove_top(self): + """ + 取堆顶 + :return: + """ + ret = None + if self._length > 0: + ret = self._remove_top(self._data) + self._length -= 1 + return ret + + @staticmethod + def _remove_top(data): + """ + 取堆顶内部实现 + :param data: + :return: + """ + assert type(data) is list + + length = len(data) + if length == 0: + return None + + data[0], data[-1] = data[-1], data[0] + ret = data.pop() + length -= 1 + + # length == 0 or == 1, return + if length > 1: + BinaryHeap._heap_down(data, 0, length-1) + + return ret + + @staticmethod + def _type_assert(nums): + assert type(nums) is list + for n in nums: + assert type(n) is int + + @staticmethod + def _draw_heap(data): + """ + 格式化打印 + :param data: + :return: + """ + length = len(data) + + if length == 0: + return 'empty heap' + + ret = '' + for i, n in enumerate(data): + ret += str(n) + # 每行最后一个换行 + if i == 2**int(math.log(i+1, 2)+1) - 2 or i == len(data) - 1: + ret += '\n' + else: + ret += ', ' + + return ret + + def __repr__(self): + return self._draw_heap(self._data) + + +if __name__ == '__main__': + nums = list(range(10)) + random.shuffle(nums) + + bh = BinaryHeap(nums) + print('--- before heapify ---') + print(bh) + + # heapify + bh.heapify() + print('--- after heapify ---') + print(bh) + + # insert + print('--- insert ---') + if bh.insert(8): + print('insert success') + else: + print('insert fail') + print(bh) + + # get top + print('--- get top ---') + print('get top of the heap: {}'.format(bh.get_top())) + bh.remove_top() + print(bh) diff --git a/python/28_binary_heap/binary_heap_sort.py b/python/28_binary_heap/binary_heap_sort.py new file mode 100644 index 00000000..f0506d4f --- /dev/null +++ b/python/28_binary_heap/binary_heap_sort.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from binary_heap import BinaryHeap + + +class BinaryHeapSort(BinaryHeap): + def __init__(self): + super(BinaryHeapSort, self).__init__() + + def sort(self, nums): + """ + 排序 + 1. 堆化,大顶堆 + 2. 排序,从后往前遍历,首尾元素互换,子数组堆化 + :param nums: + :return: + """ + assert type(nums) is list + length = len(nums) + + if length <= 1: + return + + self._type_assert(nums) + + # heapify + self._heapify(nums, length-1) + + # sort + for i in range(length-1, 0, -1): + nums[0], nums[i] = nums[i], nums[0] + self._heap_down(nums, 0, i-1) + + return + + +if __name__ == '__main__': + bhs = BinaryHeapSort() + nums = [3, 5, 2, 6, 1, 7, 6] + + print('--- before sort ---') + print(nums) + + bhs.sort(nums) + print('--- after sort ---') + print(nums) diff --git a/python/28_binary_heap/heap.py b/python/28_binary_heap/heap.py new file mode 100644 index 00000000..b934057f --- /dev/null +++ b/python/28_binary_heap/heap.py @@ -0,0 +1,178 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import math +import random + + +class Heap: + def __init__(self, nums=None, capacity=100): + self._data = [] + self._capacity = capacity + if type(nums) == list and len(nums) <= self._capacity: + for n in nums: + assert type(n) is int + self._data.append(n) + self._length = len(self._data) + self._heapify() + + def _heapify(self): + if self._length <= 1: + return + + # idx of the Last Parent node + lp = (self._length - 2) // 2 + + for i in range(lp, -1, -1): + self._heap_down(i) + + def _heap_down(self, idx): + pass + + def insert(self, num): + pass + + def get_top(self): + if self._length <= 0: + return None + return self._data[0] + + def remove_top(self): + if self._length <= 0: + return None + + self._data[0], self._data[-1] = self._data[-1], self._data[0] + ret = self._data.pop() + self._length -= 1 + self._heap_down(0) + + return ret + + def get_data(self): + return self._data + + def get_length(self): + return self._length + + @staticmethod + def _draw_heap(data): + """ + 格式化打印 + :param data: + :return: + """ + length = len(data) + + if length == 0: + return 'empty heap' + + ret = '' + for i, n in enumerate(data): + ret += str(n) + # 每行最后一个换行 + if i == 2 ** int(math.log(i + 1, 2) + 1) - 2 or i == len(data) - 1: + ret += '\n' + else: + ret += ', ' + + return ret + + def __repr__(self): + return self._draw_heap(self._data) + + +class MaxHeap(Heap): + def _heap_down(self, idx): + if self._length <= 1: + return + + lp = (self._length - 2) // 2 + + while idx <= lp: + lc = 2 * idx + 1 + rc = lc + 1 + + if rc <= self._length-1: + tmp = lc if self._data[lc] > self._data[rc] else rc + else: + tmp = lc + + if self._data[tmp] > self._data[idx]: + self._data[tmp], self._data[idx] = self._data[idx], self._data[tmp] + idx = tmp + else: + break + + def insert(self, num): + if self._length >= self._capacity: + return False + + self._data.append(num) + self._length += 1 + + nn = self._length - 1 + while nn > 0: + p = (nn-1) // 2 + + if self._data[nn] > self._data[p]: + self._data[nn], self._data[p] = self._data[p], self._data[nn] + nn = p + else: + break + + return True + + +class MinHeap(Heap): + def _heap_down(self, idx): + if self._length <= 1: + return + + lp = (self._length - 2) // 2 + + while idx <= lp: + lc = 2 * idx + 1 + rc = lc + 1 + + if rc <= self._length-1: + tmp = lc if self._data[lc] < self._data[rc] else rc + else: + tmp = lc + + if self._data[tmp] < self._data[idx]: + self._data[tmp], self._data[idx] = self._data[idx], self._data[tmp] + idx = tmp + else: + break + + def insert(self, num): + if self._length >= self._capacity: + return False + + self._data.append(num) + self._length += 1 + + nn = self._length - 1 + while nn > 0: + p = (nn-1) // 2 + + if self._data[nn] < self._data[p]: + self._data[nn], self._data[p] = self._data[p], self._data[nn] + nn = p + else: + break + + return True + + +if __name__ == '__main__': + nums = list(range(10)) + random.shuffle(nums) + + max_h = MaxHeap(nums) + print('--- max heap ---') + print(max_h) + + print('--- min heap ---') + min_h = MinHeap(nums) + print(min_h) diff --git a/python/28_binary_heap/priority_queue.py b/python/28_binary_heap/priority_queue.py new file mode 100644 index 00000000..32645348 --- /dev/null +++ b/python/28_binary_heap/priority_queue.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import math + + +class QueueNode: + def __init__(self, priority, data=None): + assert type(priority) is int and priority >= 0 + self.priority = priority + self.data = data + + def __repr__(self): + return str((self.priority, self.data)) + + +class PriorityQueue: + def __init__(self, capacity=100): + self._capacity = capacity + self._q = [] + self._length = 0 + + def enqueue(self, priority, data=None): + if self._length >= self._capacity: + return False + + new_node = QueueNode(priority, data) + self._q.append(new_node) + self._length += 1 + + # update queue + nn = self._length - 1 + while nn > 0: + p = (nn - 1) // 2 + if self._q[nn].priority < self._q[p].priority: + self._q[nn], self._q[p] = self._q[p], self._q[nn] + nn = p + else: + break + + return True + + def dequeue(self): + if self._length <= 0: + raise Exception('the queue is empty....') + + self._q[0], self._q[-1] = self._q[-1], self._q[0] + ret = self._q.pop() + self._length -= 1 + + if self._length > 1: + # update queue + lp = (self._length - 2) // 2 + idx = 0 + + while idx <= lp: + lc = 2 * idx + 1 + rc = lc + 1 + + if rc <= self._length - 1: + tmp = lc if self._q[lc].priority < self._q[rc].priority else rc + else: + tmp = lc + + if self._q[tmp].priority < self._q[idx].priority: + self._q[tmp], self._q[idx] = self._q[idx], self._q[tmp] + idx = tmp + else: + break + return ret + + def get_length(self): + return self._length + + @staticmethod + def _draw_heap(data): + """ + 格式化打印 + :param data: + :return: + """ + length = len(data) + + if length == 0: + return 'empty' + + ret = '' + for i, n in enumerate(data): + ret += str(n) + # 每行最后一个换行 + if i == 2 ** int(math.log(i + 1, 2) + 1) - 2 or i == len(data) - 1: + ret += '\n' + else: + ret += ', ' + + return ret + + def __repr__(self): + def formater(node): + assert type(node) is QueueNode + return node.priority, node.data + + data = list(map(formater, self._q)) + return self._draw_heap(data) + + +if __name__ == '__main__': + pq = PriorityQueue() + pq.enqueue(5, 'Watch TV') + pq.enqueue(2, 'Learning') + pq.enqueue(10, 'Go Sleep') + pq.enqueue(0, 'Go Home') + pq.enqueue(7, 'Mobile Games') + print(pq) + + while pq.get_length() > 0: + print(pq.dequeue()) diff --git a/python/28_binary_heap/top_k.py b/python/28_binary_heap/top_k.py new file mode 100644 index 00000000..8123a70b --- /dev/null +++ b/python/28_binary_heap/top_k.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import random +from heap import MinHeap + + +def top_k(nums, k): + """ + 返回数组的前k大元素 + :param nums: + :param k: + :return: + """ + if len(nums) <= k: + return nums + + min_h = MinHeap(nums[:k], k) + for i in range(k, len(nums)): + tmp = min_h.get_top() + if nums[i] > tmp: + min_h.remove_top() + min_h.insert(nums[i]) + + return min_h.get_data() + + +if __name__ == '__main__': + nums = [] + k = 3 + + for i in range(20): + nums.append(random.randint(1, 100)) + + print('--- nums ---') + print(nums) + + print('--- top {} ---'.format(k)) + print(top_k(nums, k)) diff --git a/python/28_heap/heap.py b/python/28_heap/heap.py new file mode 100644 index 00000000..f3961c64 --- /dev/null +++ b/python/28_heap/heap.py @@ -0,0 +1,96 @@ +""" + Max-heap + + Author: Wenru Dong +""" + +from typing import Optional, List + +class Heap: + def __init__(self, capacity: int): + self._data = [0] * (capacity + 1) + self._capacity = capacity + self._count = 0 + + @classmethod + def _parent(cls, child_index: int) -> int: + """The parent index.""" + return child_index // 2 + + @classmethod + def _left(cls, parent_index: int) -> int: + """The left child index.""" + return 2 * parent_index + + @classmethod + def _right(cls, parent_index: int) -> int: + """The right child index.""" + return 2 * parent_index + 1 + + def _siftup(self) -> None: + i, parent = self._count, Heap._parent(self._count) + while parent and self._data[i] > self._data[parent]: + self._data[i], self._data[parent] = self._data[parent], self._data[i] + i, parent = parent, Heap._parent(parent) + + @classmethod + def _siftdown(cls, a: List[int], count: int, root_index: int = 1) -> None: + i = larger_child_index = root_index + while True: + left, right = cls._left(i), cls._right(i) + if left <= count and a[i] < a[left]: + larger_child_index = left + if right <= count and a[larger_child_index] < a[right]: + larger_child_index = right + if larger_child_index == i: break + a[i], a[larger_child_index] = a[larger_child_index], a[i] + i = larger_child_index + + def insert(self, value: int) -> None: + if self._count >= self._capacity: return + self._count += 1 + self._data[self._count] = value + self._siftup() + + def remove_max(self) -> Optional[int]: + if self._count: + result = self._data[1] + self._data[1] = self._data[self._count] + self._count -= 1 + Heap._siftdown(self._data, self._count) + return result + + @classmethod + def build_heap(cls, a: List[int]) -> None: + """Data in a needs to start from index 1.""" + for i in range((len(a) - 1)//2, 0, -1): + cls._siftdown(a, len(a) - 1, i) + + @classmethod + def sort(cls, a: List[int]) -> None: + """Data in a needs to start from index 1.""" + cls.build_heap(a) + k = len(a) - 1 + while k > 1: + a[1], a[k] = a[k], a[1] + k -= 1 + cls._siftdown(a, k) + + def __repr__(self): + return self._data[1 : self._count + 1].__repr__() + + +if __name__ == "__main__": + hp = Heap(10) + hp.insert(3) + hp.insert(9) + hp.insert(1) + hp.insert(8) + hp.insert(7) + hp.insert(3) + print(hp) + for _ in range(6): + print(hp.remove_max()) + a = [0, 6, 3, 4, 0, 9, 2, 7, 5, -2, 8, 1, 6, 10] + Heap.sort(a) + print(a[1:]) \ No newline at end of file diff --git a/python/31_bfs_dfs/bfs_dfs.py b/python/31_bfs_dfs/bfs_dfs.py new file mode 100644 index 00000000..59cebd87 --- /dev/null +++ b/python/31_bfs_dfs/bfs_dfs.py @@ -0,0 +1,88 @@ +""" + Breadth-first search and depth-first search. + + Author: Wenru Dong +""" + +from typing import List, Optional, Generator, IO +from collections import deque + +class Graph: + """Undirected graph.""" + def __init__(self, num_vertices: int): + self._num_vertices = num_vertices + self._adjacency = [[] for _ in range(num_vertices)] + + def add_edge(self, s: int, t: int) -> None: + self._adjacency[s].append(t) + self._adjacency[t].append(s) + + def _generate_path(self, s: int, t: int, prev: List[Optional[int]]) -> Generator[str, None, None]: + if prev[t] or s != t: + yield from self._generate_path(s, prev[t], prev) + yield str(t) + + def bfs(self, s: int, t: int) -> IO[str]: + """Print out the path from Vertex s to Vertex t + using bfs. + """ + if s == t: return + + visited = [False] * self._num_vertices + visited[s] = True + q = deque() + q.append(s) + prev = [None] * self._num_vertices + + while q: + v = q.popleft() + for neighbour in self._adjacency[v]: + if not visited[neighbour]: + prev[neighbour] = v + if neighbour == t: + print("->".join(self._generate_path(s, t, prev))) + return + visited[neighbour] = True + q.append(neighbour) + + def dfs(self, s: int, t: int) -> IO[str]: + """Print out a path from Vertex s to Vertex t + using dfs. + """ + found = False + visited = [False] * self._num_vertices + prev = [None] * self._num_vertices + + def _dfs(from_vertex: int) -> None: + nonlocal found + if found: return + visited[from_vertex] = True + if from_vertex == t: + found = True + return + for neighbour in self._adjacency[from_vertex]: + if not visited[neighbour]: + prev[neighbour] = from_vertex + _dfs(neighbour) + + _dfs(s) + print("->".join(self._generate_path(s, t, prev))) + + +if __name__ == "__main__": + + graph = Graph(8) + + graph.add_edge(0, 1) + graph.add_edge(0, 3) + graph.add_edge(1, 2) + graph.add_edge(1, 4) + graph.add_edge(2, 5) + graph.add_edge(3, 4) + graph.add_edge(4, 5) + graph.add_edge(4, 6) + graph.add_edge(5, 7) + graph.add_edge(6, 7) + + graph.bfs(0, 7) + graph.dfs(0, 7) diff --git a/python/32_bf_rk/bf_rk.py b/python/32_bf_rk/bf_rk.py new file mode 100644 index 00000000..0cd23990 --- /dev/null +++ b/python/32_bf_rk/bf_rk.py @@ -0,0 +1,93 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from time import time + + +def bf(main, pattern): + """ + 字符串匹配,bf暴搜 + :param main: 主串 + :param pattern: 模式串 + :return: + """ + n = len(main) + m = len(pattern) + + if n <= m: + return 0 if pattern == main else -1 + + for i in range(n-m+1): + for j in range(m): + if main[i+j] == pattern[j]: + if j == m-1: + return i + else: + continue + else: + break + return -1 + + +def simple_hash(s, start, end): + """ + 计算子串的哈希值 + 每个字符取acs-ii码后求和 + :param s: + :param start: + :param end: + :return: + """ + assert start <= end + + ret = 0 + for c in s[start: end+1]: + ret += ord(c) + return ret + + +def rk(main, pattern): + n = len(main) + m = len(pattern) + + if n <= m: + return 0 if pattern == main else -1 + + # 子串哈希值表 + hash_memo = [None] * (n-m+1) + hash_memo[0] = simple_hash(main, 0, m-1) + for i in range(1, n-m+1): + hash_memo[i] = hash_memo[i-1] - simple_hash(main, i-1, i-1) + simple_hash(main, i+m-1, i+m-1) + + # 模式串哈希值 + hash_p = simple_hash(pattern, 0, m-1) + + for i, h in enumerate(hash_memo): + # 可能存在哈希冲突 + if h == hash_p: + if pattern == main[i:i+m]: + return i + else: + continue + return -1 + + +if __name__ == '__main__': + m_str = 'a'*10000 + p_str = 'a'*200+'b' + + print('--- time consume ---') + t = time() + print('[bf] result:', bf(m_str, p_str)) + print('[bf] time cost: {0:.5}s'.format(time()-t)) + + t = time() + print('[rk] result:', rk(m_str, p_str)) + print('[rk] time cost: {0:.5}s'.format(time()-t)) + + print('') + print('--- search ---') + m_str = 'thequickbrownfoxjumpsoverthelazydog' + p_str = 'jump' + print('[bf] result:', bf(m_str, p_str)) + print('[rk] result:', rk(m_str, p_str)) diff --git a/python/33_bm/bm.py b/python/33_bm/bm.py new file mode 100644 index 00000000..74a9a34b --- /dev/null +++ b/python/33_bm/bm.py @@ -0,0 +1,77 @@ +""" + Boyer-Moore string-search algorithm. + + Author: Wenru Dong +""" + +from typing import List, Tuple + +SIZE = 256 + +def _generate_bad_character_table(pattern: str) -> List[int]: + bc = [-1] * SIZE + for i, char in enumerate(pattern): + bc[ord(char)] = i + return bc + + +def _generate_good_suffix_table(pattern: str) -> Tuple[List[bool], List[int]]: + m = len(pattern) + # prefix[k] records whether the last k-character suffix of pattern + # can match with the first k-character prefix of pattern. + # suffix[k] records the starting index of the last substring of + # pattern that can match with the last k-character suffix of pattern. + prefix, suffix = [False] * m, [-1] * m + # For each substring patter[:i+1], we find the common suffix with + # pattern, and the starting index of this common suffix. + # This way we can re-write previous suffix[k] to record the index + # as large as possible, hence the last substring. + for i in range(m - 1): + j = i # starting index of the common suffix + k = 0 # length of the common suffix + while j >= 0 and pattern[j] == pattern[~k]: + j -= 1 + k += 1 + suffix[k] = j + 1 + if j == -1: prefix[k] = True + return (prefix, suffix) + + +def _move_by_good_suffix(bad_character_index: int, suffix: List[int], prefix: List[bool]) -> int: + k = len(suffix) - 1 - bad_character_index + if suffix[k] != -1: return bad_character_index - suffix[k] + 1 + # Test from k - 1 + for r, can_match_prefix in enumerate(reversed(prefix[:k]), bad_character_index + 2): + if can_match_prefix: return r + return len(suffix) + + +def bm(s: str, pattern: str) -> int: + bc = _generate_bad_character_table(pattern) + prefix, suffix = _generate_good_suffix_table(pattern) + n, m = len(s), len(pattern) + i = 0 + while i <= n - m: + j = m - 1 # bad character index in pattern + while j >= 0: + if s[i + j] != pattern[j]: break + j -= 1 + if j < 0: return i + + x = j - bc[ord(s[i + j])] + y = 0 + if j < m - 1: + y = _move_by_good_suffix(j, suffix, prefix) + i += max(x, y) + return -1 + + +if __name__ == "__main__": + + s = "Here is a simple example" + pattern = "example" + print(bm(s, pattern)) + + s = "abcdcccdc" + pattern = "cccd" + print(s.find(pattern) == bm(s, pattern)) \ No newline at end of file diff --git a/python/33_bm/bm_.py b/python/33_bm/bm_.py new file mode 100644 index 00000000..7d615c4e --- /dev/null +++ b/python/33_bm/bm_.py @@ -0,0 +1,120 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +SIZE = 256 + + +def bm(main, pattern): + """ + BM算法 + 匹配规则: + 1. 坏字符规则 + 2. 好字符规则 + :param main: + :param pattern: + :return: + """ + assert type(main) is str and type(pattern) is str + n, m = len(main), len(pattern) + + if n <= m: + return 0 if main == pattern else -1 + + # bc + bc = [-1] * SIZE + generate_bc(pattern, m, bc) + + # gs + suffix = [-1] * m + prefix = [False] * m + generate_gs(pattern, m, suffix, prefix) + + i = 0 + while i < n-m+1: + j = m - 1 + while j >= 0: + if main[i+j] != pattern[j]: + break + else: + j -= 1 + + # pattern整个已被匹配,返回 + if j == -1: + return i + + # 1. bc规则计算后移位数 + x = j - bc[ord(main[i+j])] + + # 2. gs规则计算后移位数 + y = 0 + if j != m - 1: # 存在gs + y = move_by_gs(j, m, suffix, prefix) + + i += max(x, y) + + return -1 + + +def generate_bc(pattern, m, bc): + """ + 生成坏字符哈希表 + :param pattern: + :param m: + :param bc: + :return: + """ + for i in range(m): + bc[ord(pattern[i])] = i + + +def generate_gs(pattern, m, suffix, prefix): + """ + 好后缀预处理 + :param pattern: + :param m: + :param suffix: + :param prefix: + :return: + """ + for i in range(m-1): + k = 0 # pattern[:i+1]和pattern的公共后缀长度 + for j in range(i, -1, -1): + if pattern[j] == pattern[m-1-k]: + k += 1 + suffix[k] = j + if j == 0: + prefix[k] = True + else: + break + + +def move_by_gs(j, m, suffix, prefix): + """ + 通过好后缀计算移动值 + 需要处理三种情况: + 1. 整个好后缀在pattern仍能找到 + 2. 好后缀里存在 *后缀子串* 能和pattern的 *前缀* 匹配 + 3. 其他 + :param j: + :param m: + :param suffix: + :param prefix: + :return: + """ + k = m - 1 - j # j指向从后往前的第一个坏字符,k是此次匹配的好后缀的长度 + + if suffix[k] != -1: # 1. 整个好后缀在pattern剩余字符中仍有出现 + return j - suffix[k] + 1 + else: + for r in range(j+2, m): # 2. 后缀子串从长到短搜索 + if prefix[m-r]: + return r + return m # 3. 其他情况 + + +if __name__ == '__main__': + print('--- search ---') + m_str = 'dfasdeeeetewtweyyyhtruuueyytewtweyyhtrhrth' + p_str = 'eyytewtweyy' + print('[Built-in Functions] result:', m_str.find(p_str)) + print('[bm] result:', bm(m_str, p_str)) diff --git a/python/34_kmp/kmp.py b/python/34_kmp/kmp.py new file mode 100644 index 00000000..552f3c95 --- /dev/null +++ b/python/34_kmp/kmp.py @@ -0,0 +1,61 @@ +""" + KMP algorithm + + Author: Wenru Dong +""" + +from typing import List + +def kmp(s: int, pattern: int) -> int: + m = len(pattern) + partial_match_table = _get_partial_match_table(pattern) + j = 0 + for i in range(len(s)): + while j >= 0 and s[i] != pattern[j]: + j = partial_match_table[j] + j += 1 + if j == m: + return i - m + 1 + return -1 + + +def _get_partial_match_table(pattern: int) -> List[int]: + # Denote πᵏ(i) as π applied to i for k times, + # i.e., π²(i) = π(π(i)). + # Then we have the result: + # π(i) = πᵏ(i-1) + 1, + # where k is the smallest integer such that + # pattern[πᵏ(i-1)+1] == pattern[i]. + + # The value of π means the maximum length + # of proper prefix/suffix. + # The index of π means the length of the prefix + # considered for pattern. + # For example, π[2] means we are considering the first 2 characters + # of the pattern. + # If π[2] == 1, it means for the prefix of the pattern, P[0]P[1], + # it has a maximum length proper prefix of 1, which is also the + # suffix of P[0]P[1]. + # We also add a π[0] == -1 for easier handling of boundary + # condition. + + m = len(pattern) + π = [0] * (m + 1) + π[0] = k = -1 # We use k here to represent πᵏ(i) + for i in range(1, m + 1): + while k >= 0 and pattern[k] != pattern[i - 1]: + k = π[k] + k += 1 + π[i] = k + return π + + +if __name__ == "__main__": + + s = "abc abcdab abcdabcdabde" + pattern = "bcdabd" + print(kmp(s, pattern), s.find(pattern)) + + s = "hello" + pattern = "ll" + print(kmp(s, pattern), s.find(pattern)) \ No newline at end of file diff --git a/python/34_kmp/kmp_.py b/python/34_kmp/kmp_.py new file mode 100644 index 00000000..17fbedc7 --- /dev/null +++ b/python/34_kmp/kmp_.py @@ -0,0 +1,83 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + + +def kmp(main, pattern): + """ + kmp字符串匹配 + :param main: + :param pattern: + :return: + """ + assert type(main) is str and type(pattern) is str + + n, m = len(main), len(pattern) + + if m == 0: + return 0 + if n <= m: + return 0 if main == pattern else -1 + + # 求解next数组 + next = get_next(pattern) + + j = 0 + for i in range(n): + # 在pattern[:j]中,从长到短递归去找最长的和后缀子串匹配的前缀子串 + while j > 0 and main[i] != pattern[j]: + j = next[j-1] + 1 # 如果next[j-1] = -1,则要从起始字符取匹配 + + if main[i] == pattern[j]: + if j == m-1: + return i-m+1 + else: + j += 1 + return -1 + + +def get_next(pattern): + """ + next数组生成 + + 注意: + 理解的难点在于next[i]根据next[0], next[1]…… next[i-1]的求解 + next[i]的值依赖于前面的next数组的值,求解思路: + 1. 首先取出前一个最长的匹配的前缀子串,其下标就是next[i-1] + 2. 对比下一个字符,如果匹配,直接赋值next[i]为next[i-1]+1,因为i-1的时候已经是最长 + *3. 如果不匹配,需要递归去找次长的匹配的前缀子串,这里难理解的就是递归地方式,next[i-1] + 是i-1的最长匹配前缀子串的下标结尾,则 *next[next[i-1]]* 是其次长匹配前缀子串的下标 + 结尾 + *4. 递归的出口,就是在次长前缀子串的下一个字符和当前匹配 或 遇到-1,遇到-1则说明没找到任 + 何匹配的前缀子串,这时需要找pattern的第一个字符对比 + + ps: next[m-1]的数值其实没有任何意义,求解时可以不理。网上也有将next数组往右平移的做法。 + :param pattern: + :return: + """ + m = len(pattern) + next = [-1] * m + + next[0] = -1 + + # for i in range(1, m): + for i in range(1, m-1): + j = next[i-1] # 取i-1时匹配到的最长前缀子串 + while j != -1 and pattern[j+1] != pattern[i]: + j = next[j] # 次长的前缀子串的下标,即是next[next[i-1]] + + # 根据上面跳出while的条件,当j=-1时,需要比较pattern[0]和当前字符 + # 如果j!=-1,则pattern[j+1]和pattern[i]一定是相等的 + if pattern[j+1] == pattern[i]: # 如果接下来的字符也是匹配的,那i的最长前缀子串下标是next[i-1]+1 + j += 1 + next[i] = j + + return next + + +if __name__ == '__main__': + m_str = "aabbbbaaabbababbabbbabaaabb" + p_str = "abbabbbabaa" + + print('--- search ---') + print('[Built-in Functions] result:', m_str.find(p_str)) + print('[kmp] result:', kmp(m_str, p_str)) diff --git a/python/35_trie/trie.py b/python/35_trie/trie.py new file mode 100644 index 00000000..a1cf3eb6 --- /dev/null +++ b/python/35_trie/trie.py @@ -0,0 +1,42 @@ +""" + Author: Wenru Dong +""" + +class TrieNode: + def __init__(self, data: str): + self._data = data + self._children = [None] * 26 + self._is_ending_char = False + + +class Trie: + def __init__(self): + self._root = TrieNode("/") + + def insert(self, text: str) -> None: + node = self._root + for index, char in map(lambda x: (ord(x) - ord("a"), x), text): + if not node._children[index]: + node._children[index] = TrieNode(char) + node = node._children[index] + node._is_ending_char = True + + def find(self, pattern: str) -> bool: + node = self._root + for index in map(lambda x: ord(x) - ord("a"), pattern): + if not node._children[index]: return False + node = node._children[index] + return node._is_ending_char + + +if __name__ == "__main__": + + strs = ["how", "hi", "her", "hello", "so", "see"] + trie = Trie() + for s in strs: + trie.insert(s) + + for s in strs: + print(trie.find(s)) + + print(trie.find("swift")) \ No newline at end of file diff --git a/python/35_trie/trie_.py b/python/35_trie/trie_.py new file mode 100644 index 00000000..e41d1aaa --- /dev/null +++ b/python/35_trie/trie_.py @@ -0,0 +1,170 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +from queue import Queue +import pygraphviz as pgv + +OUTPUT_PATH = 'E:/' + + +class Node: + def __init__(self, c): + self.data = c + self.is_ending_char = False + # 使用有序数组,降低空间消耗,支持更多字符 + self.children = [] + + def insert_child(self, c): + """ + 插入一个子节点 + :param c: + :return: + """ + v = ord(c) + idx = self._find_insert_idx(v) + length = len(self.children) + + node = Node(c) + if idx == length: + self.children.append(node) + else: + self.children.append(None) + for i in range(length, idx, -1): + self.children[i] = self.children[i-1] + self.children[idx] = node + + def get_child(self, c): + """ + 搜索子节点并返回 + :param c: + :return: + """ + start = 0 + end = len(self.children) - 1 + v = ord(c) + + while start <= end: + mid = (start + end)//2 + if v == ord(self.children[mid].data): + return self.children[mid] + elif v < ord(self.children[mid].data): + end = mid - 1 + else: + start = mid + 1 + # 找不到返回None + return None + + def _find_insert_idx(self, v): + """ + 二分查找,找到有序数组的插入位置 + :param v: + :return: + """ + start = 0 + end = len(self.children) - 1 + + while start <= end: + mid = (start + end)//2 + if v < ord(self.children[mid].data): + end = mid - 1 + else: + if mid + 1 == len(self.children) or v < ord(self.children[mid+1].data): + return mid + 1 + else: + start = mid + 1 + # v < self.children[0] + return 0 + + def __repr__(self): + return 'node value: {}'.format(self.data) + '\n' \ + + 'children:{}'.format([n.data for n in self.children]) + + +class Trie: + def __init__(self): + self.root = Node(None) + + def gen_tree(self, string_list): + """ + 创建trie树 + + 1. 遍历每个字符串的字符,从根节点开始,如果没有对应子节点,则创建 + 2. 每一个串的末尾节点标注为红色(is_ending_char) + :param string_list: + :return: + """ + for string in string_list: + n = self.root + for c in string: + if n.get_child(c) is None: + n.insert_child(c) + n = n.get_child(c) + n.is_ending_char = True + + def search(self, pattern): + """ + 搜索 + + 1. 遍历模式串的字符,从根节点开始搜索,如果途中子节点不存在,返回False + 2. 遍历完模式串,则说明模式串存在,再检查树中最后一个节点是否为红色,是 + 则返回True,否则False + :param pattern: + :return: + """ + assert type(pattern) is str and len(pattern) > 0 + + n = self.root + for c in pattern: + if n.get_child(c) is None: + return False + n = n.get_child(c) + + return True if n.is_ending_char is True else False + + def draw_img(self, img_name='Trie.png'): + """ + 画出trie树 + :param img_name: + :return: + """ + if self.root is None: + return + + tree = pgv.AGraph('graph foo {}', strict=False, directed=False) + + # root + nid = 0 + color = 'black' + tree.add_node(nid, color=color, label='None') + + q = Queue() + q.put((self.root, nid)) + while not q.empty(): + n, pid = q.get() + for c in n.children: + nid += 1 + q.put((c, nid)) + color = 'red' if c.is_ending_char is True else 'black' + tree.add_node(nid, color=color, label=c.data) + tree.add_edge(pid, nid) + + tree.graph_attr['epsilon'] = '0.01' + tree.layout('dot') + tree.draw(OUTPUT_PATH + img_name) + return True + + +if __name__ == '__main__': + string_list = ['abc', 'abd', 'abcc', 'accd', 'acml', 'P@trick', 'data', 'structure', 'algorithm'] + + print('--- gen trie ---') + print(string_list) + trie = Trie() + trie.gen_tree(string_list) + # trie.draw_img() + + print('\n') + print('--- search result ---') + search_string = ['a', 'ab', 'abc', 'abcc', 'abe', 'P@trick', 'P@tric', 'Patrick'] + for ss in search_string: + print('[pattern]: {}'.format(ss), '[result]: {}'.format(trie.search(ss)))