Merge github.com:wangzheng0822/algo
This commit is contained in:
commit
f594e28af7
@ -6,7 +6,7 @@ using namespace std;
|
||||
|
||||
class CElement;
|
||||
/***
|
||||
* @brief 单链表容器
|
||||
* @brief 单链表容器
|
||||
*/
|
||||
class CSingleList
|
||||
{
|
||||
@ -15,61 +15,61 @@ public:
|
||||
~CSingleList();
|
||||
|
||||
/**
|
||||
* @brief 插入..链表末尾插入
|
||||
* @return 成功返回非空指针,否则失败
|
||||
* @brief 插入..链表末尾插入
|
||||
* @return 成功返回非空指针,否则失败
|
||||
*/
|
||||
CElement* Insert(void* lpData, int iDataSize);
|
||||
/**
|
||||
* @brief 插入..链表指定位置插入
|
||||
* @return 成功返回非空指针,否则失败
|
||||
* @brief 插入..链表指定位置插入
|
||||
* @return 成功返回非空指针,否则失败
|
||||
*/
|
||||
CElement* Insert(CElement* lpElement, void* lpData, int iDataSize);
|
||||
/**
|
||||
* @brief 删除
|
||||
* @brief 删除
|
||||
*/
|
||||
void Delete(CElement*);
|
||||
|
||||
/**
|
||||
* @brief 链首
|
||||
* @brief 链首
|
||||
*/
|
||||
CElement* Begin();
|
||||
/**
|
||||
* @brief 下一个元素
|
||||
* @brief 下一个元素
|
||||
*/
|
||||
CElement* Next();
|
||||
/***
|
||||
* @brief 链尾
|
||||
* @brief 链尾
|
||||
*/
|
||||
CElement* End();
|
||||
|
||||
/**
|
||||
* @brief 是否是空链表
|
||||
* @return 空返回TRUE,否则返回FALSE
|
||||
* @brief 是否是空链表
|
||||
* @return 空返回TRUE,否则返回FALSE
|
||||
*/
|
||||
bool Empty();
|
||||
|
||||
/**
|
||||
* @brief 反转
|
||||
* @brief 反转
|
||||
*/
|
||||
void Reverse();
|
||||
|
||||
/**
|
||||
* @brief 检测环
|
||||
* @return 返回TRUE时表示链表存在环,否则不存在环.
|
||||
* @brief 检测环
|
||||
* @return 返回TRUE时表示链表存在环,否则不存在环.
|
||||
*/
|
||||
bool CheckCircle();
|
||||
|
||||
/**
|
||||
* @brief 合并2个有序的链表
|
||||
* @brief 合并2个有序的链表
|
||||
*/
|
||||
void Merge(CSingleList& lst, std::function<int(void* t1, void* t2)>);
|
||||
|
||||
/**
|
||||
* @brief 删除倒数第K个结点
|
||||
* @brief 删除倒数第K个结点
|
||||
*/
|
||||
void DeleteLastKth(int k);
|
||||
/**
|
||||
* @brief 求中间节点
|
||||
* @brief 求中间节点
|
||||
*/
|
||||
CElement* Center();
|
||||
private:
|
||||
@ -80,18 +80,18 @@ private:
|
||||
CSingleList(CSingleList const & rhs);
|
||||
CSingleList& operator= (CSingleList const& rhs);
|
||||
private:
|
||||
/**头结点*/
|
||||
/**头结点*/
|
||||
CElement* m_lpHead;
|
||||
/**哨兵*/
|
||||
/**哨兵*/
|
||||
CElement* m_lpSentinel;
|
||||
/**空结点,用于End()返回 */
|
||||
/**空结点,用于End()返回 */
|
||||
CElement* m_lpNull;
|
||||
/**当前结点. 枚举时使用. */
|
||||
/**当前结点. 枚举时使用. */
|
||||
CElement* m_lpCur;
|
||||
};
|
||||
|
||||
/***
|
||||
* @brief 单链表结点元素.
|
||||
* @brief 单链表结点元素.
|
||||
*/
|
||||
class CElement
|
||||
{
|
||||
@ -101,11 +101,11 @@ protected:
|
||||
~CElement();
|
||||
public:
|
||||
/***
|
||||
* @brief 获取数据指针
|
||||
* @brief 获取数据指针
|
||||
*/
|
||||
void* GetDataPtr();
|
||||
protected:
|
||||
/**下一个结点*/
|
||||
/**下一个结点*/
|
||||
CElement* m_lpNext;
|
||||
void* m_lpData;
|
||||
};
|
||||
@ -113,7 +113,7 @@ protected:
|
||||
|
||||
void CreateList(CSingleList& lst)
|
||||
{
|
||||
//循环插入元素到链表尾
|
||||
//循环插入元素到链表尾
|
||||
for(int i=1; i<10;i++)
|
||||
{
|
||||
int* p = new int();
|
||||
@ -134,15 +134,15 @@ void PrintList(CSingleList& lst)
|
||||
int main()
|
||||
{
|
||||
{
|
||||
/// 链表的基本操作,插入/枚举/删除
|
||||
/// 链表的基本操作,插入/枚举/删除
|
||||
CSingleList lst;
|
||||
CElement* lpElement = NULL;
|
||||
CreateList(lst);
|
||||
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
PrintList(lst);
|
||||
|
||||
std::cout<<"查找指定元素,并在指定元素后面插入新元素"<<std::endl;
|
||||
std::cout<<"查找指定元素,并在指定元素后面插入新元素"<<std::endl;
|
||||
lpElement = lst.Begin();
|
||||
while(lpElement != lst.End())
|
||||
{
|
||||
@ -157,10 +157,10 @@ int main()
|
||||
}
|
||||
}
|
||||
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
PrintList(lst);
|
||||
|
||||
std::cout<<"查找指定元素(数字是7的元素),并删除指定元素"<<std::endl;
|
||||
std::cout<<"查找指定元素(数字是7的元素),并删除指定元素"<<std::endl;
|
||||
lpElement = lst.Begin();
|
||||
while(lpElement != lst.End())
|
||||
{
|
||||
@ -172,52 +172,52 @@ int main()
|
||||
lpElement = lst.Next();
|
||||
}
|
||||
}
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
PrintList(lst);
|
||||
}
|
||||
|
||||
std::cout<<"--------------------------"<<std::endl;
|
||||
{
|
||||
/// 链表的反转
|
||||
/// 链表的反转
|
||||
CSingleList lst;
|
||||
CElement* lpElement = NULL;
|
||||
CreateList(lst);
|
||||
std::cout<<"反转"<<std::endl;
|
||||
std::cout<<"反转"<<std::endl;
|
||||
lst.Reverse();
|
||||
PrintList(lst);
|
||||
}
|
||||
|
||||
std::cout<<"--------------------------"<<std::endl;
|
||||
{
|
||||
/// 检测环
|
||||
/// 检测环
|
||||
CSingleList lst;
|
||||
CElement* lpElement = NULL;
|
||||
CreateList(lst);
|
||||
std::cout<<"检测环"<<std::endl;
|
||||
std::cout<<"检测环"<<std::endl;
|
||||
bool bRet = lst.CheckCircle();
|
||||
if(bRet){
|
||||
std::cout<<"存在环."<<std::endl;
|
||||
std::cout<<"存在环."<<std::endl;
|
||||
}else{
|
||||
std::cout<<"不存在环."<<std::endl;
|
||||
std::cout<<"不存在环."<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout<<"--------------------------"<<std::endl;
|
||||
{
|
||||
/// 有序链表合并
|
||||
/// 有序链表合并
|
||||
CSingleList lst,lst2;
|
||||
CElement* lpElement = NULL;
|
||||
for(int i=1; i<10;i++)
|
||||
for(int i=1; i<30;i++)
|
||||
{
|
||||
int* p = new int();
|
||||
*p = i;
|
||||
if(i%2){
|
||||
if(i%4){
|
||||
lst2.Insert(p, 4);
|
||||
}else{
|
||||
lst.Insert(p, 4);
|
||||
}
|
||||
}
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
std::cout<<"枚举链表当前的元素"<<std::endl;
|
||||
PrintList(lst);
|
||||
std::cout<<"......"<<std::endl;
|
||||
PrintList(lst2);
|
||||
@ -231,31 +231,31 @@ int main()
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
std::cout<<"合并之后,打印当前链表."<<std::endl;
|
||||
std::cout<<"合并之后,打印当前链表."<<std::endl;
|
||||
PrintList(lst);
|
||||
}
|
||||
std::cout<<"--------------------------"<<std::endl;
|
||||
{
|
||||
/// 删除倒数第K个结点,并查看中间节点
|
||||
/// 删除倒数第K个结点,并查看中间节点
|
||||
CSingleList lst;
|
||||
CreateList(lst);
|
||||
std::cout<<"删除倒数第0个结点"<<std::endl;
|
||||
std::cout<<"删除倒数第0个结点"<<std::endl;
|
||||
lst.DeleteLastKth(0);
|
||||
PrintList(lst);
|
||||
CElement* lpCenter = lst.Center();
|
||||
std::cout<<"中间节点:"<<*((int*)lpCenter->GetDataPtr())<<std::endl;
|
||||
std::cout<<"中间节点:"<<*((int*)lpCenter->GetDataPtr())<<std::endl;
|
||||
|
||||
std::cout<<"删除倒数第1个结点"<<std::endl;
|
||||
std::cout<<"删除倒数第1个结点"<<std::endl;
|
||||
lst.DeleteLastKth(1);
|
||||
PrintList(lst);
|
||||
lpCenter = lst.Center();
|
||||
std::cout<<"中间节点:"<<*((int*)lpCenter->GetDataPtr())<<std::endl;
|
||||
std::cout<<"中间节点:"<<*((int*)lpCenter->GetDataPtr())<<std::endl;
|
||||
|
||||
std::cout<<"删除倒数第3个结点"<<std::endl;
|
||||
std::cout<<"删除倒数第3个结点"<<std::endl;
|
||||
lst.DeleteLastKth(3);
|
||||
PrintList(lst);
|
||||
lpCenter = lst.Center();
|
||||
std::cout<<"中间节点:"<<*((int*)lpCenter->GetDataPtr())<<std::endl;
|
||||
std::cout<<"中间节点:"<<*((int*)lpCenter->GetDataPtr())<<std::endl;
|
||||
}
|
||||
std::cin.ignore();
|
||||
|
||||
@ -316,10 +316,10 @@ CElement* CSingleList::Insert(CElement* lpElement, void* lpData, int iDataSize)
|
||||
}
|
||||
void CSingleList::Insert(CElement* lpNewElement, CElement* lpCurElement, bool bBack /*= true*/)
|
||||
{
|
||||
if(bBack){//插入到指定元素的后面
|
||||
if(bBack){//插入到指定元素的后面
|
||||
lpNewElement->m_lpNext = lpCurElement->m_lpNext;
|
||||
lpCurElement->m_lpNext = lpNewElement;
|
||||
}else{//插入到指定元素的前面
|
||||
}else{//插入到指定元素的前面
|
||||
CElement* lpIter = m_lpSentinel;
|
||||
while(NULL != lpIter)
|
||||
{
|
||||
@ -443,11 +443,13 @@ bool CSingleList::CheckCircle()
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并的2个链表必须是有序的
|
||||
*/
|
||||
void CSingleList::Merge(CSingleList& lst, std::function<int(void* t1, void* t2)> fnCompare)
|
||||
{
|
||||
CElement* lpL1 = Begin();
|
||||
CElement* lpL2 = lst.Begin();
|
||||
CElement* lpTail = NULL;
|
||||
|
||||
if(!fnCompare)
|
||||
{
|
||||
@ -458,7 +460,26 @@ void CSingleList::Merge(CSingleList& lst, std::function<int(void* t1, void* t2)>
|
||||
{
|
||||
if(lpL1 != End())
|
||||
{
|
||||
/**
|
||||
* 查找需要插入的正确位置
|
||||
*
|
||||
* 链表1,链表2; 链表1 <- 链表2, 链表2被合并到链表1中
|
||||
*
|
||||
* 如果链表1的元素小于链表2中的元素,则循环查找链表1中大于链表2中的当前元素的元素
|
||||
* 如果在链表1中找到满足上面条件的的元素位置[A]时,则把链表2中的当前元素插入到元素位置[A]的前面;
|
||||
* 如果在链表1中不存在这个位置则在链表1的末位插入元素
|
||||
*/
|
||||
iRet = fnCompare(lpL1->GetDataPtr(), lpL2->GetDataPtr());
|
||||
if(iRet < 0){
|
||||
lpL1 = Next();
|
||||
while(lpL1 != End()){
|
||||
iRet = fnCompare(lpL1->GetDataPtr(), lpL2->GetDataPtr());
|
||||
if(iRet > 0){
|
||||
break;
|
||||
}
|
||||
lpL1 = Next();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
iRet = -1;
|
||||
}
|
||||
@ -468,17 +489,13 @@ void CSingleList::Merge(CSingleList& lst, std::function<int(void* t1, void* t2)>
|
||||
lpNewElement->m_lpData = lpL2->GetDataPtr();
|
||||
if(lpL1 != End())
|
||||
{
|
||||
Insert(lpNewElement,lpL1, iRet <= 0);
|
||||
Insert(lpNewElement,lpL1, iRet < 0);
|
||||
}else{
|
||||
if(NULL == lpTail)
|
||||
{
|
||||
lpTail = Tail();
|
||||
}
|
||||
CElement* lpTail = Tail();
|
||||
Insert(lpNewElement,lpTail);
|
||||
}
|
||||
}
|
||||
lpL2 = lst.Next();
|
||||
lpL1 = Next();
|
||||
}
|
||||
}
|
||||
|
||||
|
139
c-cpp/07_linkedlist/linklist_jinshaohui.c
Normal file
139
c-cpp/07_linkedlist/linklist_jinshaohui.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*************************************************************************
|
||||
> File Name: lisklist.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-07
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
|
||||
|
||||
struct stlistNode
|
||||
{
|
||||
int val;
|
||||
struct listNode *next;
|
||||
}listNode;
|
||||
|
||||
/*反转链表*/
|
||||
listNode reverseList(listNode *head)
|
||||
{
|
||||
listNode *prev = NULL;
|
||||
listNode *next = NULL;
|
||||
|
||||
while(head != NULL)
|
||||
{
|
||||
next = head->next;
|
||||
head->next = prev;
|
||||
prev = head;
|
||||
head = next;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
/*判断链表是否有环*/
|
||||
int hasCycle(listNode *head)
|
||||
{
|
||||
listNode * fast = head;
|
||||
listNode * low = head;
|
||||
|
||||
while(fast != NULL && fast->next != NULL)
|
||||
{
|
||||
low = low->next;
|
||||
fast = fast->next->next;
|
||||
if (low == fast)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*合并有序链表*/
|
||||
listNode *mergeTwoLists(listNode *l1,listNode *l2)
|
||||
{
|
||||
listNode head = {0};
|
||||
listNode *pRes = &head;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(l1 == NULL)
|
||||
{
|
||||
pRes->next = l2;
|
||||
}
|
||||
|
||||
if (l2 == NULL)
|
||||
{
|
||||
pRes->next = l1;
|
||||
}
|
||||
|
||||
if(l1->val < l2->val)
|
||||
{
|
||||
pRes->next = l1;
|
||||
l1 = l1->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
pRes->next = l2;
|
||||
l2 = l2->next;
|
||||
}
|
||||
pRes = pRes->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
/*
|
||||
*删除链表倒数第n个节点,并返回链表头节点 */
|
||||
|
||||
listNode * removeNthFromEnd(listNode*headi,int n)
|
||||
{
|
||||
listNode *fast = head;
|
||||
listNode *prev = NULL;
|
||||
listNpde *next = head;
|
||||
int k = n;
|
||||
|
||||
/*快指针往后移动k-1*/
|
||||
while((k > 1) && (fast != NULL))
|
||||
{
|
||||
fast = fast->next;
|
||||
k--;
|
||||
}
|
||||
|
||||
/*说明链表数目不足n个*/
|
||||
if (fast == NULL)
|
||||
{
|
||||
return head;
|
||||
}
|
||||
|
||||
while (fast->next != NULL)
|
||||
{
|
||||
fast = fast->next;
|
||||
prev = next;
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
if(prev == NULL)
|
||||
{
|
||||
head = head->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = prev->next->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
/*求链表的中间节点*/
|
||||
listNode *middleNode(listNode *head)
|
||||
{
|
||||
listNode * fast = head;
|
||||
listNode * low = head;
|
||||
|
||||
while(fast != NULL && fast->next != NULL)
|
||||
{
|
||||
low = low->next;
|
||||
fast = fast->next->next;
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
57
c-cpp/10_recursive/one_two_step.c
Normal file
57
c-cpp/10_recursive/one_two_step.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*************************************************************************
|
||||
> File Name: one_two_step.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-19
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
|
||||
/*爬楼梯的问题,解决重复计算,采用数据保存方法*/
|
||||
|
||||
int helper(int n ,int *vlaue)
|
||||
{
|
||||
|
||||
if(vlaue[n] != 0)
|
||||
{
|
||||
return vlaue[n];
|
||||
}
|
||||
|
||||
vlaue[n] = helper(n - 1,vlaue) + helper(n - 2,vlaue);
|
||||
|
||||
return vlaue[n];
|
||||
}
|
||||
|
||||
int climbStaris(int n)
|
||||
{
|
||||
int *vlaue = NULL;
|
||||
int res = 0;
|
||||
|
||||
vlaue = (int *)malloc(sizeof(int)*(n+1));
|
||||
if(vlaue == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(vlaue,0,sizeof(int)*(n + 1));
|
||||
vlaue[0] = 0;
|
||||
vlaue[1] = 1;
|
||||
vlaue[2] = 2;
|
||||
res = helper(n,vlaue);
|
||||
free(vlaue);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
printf("\r\nnum%d ,%d",5,climbStaris(5));
|
||||
printf("\r\nnum%d ,%d",6,climbStaris(6));
|
||||
printf("\r\nnum%d ,%d",7,climbStaris(7));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
124
c-cpp/11_sorts/sorts_jinshaohui.c
Normal file
124
c-cpp/11_sorts/sorts_jinshaohui.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*************************************************************************
|
||||
> File Name: sorts_jinshaohui.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-19
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
|
||||
#define SWAP(a,b) \
|
||||
do{\
|
||||
(a) ^= (b);\
|
||||
(b) ^= (a);\
|
||||
(a) ^= (b);\
|
||||
}while(0)
|
||||
|
||||
/*冒泡排序*/
|
||||
void bubble_sort(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int swap_flg = 0;
|
||||
|
||||
if (size < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = size - 1; i > 0; i--)/*排序的趟数*/
|
||||
{
|
||||
swap_flg = 0;/*每次设置交换标识为0*/
|
||||
for (j = 0; j < i; j++)/*本趟排序的遍历元素个数*/
|
||||
{
|
||||
if (a[j] > a[j + 1])
|
||||
{
|
||||
SWAP(a[j],a[j+1]);
|
||||
swap_flg = 1;
|
||||
}
|
||||
}
|
||||
/*本趟数,无数据交换的话,说明已经有序,直接退出*/
|
||||
if (swap_flg == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*插入排序*/
|
||||
void insert_sort(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int key = 0;
|
||||
|
||||
for (i = 1; i < size; i ++)/*需要插入的元素个数*/
|
||||
{
|
||||
key = a[i];/*保存插入的元素数据*/
|
||||
j = i - 1;
|
||||
/* i 之前的元素都是有序的,找到比key小的插入到他后面,
|
||||
* 比key大的,需要往后挪一个位置*/
|
||||
while((j >= 0) && (a[j] > key))
|
||||
{
|
||||
a[j + 1] = a[j];
|
||||
j--;
|
||||
}
|
||||
a[j + 1] = key;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
/*选择排序*/
|
||||
void select_sort(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int min = 0;
|
||||
|
||||
for (i = 0; i < size - 1; i++)
|
||||
{
|
||||
min = i;
|
||||
for (j = i + 1; j < size; j++)
|
||||
{
|
||||
if (a[j] < a[min])
|
||||
{
|
||||
min = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (min != i)
|
||||
{
|
||||
SWAP(a[i],a[min]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void dump(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
printf("\r\n");
|
||||
for (i = 0; i < size; i++ )
|
||||
{
|
||||
printf("%d ",a[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int a[10] = {9,11,4,15,16,3,20,44,5,10};
|
||||
|
||||
//bubble_sort(a,sizeof(a)/sizeof(int));
|
||||
//insert_sort(a,sizeof(a)/sizeof(int));
|
||||
select_sort(a,sizeof(a)/sizeof(int));
|
||||
|
||||
dump(a,sizeof(a)/sizeof(int));
|
||||
|
||||
return 0;
|
||||
}
|
160
c-cpp/12_sorts/my12_sorts/merge_sort.c
Normal file
160
c-cpp/12_sorts/my12_sorts/merge_sort.c
Normal file
@ -0,0 +1,160 @@
|
||||
/*************************************************************************
|
||||
> File Name: merge_sort.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-19
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<assert.h>
|
||||
#include<string.h>
|
||||
#include<stdlib.h>
|
||||
|
||||
#define SORT_MAX (1000000)
|
||||
|
||||
void dump(int a[],int size);
|
||||
void merge_sentry(int a[],int middle,int left,int right)
|
||||
{
|
||||
int *pleft = NULL;
|
||||
int *pright = NULL;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
int left_size = middle - left + 1;
|
||||
int right_size = right - middle;
|
||||
|
||||
|
||||
pleft = (int *)malloc(sizeof(int)*(left_size + 1));
|
||||
assert(pleft != NULL);
|
||||
pright = (int *)malloc(sizeof(int)*(right_size + 1));
|
||||
assert(pright != NULL);
|
||||
|
||||
for(i = 0; i < left_size; i ++)
|
||||
{
|
||||
pleft[i] = a[left + i];
|
||||
}
|
||||
pleft[left_size] = SORT_MAX;
|
||||
for(i = 0; i < right_size; i ++)
|
||||
{
|
||||
pright[i] = a[middle + 1 + i];
|
||||
}
|
||||
pright[right_size] = SORT_MAX;
|
||||
|
||||
for (k = left,i = 0,j = 0; k <= right; k++)
|
||||
{
|
||||
if (pleft[i] <= pright[j])
|
||||
{
|
||||
a[k] = pleft[i++];
|
||||
}
|
||||
else
|
||||
{
|
||||
a[k] = pright[j++];
|
||||
}
|
||||
}
|
||||
|
||||
free(pleft);
|
||||
free(pright);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*两个有序数组合并*/
|
||||
void merge(int a[],int middle,int left,int right)
|
||||
{
|
||||
int *tmp = NULL;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
|
||||
tmp = (int*)malloc((right - left + 1)*sizeof(int));
|
||||
assert(tmp != NULL);
|
||||
|
||||
i = left;
|
||||
j = middle + 1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if((i > middle) || (j > right))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (a[i] > a[j])
|
||||
{
|
||||
tmp[k++] = a[j++];
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp[k++] = a[i++];
|
||||
}
|
||||
}
|
||||
|
||||
if (i > middle)
|
||||
{
|
||||
while(j <= right)
|
||||
{
|
||||
tmp[k++] = a[j++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(i <= middle)
|
||||
{
|
||||
tmp[k++] = a[i++];
|
||||
}
|
||||
}
|
||||
|
||||
memcpy((a + left),tmp,(right - left + 1)*sizeof(int));
|
||||
|
||||
free(tmp);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void merge_sort(int a[],int left,int right)
|
||||
{
|
||||
int middle = 0;
|
||||
|
||||
if(left >= right)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
middle = (left + right)/2;
|
||||
|
||||
merge_sort(a,left,middle);
|
||||
merge_sort(a,middle + 1,right);
|
||||
|
||||
merge_sentry(a,middle,left,right);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dump(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\r\n");
|
||||
for (i = 0; i < size; i++ )
|
||||
{
|
||||
printf("%d ",a[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
return;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int a[10] = {30,20,10,15,4,8,40,80,20,9};
|
||||
|
||||
merge_sort(a,0,9);
|
||||
|
||||
dump(a,10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
145
c-cpp/12_sorts/my12_sorts/quick_sort.c
Normal file
145
c-cpp/12_sorts/my12_sorts/quick_sort.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*************************************************************************
|
||||
> File Name: quick_sort.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-19
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<assert.h>
|
||||
#include<string.h>
|
||||
#include<stdlib.h>
|
||||
|
||||
/* SWAP 使用必须主要,不能是同一个数据进行交换*/
|
||||
#define SWAP(a,b) \
|
||||
do{\
|
||||
(a) ^= (b);\
|
||||
(b) ^= (a);\
|
||||
(a) ^= (b);\
|
||||
}while(0)
|
||||
|
||||
int partition2(int a[],int left,int right)
|
||||
{
|
||||
int i = left;
|
||||
int j = left;
|
||||
|
||||
for(; j < right;j++)
|
||||
{
|
||||
if (a[j] < a[right])
|
||||
{
|
||||
if(i != j)
|
||||
{
|
||||
SWAP(a[i],a[j]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if(i != right)
|
||||
{
|
||||
SWAP(a[i],a[right]);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int partition(int a[],int left,int right)
|
||||
{
|
||||
int i = left;
|
||||
int j = right;
|
||||
int key = a[left];
|
||||
|
||||
while(i < j)
|
||||
{
|
||||
while((i < j)&& (a[j] >= key))
|
||||
{
|
||||
j--;
|
||||
}
|
||||
if (i < j)
|
||||
{
|
||||
a[i] = a[j];
|
||||
}
|
||||
while((i < j) && a[i] <= key)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i<j)
|
||||
{
|
||||
a[j] = a[i];
|
||||
}
|
||||
}
|
||||
a[i] = key;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void quick_sort(int a[],int left,int right)
|
||||
{
|
||||
int q = 0;
|
||||
/*递归终止条件*/
|
||||
if (left >= right)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
q = partition2(a,left,right);
|
||||
quick_sort(a,left,(q - 1));
|
||||
quick_sort(a,(q + 1),right);
|
||||
return;
|
||||
}
|
||||
|
||||
void dump(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
printf("\r\n");
|
||||
for (i = 0; i < size; i++ )
|
||||
{
|
||||
printf("%d ",a[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int helper(int a[],int left,int right,int k)
|
||||
{
|
||||
int q = 0;
|
||||
|
||||
q = partition(a,left,right);
|
||||
|
||||
if (q > (k - 1))
|
||||
{
|
||||
return helper(a,left,q-1,k);
|
||||
}
|
||||
else if (q < (k - 1))
|
||||
{
|
||||
return helper(a,q+1,right,k);
|
||||
}
|
||||
|
||||
return a[q];
|
||||
}
|
||||
|
||||
/*求无序数组中从小到大第K个元素的数值*/
|
||||
int findKthlagest(int a[],int size,int k)
|
||||
{
|
||||
return helper(a,0,size-1,k);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int a[10] = {30,20,10,15,4,8,40,80,20,9};
|
||||
int k;
|
||||
|
||||
scanf("%d",&k);
|
||||
|
||||
printf("\r\n从小到大排序,第%d个元素数值是%d",k,findKthlagest(a,10,k));
|
||||
|
||||
quick_sort(a,0,9);
|
||||
|
||||
dump(a,10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,7 +27,11 @@ int partition(int *arr, int p, int r)
|
||||
|
||||
for (; j < r; j++) {
|
||||
if (arr[j] < arr[r]) {
|
||||
if(i != j)
|
||||
{
|
||||
swap(arr + i, arr + j);
|
||||
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
0
c-cpp/13_sorts/.gitkeep
Normal file
0
c-cpp/13_sorts/.gitkeep
Normal file
43
c-cpp/13_sorts/bucket_sort.hpp
Normal file
43
c-cpp/13_sorts/bucket_sort.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/26.
|
||||
*/
|
||||
|
||||
#ifndef SORTS_BUCKET_SORT_HPP_
|
||||
#define SORTS_BUCKET_SORT_HPP_
|
||||
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
template <size_t BucketSize,
|
||||
typename IterT,
|
||||
typename T = typename std::iterator_traits<IterT>::value_type,
|
||||
typename Compare = std::less<T>>
|
||||
void bucket_sort(IterT first, IterT last, Compare comp = Compare()) {
|
||||
const T min = *std::min_element(first, last), max = *std::max_element(first, last);
|
||||
const T range = max + 1 - min;
|
||||
const size_t bucket_num = (range - 1) / BucketSize + 1;
|
||||
|
||||
std::vector<std::vector<T>> buckets(bucket_num);
|
||||
for (auto b : buckets) {
|
||||
b.reserve(2 * BucketSize);
|
||||
}
|
||||
|
||||
for (IterT i = first; i != last; ++i) {
|
||||
size_t idx = (*i - min) / BucketSize;
|
||||
buckets[idx].emplace_back(*i);
|
||||
}
|
||||
|
||||
IterT dest = first;
|
||||
for (auto b : buckets) {
|
||||
std::sort(b.begin(), b.end(), comp);
|
||||
std::copy(b.begin(), b.end(), dest);
|
||||
dest += b.size();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // SORTS_BUCKET_SORT_HPP_
|
||||
|
33
c-cpp/13_sorts/bucket_sort_test.cc
Normal file
33
c-cpp/13_sorts/bucket_sort_test.cc
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/26.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include "bucket_sort.hpp"
|
||||
|
||||
template <size_t BucketSize,
|
||||
typename Container,
|
||||
typename T = typename Container::value_type,
|
||||
typename Compare = std::less<T>>
|
||||
void test_bucket_sort(Container cont, Compare comp = Compare()) {
|
||||
bucket_sort<BucketSize>(cont.begin(), cont.end(), comp);
|
||||
std::transform(cont.begin(), cont.end(), std::ostream_iterator<T>(std::cout, " "),
|
||||
[](T i){ return i; });
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::vector<int> test{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9};
|
||||
|
||||
test_bucket_sort<2>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9
|
||||
test_bucket_sort<3>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9
|
||||
test_bucket_sort<4>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9
|
||||
test_bucket_sort<5>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9
|
||||
test_bucket_sort<6>(test); // 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
40
c-cpp/13_sorts/counting_sort.hpp
Normal file
40
c-cpp/13_sorts/counting_sort.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/26.
|
||||
*/
|
||||
|
||||
#ifndef SORTS_COUNTING_SORT_HPP_
|
||||
#define SORTS_COUNTING_SORT_HPP_
|
||||
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
template <typename IterT,
|
||||
typename T = typename std::iterator_traits<IterT>::value_type>
|
||||
void counting_sort(IterT first, IterT last) {
|
||||
const auto len = std::distance(first, last);
|
||||
if (len < 2) { return; }
|
||||
|
||||
const T max = *std::max_element(first, last);
|
||||
if (max == 0) { return; }
|
||||
|
||||
std::vector<size_t> counter(max + 1);
|
||||
for (IterT i = first; i != last; ++i) {
|
||||
++counter[*i];
|
||||
}
|
||||
for (size_t i = 1; i != max + 1; ++i) {
|
||||
const size_t j = max - i;
|
||||
counter[j] += counter[j + 1]; // Liam Huang: count of numbers that is not less than j.
|
||||
}
|
||||
|
||||
std::vector<T> temp(len);
|
||||
for (IterT i = first; i != last; ++i) {
|
||||
temp[len - counter[*i]] = *i;
|
||||
--counter[*i]; // Liam Huang: stable for relative position.
|
||||
}
|
||||
std::copy(temp.begin(), temp.end(), first);
|
||||
}
|
||||
|
||||
#endif // SORTS_COUNTING_SORT_HPP_
|
||||
|
36
c-cpp/13_sorts/counting_sort_test.cc
Normal file
36
c-cpp/13_sorts/counting_sort_test.cc
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/26.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include "counting_sort.hpp"
|
||||
|
||||
template <typename Container,
|
||||
typename T = typename Container::value_type>
|
||||
void test_counting_sort(Container cont) {
|
||||
counting_sort(cont.begin(), cont.end());
|
||||
std::transform(cont.begin(), cont.end(), std::ostream_iterator<T>(std::cout, " "),
|
||||
[](T i){ return i; });
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Liam Huang: pi for test
|
||||
const std::vector<int> test1{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3};
|
||||
const std::vector<int> test2{2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9};
|
||||
const std::vector<int> test3{5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9};
|
||||
const std::vector<int> test4{3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4};
|
||||
const std::vector<int> test5{5, 9, 2, 3, 0, 7, 8, 1, 6, 4, 0, 6, 2, 8, 6};
|
||||
|
||||
test_counting_sort(test1); // 1 1 2 3 3 3 4 5 5 5 6 7 8 9 9 9
|
||||
test_counting_sort(test2); // 2 2 2 3 3 3 3 4 4 6 6 7 8 8 9
|
||||
test_counting_sort(test3); // 0 1 1 2 3 4 5 6 7 8 8 9 9 9 9
|
||||
test_counting_sort(test4); // 0 0 1 2 3 4 4 4 5 5 7 7 8 9 9
|
||||
test_counting_sort(test5); // 0 0 1 2 2 3 4 5 6 6 6 7 8 8 9
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
268
c-cpp/13_sorts/sort.c
Executable file
268
c-cpp/13_sorts/sort.c
Executable file
@ -0,0 +1,268 @@
|
||||
/*************************************************************************
|
||||
> File Name: sort.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-20
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
#include<math.h>
|
||||
#include<assert.h>
|
||||
|
||||
void dump(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
printf("\r\n");
|
||||
|
||||
for(i = 0; i <size; i++)
|
||||
{
|
||||
printf("%d ",a[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
/*计数排序,时间复杂度0(n),非原地排序
|
||||
*计数排序也是利用桶排序的解决方式
|
||||
* 如果数组最大值max比数组大小size大很多不适合;
|
||||
* 计数排序要求时非负整数
|
||||
* */
|
||||
void count_sort(int a[],int size)
|
||||
{
|
||||
int i = 0;
|
||||
int max = 0;
|
||||
int *count = 0;
|
||||
int *res = 0;
|
||||
|
||||
/*找到最大数*/
|
||||
for (i = 0 ; i< size; i++)
|
||||
{
|
||||
if (a[i] > max)
|
||||
{
|
||||
max = a[i];
|
||||
}
|
||||
}
|
||||
|
||||
count = (int *)malloc(sizeof(int)*(max + 1));
|
||||
assert(count != NULL);
|
||||
|
||||
memset(count,0,sizeof(int)*(max + 1));
|
||||
|
||||
/*计数*/
|
||||
for (i = 0; i < size;i++)
|
||||
{
|
||||
count[a[i]]++;
|
||||
}
|
||||
|
||||
/*依次累加*/
|
||||
for(i = 1 ;i <= max; i ++)
|
||||
{
|
||||
count[i] += count[i-1];
|
||||
}
|
||||
|
||||
res = (int *)malloc(sizeof(int)*(size));
|
||||
assert(res != NULL);
|
||||
/*核心代码,count[a[i] - 1]就是排序好的下标*/
|
||||
for (i = size-1;i >= 0; i--)
|
||||
{
|
||||
res[count[a[i]] -1] = a[i];
|
||||
count[a[i]]--;
|
||||
}
|
||||
|
||||
memcpy(a,res,size*(sizeof(int)));
|
||||
|
||||
free(res);
|
||||
free(count);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int count_sort_test()
|
||||
{
|
||||
int a [10]={1,5,6,8,10,9,3,1,2,1};
|
||||
printf("\r\n conunt sort test ....");
|
||||
count_sort(a,10);
|
||||
dump(a,10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NUM_OF_POS(a,pval) ((a)/pval)%10
|
||||
void radix_sort(int a[],int size,int num_count)
|
||||
{
|
||||
int count[10] = {0}; /*计数*/
|
||||
int *pres = NULL;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int pval = 10;
|
||||
int index = 0;
|
||||
int break_flg = 0;
|
||||
|
||||
pres = (int *)malloc(sizeof(int)*size);
|
||||
assert(pres != NULL);
|
||||
|
||||
for (i = 0; i < num_count; i ++)
|
||||
{
|
||||
memset(count,0,sizeof(int)*10);
|
||||
|
||||
/*求当前的基数*/
|
||||
pval = pow(10,i);
|
||||
|
||||
/*计数*/
|
||||
for (j = 0; j < size; j++)
|
||||
{
|
||||
index = NUM_OF_POS(a[j],pval);
|
||||
count[index]++;
|
||||
}
|
||||
|
||||
/*小的优化,可能位数最大的就1,其他的位数差很多*/
|
||||
if(count[0] == 9)
|
||||
{
|
||||
break_flg++;
|
||||
}
|
||||
|
||||
if(break_flg >=2)
|
||||
{
|
||||
printf("\r\n %i",i);
|
||||
break;
|
||||
}
|
||||
|
||||
/*累加*/
|
||||
for(j = 1; j < 10; j ++)
|
||||
{
|
||||
count[j] += count[j-1];
|
||||
}
|
||||
|
||||
/*排序必须从后往前,否则不是稳定排序*/
|
||||
for(j = size -1; j >= 0; j--)
|
||||
{
|
||||
index = NUM_OF_POS(a[j],pval);
|
||||
pres[count[index] - 1] = a[j];
|
||||
count[index]--;
|
||||
}
|
||||
/*本轮排序好的,拷贝到a中*/
|
||||
memcpy(a,pres,sizeof(int)*size);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void radix_sort_test()
|
||||
{
|
||||
int a[10] = {123,12341,1232134,124,236,128,1112313129,98,9,8989};
|
||||
printf("\r\n radix sort test.....");
|
||||
radix_sort(a,10,10);
|
||||
dump(a,10);
|
||||
return;
|
||||
}
|
||||
|
||||
struct barrel {
|
||||
int node[10];
|
||||
int count;/* the num of node */
|
||||
};
|
||||
int partition(int a[],int left,int right)
|
||||
{
|
||||
int i = left;
|
||||
int j = right;
|
||||
int key = a[left];
|
||||
|
||||
while(i < j)
|
||||
{
|
||||
while((i < j)&& (a[j] >= key))
|
||||
{
|
||||
j--;
|
||||
}
|
||||
if (i < j)
|
||||
{
|
||||
a[i] = a[j];
|
||||
}
|
||||
while((i < j) && a[i] <= key)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i<j)
|
||||
{
|
||||
a[j] = a[i];
|
||||
}
|
||||
}
|
||||
a[i] = key;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void quick_sort(int a[],int left,int right)
|
||||
{
|
||||
int q = 0;
|
||||
/*递归终止条件*/
|
||||
if (left >= right)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
q = partition(a,left,right);
|
||||
quick_sort(a,left,(q - 1));
|
||||
quick_sort(a,(q + 1),right);
|
||||
return;
|
||||
}
|
||||
|
||||
void bucket_sort(int data[], int size)
|
||||
{
|
||||
int max, min, num, pos;
|
||||
int i, j, k;
|
||||
struct barrel *pBarrel;
|
||||
|
||||
max = min = data[0];
|
||||
for (i = 1; i < size; i++) {
|
||||
if (data[i] > max) {
|
||||
max = data[i];
|
||||
} else if (data[i] < min) {
|
||||
min = data[i];
|
||||
}
|
||||
}
|
||||
num = (max - min + 1) / 10 + 1;
|
||||
pBarrel = (struct barrel*)malloc(sizeof(struct barrel) * num);
|
||||
memset(pBarrel, 0, sizeof(struct barrel) * num);
|
||||
|
||||
/* put data[i] into barrel which it belong to */
|
||||
for (i = 0; i < size; i++) {
|
||||
k = (data[i] - min + 1) / 10;/* calculate the index of data[i] in barrel */
|
||||
(pBarrel + k)->node[(pBarrel + k)->count] = data[i];
|
||||
(pBarrel + k)->count++;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((pBarrel + i)->count != 0)
|
||||
{
|
||||
quick_sort((pBarrel+i)->node, 0, ((pBarrel+i)->count)-1);/* sort node in every barrel */
|
||||
|
||||
for (j = 0; j < (pBarrel+i)->count; j++) {
|
||||
data[pos++] = (pBarrel+i)->node[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
free(pBarrel);
|
||||
}
|
||||
|
||||
void bucket_sort_test()
|
||||
{
|
||||
int a[] = {78, 17, 39, 26, 72, 94, 21, 12, 23, 91};
|
||||
int size = sizeof(a) / sizeof(int);
|
||||
printf("\r\n bucket sort test ...");
|
||||
bucket_sort(a, size);
|
||||
dump(a,size);
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
count_sort_test();
|
||||
|
||||
radix_sort_test();
|
||||
|
||||
bucket_sort_test();
|
||||
return 0;
|
||||
}
|
96
c-cpp/15_bsearch/binary_search.c
Normal file
96
c-cpp/15_bsearch/binary_search.c
Normal file
@ -0,0 +1,96 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef int(*bs)(int *arr, int size, int val);
|
||||
|
||||
int binary_search_r(int *arr, int size, int val)
|
||||
{
|
||||
int mid = size / 2;
|
||||
int idx;
|
||||
|
||||
if (arr[mid] == val)
|
||||
return mid;
|
||||
|
||||
// mid == 0 means size == 1
|
||||
// so the only element in array doesn't equal to val
|
||||
if (!mid)
|
||||
return -1;
|
||||
|
||||
if (arr[mid] < val) {
|
||||
idx = binary_search_r(arr + mid + 1, size - mid - 1, val);
|
||||
if (idx != -1)
|
||||
idx += mid + 1;
|
||||
} else {
|
||||
idx = binary_search_r(arr, mid, val);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int binary_search_i(int *arr, int size, int val)
|
||||
{
|
||||
int low = 0, high = size - 1, mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
if (arr[mid] == val)
|
||||
return mid;
|
||||
|
||||
if (arr[mid] < val)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void iteratioin_test(bs binary_search)
|
||||
{
|
||||
int arr[10] = {1, 4, 5, 9, 12, 19, 21, 28, 31, 36};
|
||||
int idx;
|
||||
|
||||
idx = binary_search(arr, 10, 12);
|
||||
if (idx != -1)
|
||||
printf("find 12 at %d\n", idx);
|
||||
else
|
||||
printf("12 not in arr \n");
|
||||
|
||||
idx = binary_search(arr, 10, 13);
|
||||
if (idx != -1)
|
||||
printf("find 13 at %d\n", idx);
|
||||
else
|
||||
printf("13 not in arr \n");
|
||||
|
||||
idx = binary_search(arr, 10, 1);
|
||||
if (idx != -1)
|
||||
printf("find 1 at %d\n", idx);
|
||||
else
|
||||
printf("1 not in arr \n");
|
||||
|
||||
idx = binary_search(arr, 10, 36);
|
||||
if (idx != -1)
|
||||
printf("find 36 at %d\n", idx);
|
||||
else
|
||||
printf("36 not in arr \n");
|
||||
|
||||
idx = binary_search(arr, 10, 31);
|
||||
if (idx != -1)
|
||||
printf("find 31 at %d\n", idx);
|
||||
else
|
||||
printf("31 not in arr \n");
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("=== Test iteration version:\n");
|
||||
iteratioin_test(binary_search_i);
|
||||
|
||||
printf("=== Test recursive version:\n");
|
||||
iteratioin_test(binary_search_r);
|
||||
|
||||
return 0;
|
||||
}
|
@ -8,19 +8,16 @@
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
|
||||
enum class BsearchPolicy { FIRST, LAST, UNSPECIFIED };
|
||||
|
||||
// Liam Huang: The algorithm works right with iterators that meet the ForwardIterator requirement,
|
||||
// but with a bad time complexity. For better performance, iterators should meet
|
||||
// the RandomAccessIterator requirement.
|
||||
template <typename IterT,
|
||||
typename ValueT = typename std::iterator_traits<IterT>::value_type,
|
||||
typename Compare>
|
||||
typename Compare = std::less<ValueT>>
|
||||
IterT bsearch(IterT first,
|
||||
IterT last,
|
||||
ValueT target,
|
||||
Compare comp,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
Compare comp = Compare()) {
|
||||
IterT result = last;
|
||||
while (std::distance(first, last) > 0) {
|
||||
IterT mid = first + std::distance(first, last) / 2;
|
||||
@ -29,38 +26,12 @@ IterT bsearch(IterT first,
|
||||
} else if (comp(target, *mid)) {
|
||||
last = mid;
|
||||
} else { // equal
|
||||
if (policy == BsearchPolicy::FIRST) {
|
||||
if (mid == first or comp(*(mid - 1), *mid)) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
last = mid;
|
||||
}
|
||||
} else if (policy == BsearchPolicy::LAST) {
|
||||
if (std::distance(mid, last) == 1 or comp(*mid, *(mid + 1))) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
} else {
|
||||
result = mid;
|
||||
break;
|
||||
}
|
||||
result = mid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename IterT,
|
||||
typename ValueT = typename std::iterator_traits<IterT>::value_type,
|
||||
typename Compare = std::less<ValueT>>
|
||||
IterT bsearch(IterT first,
|
||||
IterT last,
|
||||
ValueT target,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
return bsearch(first, last, target, Compare(), policy);
|
||||
}
|
||||
|
||||
#endif // BSEARCH_BSEARCH_HPP_
|
||||
|
||||
|
88
c-cpp/15_bsearch/bsearch_c/bsearch.c
Normal file
88
c-cpp/15_bsearch/bsearch_c/bsearch.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*************************************************************************
|
||||
> File Name: bsearch.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-21
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<assert.h>
|
||||
|
||||
|
||||
int mybsearch(int a[],int size,int value)
|
||||
{
|
||||
int mid = 0;
|
||||
int left = 0;
|
||||
int right = size - 1;
|
||||
|
||||
while(left <= right)
|
||||
{
|
||||
/*防止size数量太大是,(left + right)数据翻转,导致问题*/
|
||||
mid = left + ((right - left)>>1);
|
||||
|
||||
if (a[mid] == value)
|
||||
{
|
||||
return mid;
|
||||
}
|
||||
else if (a[mid] < value)
|
||||
{
|
||||
left = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int helper(int a[], int left,int right,int value)
|
||||
{
|
||||
int mid = 0;
|
||||
|
||||
if (left > right)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
/*防止size数量太大是,(left + right)数据翻转,导致问题*/
|
||||
mid = left + ((right - left)>>1);
|
||||
if (a[mid] == value)
|
||||
{
|
||||
return mid;
|
||||
}
|
||||
else if (a[mid] < value)
|
||||
{
|
||||
return helper(a,mid + 1,right,value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return helper(a,left,mid - 1,value);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*递归实现*/
|
||||
int mybsearch_2(int a[],int size,int value)
|
||||
{
|
||||
|
||||
return helper(a,0,size-1,value);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int a[10] = {5,6,8,9,10,11,23,42,53,123};
|
||||
int data = 0;
|
||||
int res = 0;
|
||||
|
||||
printf("\r\n输入一个整数");
|
||||
scanf("%d",&data);
|
||||
res = mybsearch(a,10,data);
|
||||
printf("data[%d] %s 在数据中,下标是%d",data,(res != -1)?"":"不",res);
|
||||
|
||||
printf("\r\n输入一个整数");
|
||||
scanf("%d",&data);
|
||||
res = mybsearch_2(a,10,data);
|
||||
printf("data[%d] %s 在数据中,下标是%d",data,(res != -1)?"":"不",res);
|
||||
return;
|
||||
}
|
53
c-cpp/15_bsearch/bsearch_c/sqrt.c
Normal file
53
c-cpp/15_bsearch/bsearch_c/sqrt.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*************************************************************************
|
||||
> File Name: sqrt.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-31
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<string.h>
|
||||
#include<stdlib.h>
|
||||
#include<assert.h>
|
||||
|
||||
|
||||
/*求解精度设置*/
|
||||
#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;
|
||||
}
|
||||
|
@ -8,10 +8,8 @@
|
||||
#include "bsearch.hpp"
|
||||
|
||||
template <typename VecT, typename T = typename VecT::value_type>
|
||||
void test_bsearch(const VecT& test,
|
||||
T target,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
auto it = bsearch(test.begin(), test.end(), target, policy);
|
||||
void test_bsearch(const VecT& test, T target) {
|
||||
auto it = bsearch(test.begin(), test.end(), target);
|
||||
std::cout << std::distance(test.begin(), it) << std::endl;
|
||||
}
|
||||
|
||||
@ -21,17 +19,9 @@ int main() {
|
||||
test_bsearch(test, 8); // 14
|
||||
test_bsearch(test, -1); // 14
|
||||
test_bsearch(test, 0); // 0, 1
|
||||
test_bsearch(test, 0, BsearchPolicy::FIRST); // 0
|
||||
test_bsearch(test, 0, BsearchPolicy::LAST); // 1
|
||||
test_bsearch(test, 4); // 5, 6
|
||||
test_bsearch(test, 4, BsearchPolicy::FIRST); // 5
|
||||
test_bsearch(test, 4, BsearchPolicy::LAST); // 6
|
||||
test_bsearch(test, 5); // 7, 8, 9, 10, 11
|
||||
test_bsearch(test, 5, BsearchPolicy::FIRST); // 7
|
||||
test_bsearch(test, 5, BsearchPolicy::LAST); // 11
|
||||
test_bsearch(test, 7); // 13
|
||||
test_bsearch(test, 7, BsearchPolicy::FIRST); // 13
|
||||
test_bsearch(test, 7, BsearchPolicy::LAST); // 13
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
0
c-cpp/16_bsearch/.gitkeep
Normal file
0
c-cpp/16_bsearch/.gitkeep
Normal file
190
c-cpp/16_bsearch/bsearch.c
Normal file
190
c-cpp/16_bsearch/bsearch.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*************************************************************************
|
||||
> File Name: bsearch.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-21
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<assert.h>
|
||||
|
||||
/*二分查找算法的变形问题
|
||||
*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;
|
||||
}
|
283
c-cpp/16_bsearch/bsearch_variant.c
Normal file
283
c-cpp/16_bsearch/bsearch_variant.c
Normal file
@ -0,0 +1,283 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int binary_search(int *arr, int size, int val)
|
||||
{
|
||||
int low = 0, high = size - 1, mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
if (arr[mid] == val)
|
||||
return mid;
|
||||
|
||||
if (arr[mid] < val)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* find the first index with *val*
|
||||
*
|
||||
* This is a little tricky because the calculation of mid is integer based, it
|
||||
* will be cast to the lower bound of an integer.
|
||||
*
|
||||
* In case the [low, high] range is of size 1 or 2 and arr[mid] >= val, we will
|
||||
* have:
|
||||
*
|
||||
* mid = (low + high) / 2 = low
|
||||
* high = mid - 1 = low - 1 < low, which break the loop
|
||||
*
|
||||
*/
|
||||
int binary_search_first(int *arr, int size, int val)
|
||||
{
|
||||
int low = 0, high = size - 1, mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
//printf("[%d-%d] %d\n", low, high, mid);
|
||||
|
||||
if (arr[mid] >= val)
|
||||
high = mid - 1;
|
||||
else
|
||||
low = mid + 1;
|
||||
}
|
||||
|
||||
//printf("[%d-%d] %d\n", low, high, mid);
|
||||
if (arr[low] == val)
|
||||
return low;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int binary_search_last(int *arr, int size, int val)
|
||||
{
|
||||
int low = 0, high = size - 1, mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
|
||||
if (arr[mid] <= val)
|
||||
low = mid + 1;
|
||||
else
|
||||
high = mid - 1;
|
||||
}
|
||||
|
||||
if (arr[high] == val)
|
||||
return high;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int binary_search_first_r(int *arr, int size, int val)
|
||||
{
|
||||
int mid = size / 2;
|
||||
int idx;
|
||||
|
||||
if (size <= 0)
|
||||
return -1;
|
||||
|
||||
// we find *val* at mid, try first half
|
||||
if (arr[mid] == val) {
|
||||
idx = binary_search_first_r(arr, mid, val);
|
||||
return idx != -1 ? idx : mid;
|
||||
}
|
||||
|
||||
// mid == 0 means size == 1
|
||||
// so the only element in array doesn't equal to val
|
||||
if (!mid)
|
||||
return -1;
|
||||
|
||||
if (arr[mid] < val) {
|
||||
idx = binary_search_first_r(arr + mid + 1, size - mid - 1, val);
|
||||
if (idx != -1)
|
||||
idx += mid + 1;
|
||||
} else {
|
||||
idx = binary_search_first_r(arr, mid, val);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int binary_search_last_r(int *arr, int size, int val)
|
||||
{
|
||||
int mid = size / 2;
|
||||
int idx;
|
||||
|
||||
if (size <= 0)
|
||||
return -1;
|
||||
|
||||
// we find *val* at mid, try last half
|
||||
if (arr[mid] == val) {
|
||||
idx = binary_search_last_r(arr+mid+1, size-mid-1, val);
|
||||
if (idx != -1)
|
||||
mid += idx + 1;
|
||||
return mid;
|
||||
}
|
||||
|
||||
// mid == 0 means size == 1
|
||||
// so the only element in array doesn't equal to val
|
||||
if (!mid)
|
||||
return -1;
|
||||
|
||||
if (arr[mid] < val) {
|
||||
idx = binary_search_last_r(arr + mid + 1, size - mid - 1, val);
|
||||
if (idx != -1)
|
||||
idx += mid + 1;
|
||||
} else {
|
||||
idx = binary_search_last_r(arr, mid, val);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int binary_search_first_bigger(int *arr, int size, int val)
|
||||
{
|
||||
int low = 0, high = size - 1, mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
|
||||
if (arr[mid] >= val) {
|
||||
if (mid == 0 || arr[mid-1] < val)
|
||||
return mid;
|
||||
high = mid - 1;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int binary_search_first_bigger_r(int *arr, int size, int val)
|
||||
{
|
||||
int mid = size / 2;
|
||||
int idx;
|
||||
|
||||
if (size <= 0)
|
||||
return -1;
|
||||
|
||||
if (arr[mid] >= val) {
|
||||
// find one bigger than val, try first half
|
||||
idx = binary_search_first_bigger_r(arr, mid, val);
|
||||
if (idx == -1)
|
||||
idx = mid;
|
||||
} else {
|
||||
// the bigger one may sit in second half
|
||||
idx = binary_search_first_bigger_r(arr + mid + 1, size - mid - 1, val);
|
||||
if (idx != -1)
|
||||
idx += mid + 1;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int binary_search_last_smaller(int *arr, int size, int val)
|
||||
{
|
||||
int low = 0, high = size - 1, mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
|
||||
if (arr[mid] <= val) {
|
||||
if (mid == 0 || arr[mid+1] > val)
|
||||
return mid;
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int binary_search_last_smaller_r(int *arr, int size, int val)
|
||||
{
|
||||
int mid = size / 2;
|
||||
int idx;
|
||||
|
||||
if (size <= 0)
|
||||
return -1;
|
||||
|
||||
if (arr[mid] <= val) {
|
||||
// find one smaller than val, try second half
|
||||
idx = binary_search_last_smaller_r(arr + mid + 1, size - mid - 1, val);
|
||||
if (idx != -1)
|
||||
idx += mid + 1;
|
||||
else
|
||||
idx = mid;
|
||||
} else {
|
||||
// the smaller one may sit in first half
|
||||
idx = binary_search_last_smaller_r(arr, mid, val);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int arr[10] = {1, 4, 5, 9, 12, 14, 19, 19, 31, 36};
|
||||
int idx;
|
||||
|
||||
printf("Test Array:\n");
|
||||
for (idx = 0; idx < 10; idx++)
|
||||
printf("%8d", arr[idx]);
|
||||
printf("\n");
|
||||
|
||||
idx = binary_search_first(arr, 10, 19);
|
||||
if (idx != -1)
|
||||
printf("first 19 at %d\n", idx);
|
||||
else
|
||||
printf("19 not in arr \n");
|
||||
|
||||
idx = binary_search_first_r(arr, 10, 19);
|
||||
if (idx != -1)
|
||||
printf("first 19 at %d\n", idx);
|
||||
else
|
||||
printf("19 not in arr \n");
|
||||
|
||||
idx = binary_search_last(arr, 10, 19);
|
||||
if (idx != -1)
|
||||
printf("last 19 at %d\n", idx);
|
||||
else
|
||||
printf("19 not in arr \n");
|
||||
|
||||
idx = binary_search_last_r(arr, 10, 19);
|
||||
if (idx != -1)
|
||||
printf("last 19 at %d\n", idx);
|
||||
else
|
||||
printf("19 not in arr \n");
|
||||
|
||||
idx = binary_search_first_bigger(arr, 10, 12);
|
||||
if (idx != -1)
|
||||
printf("first bigger 12 at %d\n", idx);
|
||||
else
|
||||
printf("12 not in arr \n");
|
||||
|
||||
idx = binary_search_first_bigger_r(arr, 10, 12);
|
||||
if (idx != -1)
|
||||
printf("first bigger 12 at %d\n", idx);
|
||||
else
|
||||
printf("12 not in arr \n");
|
||||
|
||||
idx = binary_search_last_smaller(arr, 10, 12);
|
||||
if (idx != -1)
|
||||
printf("last smaller 12 at %d\n", idx);
|
||||
else
|
||||
printf("12 not in arr \n");
|
||||
|
||||
idx = binary_search_last_smaller_r(arr, 10, 12);
|
||||
if (idx != -1)
|
||||
printf("last smaller 12 at %d\n", idx);
|
||||
else
|
||||
printf("12 not in arr \n");
|
||||
|
||||
return 0;
|
||||
}
|
90
c-cpp/16_bsearch/bsearch_varients.hpp
Normal file
90
c-cpp/16_bsearch/bsearch_varients.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/26.
|
||||
*/
|
||||
|
||||
#ifndef BSEARCH_BSEARCH_VARIENTS_HPP_
|
||||
#define BSEARCH_BSEARCH_VARIENTS_HPP_
|
||||
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
|
||||
enum class BsearchPolicy { UNSPECIFIED, FIRST, LAST, FIRST_NOT_LESS, LAST_NOT_GREATER };
|
||||
|
||||
// Liam Huang: The algorithm works right with iterators that meet the ForwardIterator requirement,
|
||||
// but with a bad time complexity. For better performance, iterators should meet
|
||||
// the RandomAccessIterator requirement.
|
||||
template <typename IterT,
|
||||
typename ValueT = typename std::iterator_traits<IterT>::value_type,
|
||||
typename Compare>
|
||||
IterT bsearch(IterT first,
|
||||
IterT last,
|
||||
ValueT target,
|
||||
Compare comp,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
IterT result = last;
|
||||
while (std::distance(first, last) > 0) {
|
||||
IterT mid = first + std::distance(first, last) / 2;
|
||||
if (policy == BsearchPolicy::FIRST_NOT_LESS) {
|
||||
if (!comp(*mid, target)) {
|
||||
if (mid == first or comp(*(mid - 1), target)) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
last = mid;
|
||||
}
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
} else if (policy == BsearchPolicy::LAST_NOT_GREATER) {
|
||||
if (comp(target, *mid)) {
|
||||
last = mid;
|
||||
} else {
|
||||
if (std::distance(mid, last) == 1 or comp(target, *(mid + 1))) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
}
|
||||
} else { // policy == UNSPECIFIED or FIRST or LAST
|
||||
if (comp(*mid, target)) {
|
||||
first = mid + 1;
|
||||
} else if (comp(target, *mid)) {
|
||||
last = mid;
|
||||
} else { // equal
|
||||
if (policy == BsearchPolicy::FIRST) {
|
||||
if (mid == first or comp(*(mid - 1), *mid)) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
last = mid;
|
||||
}
|
||||
} else if (policy == BsearchPolicy::LAST) {
|
||||
if (std::distance(mid, last) == 1 or comp(*mid, *(mid + 1))) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
} else {
|
||||
result = mid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename IterT,
|
||||
typename ValueT = typename std::iterator_traits<IterT>::value_type,
|
||||
typename Compare = std::less<ValueT>>
|
||||
IterT bsearch(IterT first,
|
||||
IterT last,
|
||||
ValueT target,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
return bsearch(first, last, target, Compare(), policy);
|
||||
}
|
||||
|
||||
#endif // BSEARCH_BSEARCH_VARIENTS_HPP_
|
||||
|
41
c-cpp/16_bsearch/bsearch_varients_test.cc
Normal file
41
c-cpp/16_bsearch/bsearch_varients_test.cc
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/26.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "bsearch_varients.hpp"
|
||||
|
||||
template <typename VecT, typename T = typename VecT::value_type>
|
||||
void test_bsearch(const VecT& test,
|
||||
T target,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
auto it = bsearch(test.begin(), test.end(), target, policy);
|
||||
std::cout << std::distance(test.begin(), it) << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::vector<int> test{0, 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 5, 6, 8}; // std::less<int>()
|
||||
|
||||
test_bsearch(test, 8); // 14
|
||||
test_bsearch(test, -1); // 14
|
||||
test_bsearch(test, 0); // 0, 1
|
||||
test_bsearch(test, 0, BsearchPolicy::FIRST); // 0
|
||||
test_bsearch(test, 0, BsearchPolicy::LAST); // 1
|
||||
test_bsearch(test, 4); // 5, 6
|
||||
test_bsearch(test, 4, BsearchPolicy::FIRST); // 5
|
||||
test_bsearch(test, 4, BsearchPolicy::LAST); // 6
|
||||
test_bsearch(test, 5); // 7, 8, 9, 10, 11
|
||||
test_bsearch(test, 5, BsearchPolicy::FIRST); // 7
|
||||
test_bsearch(test, 5, BsearchPolicy::LAST); // 11
|
||||
test_bsearch(test, 7, BsearchPolicy::FIRST_NOT_LESS); // 13
|
||||
test_bsearch(test, 7, BsearchPolicy::LAST_NOT_GREATER); // 12
|
||||
test_bsearch(test, 7, BsearchPolicy::FIRST); // 14
|
||||
test_bsearch(test, 8); // 13
|
||||
test_bsearch(test, 8, BsearchPolicy::FIRST); // 13
|
||||
test_bsearch(test, 8, BsearchPolicy::LAST); // 13
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
0
c-cpp/17_skiplist/.gitkeep
Normal file
0
c-cpp/17_skiplist/.gitkeep
Normal file
363
c-cpp/17_skiplist/SkipList.cpp
Normal file
363
c-cpp/17_skiplist/SkipList.cpp
Normal file
@ -0,0 +1,363 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <random>
|
||||
#include <ctime>
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* 跳表的一种实现方法。
|
||||
* 跳表中存储的是正整数,并且存储的是不重复的。
|
||||
*
|
||||
* 跳表的C++版本.
|
||||
* 翻译JAVA版本 原作者 Author:ZHENG
|
||||
*
|
||||
* Author:puhuaqiang
|
||||
*
|
||||
* 跳表结构:
|
||||
*
|
||||
* 第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
|
||||
* 如果N1是本节点,则 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<<std::endl;
|
||||
/// 打印所有等级结构
|
||||
skipList.PrintAll(-1);
|
||||
/// 查找
|
||||
std::cout<<std::endl;
|
||||
CNode* lpNode = skipList.Find(27);
|
||||
if(NULL != lpNode){
|
||||
std::cout<<"查找值为27的节点,找到该节点,节点值:"<<lpNode->GetData()<<std::endl;
|
||||
}else{
|
||||
std::cout<<"查找值为27的节点,未找到该节点"<<std::endl;
|
||||
}
|
||||
/// 删除
|
||||
std::cout<<std::endl;
|
||||
int ret = skipList.Delete(46);
|
||||
if(0 == ret){
|
||||
std::cout<<"查找值为46的节点,找到该节点,并删除成功"<<std::endl;
|
||||
}else{
|
||||
std::cout<<"查找值为46的节点,找到该节点,删除失败"<<std::endl;
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
//打印所有等级结构
|
||||
skipList.PrintAll(-1);
|
||||
std::cin.ignore();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CNode::CNode()
|
||||
{
|
||||
m_data = -1;
|
||||
m_iMaxLevel = 0;
|
||||
for(int i=0; i<MAX_LEVEL; i++){
|
||||
m_lpForwards[i] = NULL;
|
||||
}
|
||||
}
|
||||
CNode::~CNode()
|
||||
{
|
||||
|
||||
}
|
||||
CNode** CNode::GetIdxList()
|
||||
{
|
||||
return m_lpForwards;
|
||||
}
|
||||
|
||||
void CNode::SetData(int v)
|
||||
{
|
||||
m_data = v;
|
||||
}
|
||||
int CNode::GetData()
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
void CNode::SetLevel(int l)
|
||||
{
|
||||
m_iMaxLevel = l;
|
||||
}
|
||||
std::string CNode::toString()
|
||||
{
|
||||
char tmp[32];
|
||||
std::string ret;
|
||||
|
||||
ret.append("{ data: ");
|
||||
sprintf(tmp, "%d", m_data);
|
||||
ret.append(tmp);
|
||||
ret.append("; levels: ");
|
||||
sprintf(tmp, "%d", m_iMaxLevel);
|
||||
ret.append(tmp);
|
||||
ret.append(" }");
|
||||
return ret;
|
||||
}
|
||||
|
||||
CSkipList::CSkipList()
|
||||
{
|
||||
levelCount = 1;
|
||||
m_lpHead = new CNode();
|
||||
}
|
||||
CSkipList::~CSkipList()
|
||||
{
|
||||
|
||||
}
|
||||
CNode* CSkipList::Find(int v)
|
||||
{
|
||||
CNode* lpNode = m_lpHead;
|
||||
/**
|
||||
* 从 最大级索引链表开始查找.
|
||||
* K -> 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,则 新的节点会在索引1、2、3上的链表都存在
|
||||
*/
|
||||
int level = RandomLevel();
|
||||
lpNewNode->SetData(v);
|
||||
lpNewNode->SetLevel(level);
|
||||
|
||||
/**
|
||||
* 临时索引链表
|
||||
* 主要是得到新的节点在每个索引链表上的位置
|
||||
*/
|
||||
CNode *lpUpdateNode[level];
|
||||
for(int i=0; i<level; i++){
|
||||
/// 每个索引链表的头节点
|
||||
lpUpdateNode[i] =m_lpHead;
|
||||
}
|
||||
CNode* lpFind = m_lpHead;
|
||||
for(int i= level-1; i >= 0; --i){
|
||||
/**
|
||||
* 查找位置
|
||||
* eg. 第1级 1 7 10
|
||||
* 如果插入的是 6
|
||||
* lpFind->GetIdxList()[i]->GetData() : 表示节点lpFind在第1级索引的下一个节点的数据
|
||||
* 当 "lpFind->GetIdxList()[i]->GetData() < v"不成立的时候,
|
||||
* 新节点就要插入到 lpFind节点的后面, lpFind->GetIdxList()[i] 节点的前面
|
||||
* 即在这里 lpFind就是1 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; i<level; ++i){
|
||||
/**
|
||||
* 重新设置链表指针位置
|
||||
* eg 第1级索引 1 7 10
|
||||
* 插入6.
|
||||
* lpUpdateNode[i] 节点是1; lpUpdateNode[i]->GetIdxList()[i]节点是7
|
||||
*
|
||||
* 这2句代码就是 把6放在 1和7之间
|
||||
*/
|
||||
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<<lpNode->GetIdxList()[0]->toString().data()<<std::endl;
|
||||
lpNode = lpNode->GetIdxList()[0];
|
||||
}
|
||||
}
|
||||
void CSkipList::PrintAll(int l)
|
||||
{
|
||||
for(int i=MAX_LEVEL-1; i>=0;--i){
|
||||
CNode* lpNode = m_lpHead;
|
||||
std::cout<<"第"<<i<<"级:"<<std::endl;
|
||||
if((l < 0) || ((l >= 0) && (l == i))){
|
||||
while(NULL != lpNode->GetIdxList()[i]){
|
||||
std::cout<<lpNode->GetIdxList()[i]->GetData()<<" ";
|
||||
lpNode = lpNode->GetIdxList()[i];
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
if(l >= 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int GetRandom()
|
||||
{
|
||||
static int _count = 1;
|
||||
std::default_random_engine generator(time(0) + _count);
|
||||
std::uniform_int_distribution<int> 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<MAX_LEVEL; ++i){
|
||||
if(1 == (GetRandom()%3)){
|
||||
level++;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
214
c-cpp/17_skiplist/skiplist.c
Normal file
214
c-cpp/17_skiplist/skiplist.c
Normal file
@ -0,0 +1,214 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
// 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;
|
||||
}
|
186
c-cpp/17_skiplist/skiplist.hpp
Normal file
186
c-cpp/17_skiplist/skiplist.hpp
Normal file
@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/29.
|
||||
*/
|
||||
|
||||
#ifndef SKIPLIST_SKIPLIST_HPP_
|
||||
#define SKIPLIST_SKIPLIST_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
template <typename Value>
|
||||
class skiplist {
|
||||
public:
|
||||
using value_type = Value;
|
||||
using hash_type = std::hash<value_type>;
|
||||
using key_type = typename hash_type::result_type;
|
||||
using size_type = size_t;
|
||||
|
||||
private:
|
||||
struct InternalNode {
|
||||
value_type value;
|
||||
const key_type key;
|
||||
std::vector<InternalNode*> forwards; // pointers to successor nodes
|
||||
|
||||
InternalNode(const key_type& k, const size_type lv)
|
||||
: value(), key(k), forwards(lv, nullptr) {}
|
||||
InternalNode(const value_type& v, const size_type lv)
|
||||
: value(v), key(hash_type()(value)), forwards(lv, nullptr) {}
|
||||
};
|
||||
using node_type = InternalNode;
|
||||
|
||||
private:
|
||||
const size_type MAX_LEVEL = 16;
|
||||
const double PROBABILITY = 0.5;
|
||||
const unsigned int seed =
|
||||
std::chrono::system_clock::now().time_since_epoch().count();
|
||||
mutable
|
||||
std::default_random_engine generator = std::default_random_engine(seed);
|
||||
mutable
|
||||
std::binomial_distribution<size_type> distribution =
|
||||
std::binomial_distribution<size_type>(MAX_LEVEL - 1, PROBABILITY);
|
||||
node_type* head = nullptr;
|
||||
node_type* nil = nullptr;
|
||||
static const value_type default_value;
|
||||
|
||||
public:
|
||||
skiplist() {
|
||||
key_type head_key = std::numeric_limits<key_type>::min();
|
||||
key_type nil_key = std::numeric_limits<key_type>::max();
|
||||
head = new node_type(head_key, MAX_LEVEL);
|
||||
nil = new node_type(nil_key, MAX_LEVEL);
|
||||
std::fill(head->forwards.begin(), head->forwards.end(), nil);
|
||||
}
|
||||
skiplist(std::initializer_list<value_type> init) : skiplist() {
|
||||
for (const value_type& v : init) {
|
||||
insert(v);
|
||||
}
|
||||
}
|
||||
skiplist(const skiplist& other) = delete;
|
||||
skiplist(skiplist&& other) :
|
||||
MAX_LEVEL(std::move(other.MAX_LEVEL)),
|
||||
PROBABILITY(std::move(other.PROBABILITY)),
|
||||
seed(std::move(other.seed)),
|
||||
generator(std::move(other.generator)),
|
||||
distribution(std::move(other.distribution)),
|
||||
head(other.head),
|
||||
nil(other.nil) {
|
||||
other.head = nullptr;
|
||||
other.nil = nullptr;
|
||||
}
|
||||
~skiplist() {
|
||||
node_type* node = head;
|
||||
while (nullptr != node and nullptr != node->forwards[0]) {
|
||||
node_type* tmp = node;
|
||||
node = node->forwards[0];
|
||||
delete tmp;
|
||||
}
|
||||
delete node;
|
||||
}
|
||||
skiplist& operator=(const skiplist& other) = delete;
|
||||
skiplist& operator=(skiplist&& other) = delete;
|
||||
|
||||
private:
|
||||
inline size_type get_random_level() const {
|
||||
return distribution(generator);
|
||||
}
|
||||
static size_type get_node_level(const node_type* node) {
|
||||
return node->forwards.size();
|
||||
}
|
||||
static node_type* make_node(const value_type& v, const size_type lv) {
|
||||
return new node_type(v, lv);
|
||||
}
|
||||
/**
|
||||
* @brief returns a pointer to the first node such that
|
||||
* node->key == hash_type()(v) and node->value == v.
|
||||
*/
|
||||
node_type* get_first_equal(const value_type& v) const {
|
||||
const key_type target = hash_type()(v);
|
||||
node_type* x = head;
|
||||
for (size_type i = get_node_level(head); i > 0; --i) {
|
||||
while (x->forwards[i - 1]->key < target or
|
||||
x->forwards[i - 1]->key == target and x->forwards[i - 1]->value != v) {
|
||||
x = x->forwards[i - 1];
|
||||
}
|
||||
}
|
||||
return x->forwards[0];
|
||||
}
|
||||
/**
|
||||
* @brief returns a collection of nodes.
|
||||
* returns[i] is the pointer to the last node at level i + 1
|
||||
* such that returns[i]->key < hash_type()(v) or
|
||||
* returns[i]->key == hash_type()(v) but returns[i]->value != v.
|
||||
*/
|
||||
std::vector<node_type*> get_predecessors(const value_type& v) const {
|
||||
const key_type target = hash_type()(v);
|
||||
std::vector<node_type*> results(get_node_level(head), nullptr);
|
||||
node_type* x = head;
|
||||
for (size_type i = get_node_level(head); i > 0; --i) {
|
||||
while (x->forwards[i - 1]->key < target or
|
||||
x->forwards[i - 1]->key == target and x->forwards[i - 1]->value != v) {
|
||||
x = x->forwards[i - 1];
|
||||
}
|
||||
results[i - 1] = x;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public:
|
||||
const value_type& find(const value_type& target) {
|
||||
node_type* x = get_first_equal(target);
|
||||
if (nullptr != x and nil != x and x->value == target) {
|
||||
return x->value;
|
||||
} else {
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
void insert(const value_type& value) {
|
||||
std::vector<node_type*> preds = get_predecessors(value);
|
||||
const size_type new_node_lv = get_random_level();
|
||||
node_type* new_node = make_node(value, new_node_lv);
|
||||
for (size_type i = 0; i != new_node_lv; ++i) {
|
||||
new_node->forwards[i] = preds[i]->forwards[i];
|
||||
preds[i]->forwards[i] = new_node;
|
||||
}
|
||||
}
|
||||
void erase(const value_type& value) {
|
||||
std::vector<node_type*> preds = get_predecessors(value);
|
||||
|
||||
node_type* node = preds[0]->forwards[0];
|
||||
if (node == nil or node->value != value) { return; }
|
||||
|
||||
for (size_type i = 0; i != get_node_level(node); ++i) {
|
||||
preds[i]->forwards[i] = node->forwards[i];
|
||||
}
|
||||
delete node;
|
||||
}
|
||||
void print(std::ostream& os) const {
|
||||
node_type* list = head->forwards[0];
|
||||
os << "{";
|
||||
|
||||
while (list != nil) {
|
||||
os << "key: " << list->key << " value: " << list->value
|
||||
<< " level: " << get_node_level(list);
|
||||
|
||||
list = list->forwards[0];
|
||||
|
||||
if (list != nil) os << " : ";
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Value>
|
||||
const typename skiplist<Value>::value_type skiplist<Value>::default_value =
|
||||
typename skiplist<Value>::value_type();
|
||||
|
||||
#endif // SKIPLIST_SKIPLIST_HPP_
|
||||
|
346
c-cpp/17_skiplist/skiplist_c/skiplist.c
Normal file
346
c-cpp/17_skiplist/skiplist_c/skiplist.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*************************************************************************
|
||||
> File Name: skiplist.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-31
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
#include<assert.h>
|
||||
#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;
|
||||
}
|
33
c-cpp/17_skiplist/skiplist_c/skiplist.h
Normal file
33
c-cpp/17_skiplist/skiplist_c/skiplist.h
Normal file
@ -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
|
67
c-cpp/17_skiplist/skiplist_test.cc
Normal file
67
c-cpp/17_skiplist/skiplist_test.cc
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/30.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "skiplist.hpp"
|
||||
|
||||
int main() {
|
||||
// 1. Initialize a skip list for test
|
||||
// * default constructor
|
||||
// * constructor with initializer list
|
||||
// * insert
|
||||
skiplist<std::string> ss{"1", "2", "3", "4", "5"};
|
||||
|
||||
// 1a. show
|
||||
// * print
|
||||
ss.print(std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
// 2. move construction
|
||||
// * move constructor
|
||||
skiplist<std::string> s(std::move(ss));
|
||||
|
||||
// 2a. show
|
||||
// * print
|
||||
s.print(std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
// 3.a find something doesn't exist.
|
||||
// * find
|
||||
auto f = s.find("0");
|
||||
if (!f.empty()) {
|
||||
std::cout << "Node found!\nvalue: " << f << '\n';
|
||||
} else {
|
||||
std::cout << "Node NOT found!\n";
|
||||
}
|
||||
|
||||
// 3.b find something does exist.
|
||||
// * find
|
||||
auto ff = s.find("1");
|
||||
if (!ff.empty()) {
|
||||
std::cout << "Node found!\tvalue: " << ff << '\n';
|
||||
} else {
|
||||
std::cout << "Node NOT found!\n";
|
||||
}
|
||||
|
||||
// 4. insert() - reassign
|
||||
s.insert("TEST");
|
||||
|
||||
// 4a. print()
|
||||
s.print(std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
// 5. erase()
|
||||
s.erase("TEST");
|
||||
|
||||
// 5a. print();
|
||||
s.print(std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "\nDone!\n";
|
||||
|
||||
return 0;
|
||||
// 6. destructor
|
||||
}
|
362
c-cpp/17_skiplist/skiplist_tr.hpp
Normal file
362
c-cpp/17_skiplist/skiplist_tr.hpp
Normal file
@ -0,0 +1,362 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/30.
|
||||
*/
|
||||
|
||||
#ifndef SKIPLIST_SKIPLIST_TR_HPP_
|
||||
#define SKIPLIST_SKIPLIST_TR_HPP_
|
||||
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <random>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
|
||||
namespace skiplist_detail {
|
||||
template <typename Key, typename Value>
|
||||
struct InternalNode {
|
||||
using iterator = typename std::list<InternalNode>::iterator;
|
||||
const Key key;
|
||||
std::multiset<Value> values;
|
||||
std::vector<iterator> forwards;
|
||||
|
||||
InternalNode() = delete;
|
||||
explicit InternalNode(const Key& k) : key(k) {}
|
||||
};
|
||||
|
||||
template <typename IntType>
|
||||
class random_level {
|
||||
private:
|
||||
mutable std::random_device rd;
|
||||
mutable std::mt19937 gen = std::mt19937(rd());
|
||||
mutable std::binomial_distribution<IntType> dist;
|
||||
|
||||
public:
|
||||
random_level(IntType max_level, double prob) : dist(max_level - 1, prob) {}
|
||||
inline IntType operator()() const { return dist(gen); }
|
||||
};
|
||||
} // namespace skiplist_detail
|
||||
|
||||
enum class erase_policy { ALL, SINGLE };
|
||||
|
||||
template <typename Value,
|
||||
typename Hash = std::hash<Value>,
|
||||
size_t Factor = 2>
|
||||
class skiplist {
|
||||
public:
|
||||
using value_type = Value;
|
||||
using size_type = size_t;
|
||||
using hasher = Hash;
|
||||
using hash_type = typename Hash::result_type;
|
||||
using compare = std::less<hash_type>;
|
||||
using node_type = skiplist_detail::InternalNode<hash_type, value_type>;
|
||||
using container = std::list<node_type>;
|
||||
using iterator = typename container::iterator;
|
||||
using const_iterator = typename container::const_iterator;
|
||||
static_assert(std::is_same<iterator, typename node_type::iterator>::value,
|
||||
"STATIC ASSERT FAILED! iterator type differs.");
|
||||
|
||||
private:
|
||||
size_type max_lv_ = 2;
|
||||
double prob_ = 0.5;
|
||||
mutable skiplist_detail::random_level<size_type> rl_;
|
||||
container cont_;
|
||||
|
||||
public:
|
||||
skiplist() : rl_(max_lv_, prob_) {
|
||||
init_internally();
|
||||
}
|
||||
explicit skiplist(const size_type max_lv, const double prob = 0.5)
|
||||
: max_lv_(max_lv), prob_(prob), rl_(max_lv_, prob_) {
|
||||
init_internally();
|
||||
}
|
||||
skiplist(skiplist&& other) = default;
|
||||
skiplist& operator=(skiplist&& other) = default;
|
||||
~skiplist() = default;
|
||||
template <typename InputIt>
|
||||
skiplist(InputIt first, InputIt last) : skiplist() {
|
||||
using value_type_in_iter = typename std::iterator_traits<InputIt>::value_type;
|
||||
static_assert(std::is_same<value_type, value_type_in_iter>::value,
|
||||
"STATIC ASSERT FAILED! Value in InputIt should be the same to value_type.");
|
||||
for (InputIt i = first; i != last; ++i) {
|
||||
insert(*i);
|
||||
}
|
||||
}
|
||||
skiplist(std::initializer_list<value_type> init) : skiplist(init.begin(), init.end()) {}
|
||||
|
||||
private: // noncopyable
|
||||
skiplist(const skiplist&) = delete;
|
||||
skiplist& operator=(const skiplist&) = delete;
|
||||
|
||||
private:
|
||||
void init_internally() {
|
||||
const hash_type tail_key = std::numeric_limits<hash_type>::max();
|
||||
node_type tail(tail_key);
|
||||
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<hash_type>::min();
|
||||
node_type head(head_key);
|
||||
head.forwards.resize(max_lv_, tail_iter);
|
||||
cont_.insert(cont_.begin(), std::move(head));
|
||||
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
assert(cont_.begin()->key == head_key);
|
||||
for (auto it : cont_.begin()->forwards) {
|
||||
assert(it->key == tail_key);
|
||||
}
|
||||
for (auto it : std::next(cont_.begin())->forwards) {
|
||||
assert(it == cont_.end());
|
||||
}
|
||||
std::cerr << "UT_DEBUG: all assert in init_internally() success!\n";
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* @brief return a const_iterator points to the last element
|
||||
* such that its hash_key <= target_hash_key
|
||||
*/
|
||||
const_iterator find_helper(const hash_type& key) const {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "Keys contained in the list: ";
|
||||
for (auto node : cont_) {
|
||||
std::cerr << node.key << ' ';
|
||||
}
|
||||
std::cerr << '\n';
|
||||
std::cerr << "Target key: " << key << '\n';
|
||||
#endif
|
||||
const_iterator iter = begin();
|
||||
for (size_type i = 0; i != max_lv_; ++i) {
|
||||
size_type focus = max_lv_ - 1 - i;
|
||||
// invariant: iter->key <= key
|
||||
while (not compare()(key, iter->forwards[focus]->key)) {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "i: " << i << " focus: " << focus << ". "
|
||||
<< "since iter->forwards[focus]->key[" << iter->forwards[focus]->key
|
||||
<< "] <= key[" << key << "], ";
|
||||
#endif
|
||||
iter = iter->forwards[focus];
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "step forward iter to [" << iter->key << "]\n";
|
||||
#endif
|
||||
}
|
||||
// result: iter->key <= key < iter->forwards[focus]->key
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "The following fact holds at level " << focus
|
||||
<< ": iter->key[" << iter->key << "] <= key["
|
||||
<< key << "] < iter->forwards[focus]->key[" << iter->forwards[focus]->key
|
||||
<<"].\n";
|
||||
#endif
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
std::vector<iterator> find_predecessors(const hash_type& key, const size_type& lv) {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "Keys contained in the list: ";
|
||||
for (auto node : cont_) {
|
||||
std::cerr << node.key << ' ';
|
||||
}
|
||||
std::cerr << '\n';
|
||||
std::cerr << "Target key: " << key << '\n';
|
||||
#endif
|
||||
std::vector<iterator> res;
|
||||
res.resize(lv + 1);
|
||||
iterator iter = begin();
|
||||
for (size_type i = 0; i != max_lv_; ++i) {
|
||||
size_type focus = max_lv_ - 1 - i;
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "i: " << i << " focus: " << focus << ".\n";
|
||||
#endif
|
||||
// invariant: iter->key < key
|
||||
while (compare()(iter->forwards[focus]->key, key)) {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "since iter->forwards[focus]->key[" << iter->forwards[focus]->key
|
||||
<< "] < key[" << key << "], ";
|
||||
#endif
|
||||
iter = iter->forwards[focus];
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "step forward iter to [" << iter->key << "]\n";
|
||||
#endif
|
||||
}
|
||||
// result: iter->key < key <= iter->forwards[focus]->key
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "The following fact holds at level " << focus
|
||||
<< ": iter->key[" << iter->key << "] < key[" << key
|
||||
<< "] <= iter->forwards[focus]->key[" << iter->forwards[focus]->key
|
||||
<<"].\n";
|
||||
#endif
|
||||
if (focus < lv + 1) {
|
||||
res[focus] = iter;
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "predecessor at level [" << focus
|
||||
<< "] has been recorded, while level upper limit is " << lv <<".\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
size_type size() const {
|
||||
return cont_.size() - 2;
|
||||
}
|
||||
bool empty() const {
|
||||
return size() == 0;
|
||||
}
|
||||
iterator begin() {
|
||||
return cont_.begin();
|
||||
}
|
||||
const_iterator begin() const {
|
||||
return cont_.cbegin();
|
||||
}
|
||||
const_iterator cbegin() const {
|
||||
return cont_.cbegin();
|
||||
}
|
||||
iterator end() {
|
||||
return cont_.end();
|
||||
}
|
||||
const_iterator end() const {
|
||||
return cont_.cend();
|
||||
}
|
||||
const_iterator cend() const {
|
||||
return cont_.cend();
|
||||
}
|
||||
void grow(const size_type new_max_lv) {
|
||||
if (max_lv_ < new_max_lv) {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "grow from [" << max_lv_ << "] to ["
|
||||
<< new_max_lv << "]!\n";
|
||||
#endif
|
||||
max_lv_ = new_max_lv;
|
||||
|
||||
iterator tail = std::prev(cont_.end());
|
||||
auto beg_tail = tail->forwards.end();
|
||||
tail->forwards.resize(max_lv_, cont_.end());
|
||||
|
||||
iterator head = cont_.begin();
|
||||
auto beg_head = head->forwards.end();
|
||||
head->forwards.resize(max_lv_, tail);
|
||||
|
||||
return;
|
||||
} else {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "abandon growing!\n";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
void grow() {
|
||||
grow(Factor * max_lv_);
|
||||
}
|
||||
size_type capability() const {
|
||||
return std::pow(Factor, max_lv_);
|
||||
}
|
||||
|
||||
public:
|
||||
const_iterator find(const value_type& target) const {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "finding [" << target << "]!\n";
|
||||
#endif
|
||||
const hash_type key = hasher()(target);
|
||||
const_iterator iter = find_helper(key);
|
||||
return (iter->key == key) ? iter : cont_.end();
|
||||
}
|
||||
void insert(const value_type& target) {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "inserting [" << target << "]!\n";
|
||||
#endif
|
||||
if (size() > static_cast<double>(Factor - 1) / Factor * capability()) {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "size[" << size() << "], Factor[" << Factor << "], capability[" << capability() << "]!\n";
|
||||
#endif
|
||||
grow();
|
||||
}
|
||||
const hash_type key = hasher()(target);
|
||||
const size_type lv = rl_();
|
||||
std::vector<iterator> predecessors = find_predecessors(key, lv);
|
||||
if (predecessors[0]->forwards[0]->key == key) { // key already in skiplist
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "key [" << key << "] already in the skiplist, insert directly!\n";
|
||||
#endif
|
||||
predecessors[0]->forwards[0]->values.insert(target);
|
||||
return;
|
||||
} else {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "key [" << key << "] not in the skiplist, insert a new node!\n";
|
||||
#endif
|
||||
node_type node(key);
|
||||
node.forwards.resize(lv + 1);
|
||||
node.values.insert(target);
|
||||
iterator inserted = cont_.insert(predecessors[0]->forwards[0], std::move(node));
|
||||
for (size_type i = 0; i != lv + 1; ++i) {
|
||||
inserted->forwards[i] = predecessors[i]->forwards[i];
|
||||
predecessors[i]->forwards[i] = inserted;
|
||||
}
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
assert(inserted->forwards[0] == std::next(inserted));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
void erase(const value_type& target,
|
||||
const erase_policy policy = erase_policy::ALL) {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "erasing [" << target << "]!\n";
|
||||
#endif
|
||||
const hash_type key = hasher()(target);
|
||||
std::vector<iterator> predecessors = find_predecessors(key, max_lv_);
|
||||
if (predecessors[0]->forwards[0]->key == key) { // hit
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "key [" << key << "] is in the skiplist!\n";
|
||||
#endif
|
||||
iterator found = predecessors[0]->forwards[0];
|
||||
for (auto iter = found->values.begin(); iter != found->values.end(); ) {
|
||||
if (policy == erase_policy::ALL) {
|
||||
if (*iter == target) {
|
||||
iter = found->values.erase(iter);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
} else if (policy == erase_policy::SINGLE) {
|
||||
if (*iter == target) {
|
||||
found->values.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "target(s) removed!\n";
|
||||
#endif
|
||||
if (found->values.empty()) {
|
||||
const size_type lvp1 = found->forwards.size(); // lv plus 1
|
||||
for (size_type i = 0; i != lvp1; ++i) {
|
||||
predecessors[i]->forwards[i] = found->forwards[i];
|
||||
}
|
||||
cont_.erase(found);
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "empty node removed!\n";
|
||||
#endif
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
#ifdef LIAM_UT_DEBUG_
|
||||
std::cerr << "key [" << key << "] is not in the skiplist, do nothing!\n";
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SKIPLIST_SKIPLIST_TR_HPP_
|
107
c-cpp/17_skiplist/skiplist_tr_test.cc
Normal file
107
c-cpp/17_skiplist/skiplist_tr_test.cc
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/30.
|
||||
*/
|
||||
#include <assert.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "skiplist_tr.hpp"
|
||||
|
||||
int main() {
|
||||
// 1. UT for skiplist_detail::random_level
|
||||
skiplist_detail::random_level<size_t> rl(5, 0.5);
|
||||
std::map<size_t, size_t> hist;
|
||||
for (size_t i = 0; i != 10000; ++i) {
|
||||
++hist[rl()];
|
||||
}
|
||||
for (auto p : hist) {
|
||||
std::cout << p.first << ' ' << std::string(p.second / 100, '*') << '\n';
|
||||
}
|
||||
|
||||
// 2. UT for skiplist(), init_internally(), size(), empty()
|
||||
skiplist<std::string> sl_default;
|
||||
assert(sl_default.empty());
|
||||
// 2.1. UT for grow with abandon
|
||||
sl_default.grow(1);
|
||||
assert(sl_default.capability() == 4);
|
||||
// 2.2. UT for grow
|
||||
sl_default.grow(10);
|
||||
assert(sl_default.capability() == 1024);
|
||||
|
||||
// 3. UT for constructor of initializer_list and InputIt, init_internally(), insert(),
|
||||
// find_predecessors()
|
||||
skiplist<std::string> sl{"hello", "world", "!"};
|
||||
assert(not sl.empty());
|
||||
assert(3 == sl.size());
|
||||
|
||||
// 4. UT for find() find_helper()
|
||||
auto search = sl_default.find("nonexist");
|
||||
assert(search == sl_default.cend());
|
||||
assert(search == sl_default.end());
|
||||
search = sl.find("hello");
|
||||
assert(search != sl.cend());
|
||||
assert(search != sl.end());
|
||||
search = sl.find("nonexist");
|
||||
assert(search == sl.cend());
|
||||
assert(search == sl.end());
|
||||
|
||||
// 5. UT for insert(), find_predecessors()
|
||||
// 5.1. UT for insert a already-exist item
|
||||
sl.insert("hello");
|
||||
search = sl.find("hello");
|
||||
assert(search != sl.cend());
|
||||
assert(search != sl.end());
|
||||
// 5.2. UT for insert a new incoming item
|
||||
search = sl.find("now exist");
|
||||
assert(search == sl.cend());
|
||||
assert(search == sl.end());
|
||||
sl.insert("now exist");
|
||||
search = sl.find("now exist");
|
||||
assert(search != sl.cend());
|
||||
assert(search != sl.end());
|
||||
|
||||
// 6. UT for erase(), find_predecessors()
|
||||
sl.insert("hello");
|
||||
sl.insert("hello");
|
||||
sl.insert("hello");
|
||||
sl.insert("hello");
|
||||
// 6.1. UT for erase single item
|
||||
sl.erase("hello", erase_policy::SINGLE);
|
||||
search = sl.find("hello");
|
||||
assert(search != sl.cend());
|
||||
assert(search != sl.end());
|
||||
// 6.2. UT for erase all items
|
||||
sl.erase("hello", erase_policy::ALL);
|
||||
search = sl.find("hello");
|
||||
assert(search == sl.cend());
|
||||
assert(search == sl.end());
|
||||
// 6.3 UT for erase non-exist item
|
||||
sl.erase("nonexist");
|
||||
|
||||
// 7. UT for insert() behind erase()
|
||||
// 7.1. different word
|
||||
sl.insert("world");
|
||||
search = sl.find("world");
|
||||
assert(search != sl.cend());
|
||||
assert(search != sl.end());
|
||||
assert(search->values.count("world") == 2);
|
||||
// 7.1. same word, also UT for grow()
|
||||
search = sl.find("hello");
|
||||
assert(search == sl.cend());
|
||||
assert(search == sl.end());
|
||||
sl.insert("hello");
|
||||
sl.insert("hello");
|
||||
sl.insert("hello");
|
||||
sl.insert("hello");
|
||||
sl.insert("hello");
|
||||
search = sl.find("hello");
|
||||
assert(search != sl.cend());
|
||||
assert(search != sl.end());
|
||||
assert(search->values.count("hello") == 5);
|
||||
|
||||
return 0;
|
||||
// 8. UT for ~skiplist()
|
||||
}
|
||||
|
364
c-cpp/18_hash/listhash/listhash.c
Normal file
364
c-cpp/18_hash/listhash/listhash.c
Normal file
@ -0,0 +1,364 @@
|
||||
/*************************************************************************
|
||||
> File Name: listhash.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-11-07
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
#include<assert.h>
|
||||
#include"listhash.h"
|
||||
|
||||
#ifdef MEMORY_TEST
|
||||
#include<mcheck.h>
|
||||
#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 <h->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;
|
||||
|
||||
}
|
53
c-cpp/18_hash/listhash/listhash.h
Executable file
53
c-cpp/18_hash/listhash/listhash.h
Executable file
@ -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
|
186
c-cpp/18_hashtable/hashtable.c
Normal file
186
c-cpp/18_hashtable/hashtable.c
Normal file
@ -0,0 +1,186 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* 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;
|
||||
}
|
114
c-cpp/19_Dlisthash/Dlist.h
Executable file
114
c-cpp/19_Dlisthash/Dlist.h
Executable file
@ -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
|
398
c-cpp/19_Dlisthash/LinkedHashMap.c
Executable file
398
c-cpp/19_Dlisthash/LinkedHashMap.c
Executable file
@ -0,0 +1,398 @@
|
||||
/*************************************************************************
|
||||
> File Name: LinkedHashMap.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-11-08
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<assert.h>
|
||||
#include<string.h>
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#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;
|
||||
|
||||
}
|
||||
|
40
c-cpp/19_Dlisthash/LinkedHashMap.h
Executable file
40
c-cpp/19_Dlisthash/LinkedHashMap.h
Executable file
@ -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
|
83
c-cpp/23_binarytree/binarytree.c
Normal file
83
c-cpp/23_binarytree/binarytree.c
Normal file
@ -0,0 +1,83 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* 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;
|
||||
}
|
213
c-cpp/23_binarytree/tree/binarytree.c
Normal file
213
c-cpp/23_binarytree/tree/binarytree.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*************************************************************************
|
||||
> File Name: binarytree.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-11-12
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<assert.h>
|
||||
|
||||
#include<string.h>
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#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;
|
||||
}
|
||||
|
85
c-cpp/23_binarytree/tree/list_queue.c
Normal file
85
c-cpp/23_binarytree/tree/list_queue.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*************************************************************************
|
||||
> File Name: list_queue.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-10-13
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<stdio.h>
|
||||
#include<stdlib.h>
|
||||
#include<string.h>
|
||||
#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;
|
||||
}
|
30
c-cpp/23_binarytree/tree/list_queue.h
Normal file
30
c-cpp/23_binarytree/tree/list_queue.h
Normal file
@ -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
|
322
c-cpp/24_binarysearchtree/binarysearchtree.c
Normal file
322
c-cpp/24_binarysearchtree/binarysearchtree.c
Normal file
@ -0,0 +1,322 @@
|
||||
/*************************************************************************
|
||||
> File Name: binarysearchtree.c
|
||||
> Author: jinshaohui
|
||||
> Mail: jinshaohui789@163.com
|
||||
> Time: 18-11-12
|
||||
> Desc:
|
||||
************************************************************************/
|
||||
#include<assert.h>
|
||||
#include<string.h>
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#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;
|
||||
}
|
34
c-cpp/24_binarysearchtree/binarysearchtree.h
Normal file
34
c-cpp/24_binarysearchtree/binarysearchtree.h
Normal file
@ -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
|
197
c-cpp/24_binarysearchtree/bst.c
Normal file
197
c-cpp/24_binarysearchtree/bst.c
Normal file
@ -0,0 +1,197 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
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;
|
||||
}
|
160
c-cpp/28_heap/heap.c
Normal file
160
c-cpp/28_heap/heap.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* 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;
|
||||
}
|
197
c-cpp/bst.c
Normal file
197
c-cpp/bst.c
Normal file
@ -0,0 +1,197 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
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;
|
||||
}
|
63
f21
Normal file
63
f21
Normal file
@ -0,0 +1,63 @@
|
||||
// A Stack based C++ program to find next
|
||||
// greater element for all array elements
|
||||
// in same order as input.
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* prints element and NGE pair for all
|
||||
elements of arr[] of size n */
|
||||
void printNGE(int arr[], int n)
|
||||
{
|
||||
stack<int> s;
|
||||
unordered_map<int, int> mp;
|
||||
|
||||
/* push the first element to stack */
|
||||
s.push(arr[0]);
|
||||
|
||||
|
||||
// iterate for rest of the elements
|
||||
for (int i = 1; i < n; i++) {
|
||||
|
||||
if (s.empty()) {
|
||||
s.push(arr[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if stack is not empty, then
|
||||
pop an element from stack.
|
||||
If the popped element is smaller
|
||||
than next, then
|
||||
a) print the pair
|
||||
b) keep popping while elements are
|
||||
smaller and stack is not empty */
|
||||
while (s.empty() == false && s.top() < arr[i]) {
|
||||
mp[s.top()] = arr[i];
|
||||
s.pop();
|
||||
}
|
||||
|
||||
/* push next to stack so that we can find
|
||||
next smaller for it */
|
||||
s.push(arr[i]);
|
||||
}
|
||||
|
||||
/* After iterating over the loop, the remaining
|
||||
elements in stack do not have the next smaller
|
||||
element, so print -1 for them */
|
||||
while (s.empty() == false) {
|
||||
mp[s.top()] = -1;
|
||||
s.pop();
|
||||
}
|
||||
|
||||
for (int i=0; i<n; i++)
|
||||
cout << arr[i] << " ---> " << mp[arr[i]] << endl;
|
||||
}
|
||||
|
||||
/* Driver program to test above functions */
|
||||
int main()
|
||||
{
|
||||
int arr[] = { 11, 13, 21, 3 };
|
||||
int n = sizeof(arr) / sizeof(arr[0]);
|
||||
printNGE(arr, n);
|
||||
return 0;
|
||||
}
|
@ -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
|
||||
|
@ -45,3 +45,111 @@ func bs(a []int, v int, low, high int) int {
|
||||
return bs(a, v, mid+1, high)
|
||||
}
|
||||
}
|
||||
|
||||
//查找第一个等于给定值的元素
|
||||
func BinarySearchFirst(a []int, v int) int {
|
||||
n := len(a)
|
||||
if n == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
low := 0
|
||||
high := n - 1
|
||||
for low <= high {
|
||||
mid := (low + high) >> 1
|
||||
if a[mid] > v {
|
||||
high = mid - 1
|
||||
} else if a[mid] < v {
|
||||
low = mid + 1
|
||||
} else {
|
||||
if mid == 0 || a[mid-1] != v {
|
||||
return mid
|
||||
} else {
|
||||
high = mid - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
//查找最后一个值等于给定值的元素
|
||||
func BinarySearchLast(a []int, v int) int {
|
||||
n := len(a)
|
||||
if n == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
low := 0
|
||||
high := n - 1
|
||||
for low <= high {
|
||||
mid := (low + high) >> 1
|
||||
if a[mid] > v {
|
||||
high = mid - 1
|
||||
} else if a[mid] < v {
|
||||
low = mid + 1
|
||||
} else {
|
||||
if mid == n-1 || a[mid+1] != v {
|
||||
return mid
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
//查找第一个大于等于给定值的元素
|
||||
func BinarySearchFirstGT(a []int, v int) int {
|
||||
n := len(a)
|
||||
if n == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
low := 0
|
||||
high := n - 1
|
||||
for low <= high {
|
||||
mid := (high + low) >> 1
|
||||
if a[mid] > v {
|
||||
high = mid - 1
|
||||
} else if a[mid] < v {
|
||||
low = mid + 1
|
||||
} else {
|
||||
if mid != n-1 && a[mid+1] > v {
|
||||
return mid + 1
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
//查找最后一个小于等于给定值的元素
|
||||
func BinarySearchLastLT(a []int, v int) int {
|
||||
n := len(a)
|
||||
if n == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
low := 0
|
||||
high := n - 1
|
||||
for low <= high {
|
||||
mid := (low + high) >> 1
|
||||
if a[mid] > v {
|
||||
high = mid - 1
|
||||
} else if a[mid] < v {
|
||||
low = mid + 1
|
||||
} else {
|
||||
if mid == 0 || a[mid-1] < v {
|
||||
return mid - 1
|
||||
} else {
|
||||
high = mid - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
@ -25,3 +25,79 @@ func TestBinarySearchRecursive(t *testing.T) {
|
||||
t.Fatal(BinarySearch(a, 4))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinarySearchFirst(t *testing.T) {
|
||||
var a []int
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchFirst(a, 2) != 1 {
|
||||
t.Fatal(BinarySearchFirst(a, 2))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchFirst(a, 3) != 4 {
|
||||
t.Fatal(BinarySearchFirst(a, 3))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinarySearchLast(t *testing.T) {
|
||||
var a []int
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchLast(a, 2) != 3 {
|
||||
t.Fatal(BinarySearchLast(a, 2))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchLast(a, 3) != 4 {
|
||||
t.Fatal(BinarySearchLast(a, 3))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinarySearchFirstGT(t *testing.T) {
|
||||
var a []int
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchFirstGT(a, 2) != 4 {
|
||||
t.Fatal(BinarySearchFirstGT(a, 2))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchFirstGT(a, 1) != 1 {
|
||||
t.Fatal(BinarySearchFirstGT(a, 1))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchFirstGT(a, 3) != 5 {
|
||||
t.Fatal(BinarySearchFirstGT(a, 3))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchFirstGT(a, 4) != -1 {
|
||||
t.Fatal(BinarySearchFirstGT(a, 4))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinarySearchLastLT(t *testing.T) {
|
||||
var a []int
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchLastLT(a, 2) != 0 {
|
||||
t.Fatal(BinarySearchLastLT(a, 2))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchLastLT(a, 1) != -1 {
|
||||
t.Fatal(BinarySearchLastLT(a, 1))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchLastLT(a, 3) != 3 {
|
||||
t.Fatal(BinarySearchLastLT(a, 3))
|
||||
}
|
||||
|
||||
a = []int{1, 2, 2, 2, 3, 4}
|
||||
if BinarySearchLastLT(a, 4) != 4 {
|
||||
t.Fatal(BinarySearchLastLT(a, 4))
|
||||
}
|
||||
}
|
||||
|
177
go/17_skiplist/skiplist.go
Normal file
177
go/17_skiplist/skiplist.go
Normal file
@ -0,0 +1,177 @@
|
||||
package _7_skiplist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
const (
|
||||
//最高层数
|
||||
MAX_LEVEL = 16
|
||||
)
|
||||
|
||||
//跳表节点结构体
|
||||
type skipListNode struct {
|
||||
//跳表保存的值
|
||||
v interface{}
|
||||
//用于排序的分值
|
||||
score int
|
||||
//层高
|
||||
level int
|
||||
//每层前进指针
|
||||
forwards []*skipListNode
|
||||
}
|
||||
|
||||
//新建跳表节点
|
||||
func newSkipListNode(v interface{}, score, level int) *skipListNode {
|
||||
return &skipListNode{v: v, score: score, forwards: make([]*skipListNode, level, level), level: level}
|
||||
}
|
||||
|
||||
//跳表结构体
|
||||
type SkipList struct {
|
||||
//跳表头结点
|
||||
head *skipListNode
|
||||
//跳表当前层数
|
||||
level int
|
||||
//跳表长度
|
||||
length int
|
||||
}
|
||||
|
||||
//实例化跳表对象
|
||||
func NewSkipList() *SkipList {
|
||||
//头结点,便于操作
|
||||
head := newSkipListNode(0, math.MinInt32, MAX_LEVEL)
|
||||
return &SkipList{head, 1, 0}
|
||||
}
|
||||
|
||||
//获取跳表长度
|
||||
func (sl *SkipList) Length() int {
|
||||
return sl.length
|
||||
}
|
||||
|
||||
//获取跳表层级
|
||||
func (sl *SkipList) Level() int {
|
||||
return sl.level
|
||||
}
|
||||
|
||||
//插入节点到跳表中
|
||||
func (sl *SkipList) Insert(v interface{}, score int) int {
|
||||
if nil == v {
|
||||
return 1
|
||||
}
|
||||
|
||||
//查找插入位置
|
||||
cur := sl.head
|
||||
//记录每层的路径
|
||||
update := [MAX_LEVEL]*skipListNode{}
|
||||
i := MAX_LEVEL - 1
|
||||
for ; i >= 0; i-- {
|
||||
for nil != cur.forwards[i] {
|
||||
if cur.forwards[i].v == v {
|
||||
return 2
|
||||
}
|
||||
if cur.forwards[i].score > score {
|
||||
update[i] = cur
|
||||
break
|
||||
}
|
||||
cur = cur.forwards[i]
|
||||
}
|
||||
if nil == cur.forwards[i] {
|
||||
update[i] = cur
|
||||
}
|
||||
}
|
||||
|
||||
//通过随机算法获取该节点层数
|
||||
level := 1
|
||||
for i := 1; i < MAX_LEVEL; i++ {
|
||||
if rand.Int31()%7 == 1 {
|
||||
level++
|
||||
}
|
||||
}
|
||||
|
||||
//创建一个新的跳表节点
|
||||
newNode := newSkipListNode(v, score, level)
|
||||
|
||||
//原有节点连接
|
||||
for i := 0; i <= level-1; i++ {
|
||||
next := update[i].forwards[i]
|
||||
update[i].forwards[i] = newNode
|
||||
newNode.forwards[i] = next
|
||||
}
|
||||
|
||||
//如果当前节点的层数大于之前跳表的层数
|
||||
//更新当前跳表层数
|
||||
if level > sl.level {
|
||||
sl.level = level
|
||||
}
|
||||
|
||||
//更新跳表长度
|
||||
sl.length++
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
//查找
|
||||
func (sl *SkipList) Find(v interface{}, score int) *skipListNode {
|
||||
if nil == v || sl.length == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
cur := sl.head
|
||||
for i := sl.level - 1; i >= 0; i-- {
|
||||
for nil != cur.forwards[i] {
|
||||
if cur.forwards[i].score == score && cur.forwards[i].v == v {
|
||||
return cur.forwards[i]
|
||||
} else if cur.forwards[i].score > score {
|
||||
break
|
||||
}
|
||||
cur = cur.forwards[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//删除节点
|
||||
func (sl *SkipList) Delete(v interface{}, score int) int {
|
||||
if nil == v {
|
||||
return 1
|
||||
}
|
||||
|
||||
//查找前驱节点
|
||||
cur := sl.head
|
||||
//记录前驱路径
|
||||
update := [MAX_LEVEL]*skipListNode{}
|
||||
for i := sl.level - 1; i >= 0; i-- {
|
||||
update[i] = sl.head
|
||||
for nil != cur.forwards[i] {
|
||||
if cur.forwards[i].score == score && cur.forwards[i].v == v {
|
||||
update[i] = cur
|
||||
break
|
||||
}
|
||||
cur = cur.forwards[i]
|
||||
}
|
||||
}
|
||||
|
||||
cur = update[0].forwards[0]
|
||||
for i := cur.level - 1; i >= 0; i-- {
|
||||
if update[i] == sl.head && cur.forwards[i] == nil {
|
||||
sl.level = i
|
||||
}
|
||||
|
||||
if nil == update[i].forwards[i] {
|
||||
update[i].forwards[i] = nil
|
||||
} else {
|
||||
update[i].forwards[i] = update[i].forwards[i].forwards[i]
|
||||
}
|
||||
}
|
||||
|
||||
sl.length--
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (sl *SkipList) String() string {
|
||||
return fmt.Sprintf("level:%+v, length:%+v", sl.level, sl.length)
|
||||
}
|
38
go/17_skiplist/skiplist_test.go
Normal file
38
go/17_skiplist/skiplist_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
package _7_skiplist
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSkipList(t *testing.T) {
|
||||
sl := NewSkipList()
|
||||
|
||||
sl.Insert("leo", 95)
|
||||
t.Log(sl.head.forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0])
|
||||
t.Log(sl)
|
||||
t.Log("-----------------------------")
|
||||
|
||||
sl.Insert("jack", 88)
|
||||
t.Log(sl.head.forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0].forwards[0])
|
||||
t.Log(sl)
|
||||
t.Log("-----------------------------")
|
||||
|
||||
sl.Insert("lily", 100)
|
||||
t.Log(sl.head.forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0].forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0].forwards[0].forwards[0])
|
||||
t.Log(sl)
|
||||
t.Log("-----------------------------")
|
||||
|
||||
t.Log(sl.Find("jack", 88))
|
||||
t.Log("-----------------------------")
|
||||
|
||||
sl.Delete("leo", 95)
|
||||
t.Log(sl.head.forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0])
|
||||
t.Log(sl.head.forwards[0].forwards[0].forwards[0])
|
||||
t.Log(sl)
|
||||
t.Log("-----------------------------")
|
||||
}
|
145
go/24_tree/BinarySearchTree.go
Normal file
145
go/24_tree/BinarySearchTree.go
Normal file
@ -0,0 +1,145 @@
|
||||
package _4_tree
|
||||
|
||||
type BST struct {
|
||||
*BinaryTree
|
||||
//比对函数,0:v==nodeV,正数:v>nodeV,负数:v<nodeV
|
||||
compareFunc func(v, nodeV interface{}) int
|
||||
}
|
||||
|
||||
func NewBST(rootV interface{}, compareFunc func(v, nodeV interface{}) int) *BST {
|
||||
if nil == compareFunc {
|
||||
return nil
|
||||
}
|
||||
return &BST{BinaryTree: NewBinaryTree(rootV), compareFunc: compareFunc}
|
||||
}
|
||||
|
||||
func (this *BST) Find(v interface{}) *Node {
|
||||
p := this.root
|
||||
for nil != p {
|
||||
compareResult := this.compareFunc(v, p.data)
|
||||
if compareResult == 0 {
|
||||
return p
|
||||
} else if compareResult > 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
|
||||
}
|
145
go/24_tree/BinarySearchTree_test.go
Normal file
145
go/24_tree/BinarySearchTree_test.go
Normal file
@ -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()
|
||||
}
|
97
go/24_tree/BinaryTree.go
Normal file
97
go/24_tree/BinaryTree.go
Normal file
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
39
go/24_tree/BinaryTree_test.go
Normal file
39
go/24_tree/BinaryTree_test.go
Normal file
@ -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()
|
||||
}
|
72
go/24_tree/StackBasedOnArray.go
Normal file
72
go/24_tree/StackBasedOnArray.go
Normal file
@ -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])
|
||||
}
|
||||
}
|
||||
}
|
17
go/24_tree/TreeNode.go
Normal file
17
go/24_tree/TreeNode.go
Normal file
@ -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)
|
||||
}
|
83
go/28_heap/heap.go
Normal file
83
go/28_heap/heap.go
Normal file
@ -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
|
||||
}
|
54
go/28_heap/heap_sort.go
Normal file
54
go/28_heap/heap_sort.go
Normal file
@ -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
|
||||
}
|
90
go/binarysearch2.go
Normal file
90
go/binarysearch2.go
Normal file
@ -0,0 +1,90 @@
|
||||
package binarySearch
|
||||
|
||||
//查找第一个值等于给定值得元素
|
||||
func BinarySearch2(nums []int, value int) int {
|
||||
length := len(nums)
|
||||
start := 0
|
||||
end := length - 1
|
||||
for start <= end {
|
||||
mid := start + ((end - start) >> 1)
|
||||
if nums[mid] > value {
|
||||
end = mid - 1
|
||||
} else if nums[mid] < value {
|
||||
start = mid + 1
|
||||
} else {
|
||||
for mid >= 0 {
|
||||
if nums[mid-1] == value {
|
||||
mid--
|
||||
} else {
|
||||
return mid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// 查找最后一个值等于给定值的元素
|
||||
func BinarySearch3(nums []int, value int) int {
|
||||
start := 0
|
||||
end := len(nums) - 1
|
||||
for start <= end {
|
||||
mid := start + ((end - start) >> 1)
|
||||
if nums[mid] > value {
|
||||
end = mid - 1
|
||||
} else if nums[mid] < value {
|
||||
start = mid + 1
|
||||
} else {
|
||||
for mid < len(nums) {
|
||||
if nums[mid+1] == value {
|
||||
mid++
|
||||
} else {
|
||||
return mid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// 查找第一个大于等于给定值的元素
|
||||
func BinarySearch4(nums []int, value int) int {
|
||||
start := 0
|
||||
end := len(nums) - 1
|
||||
for start <= end {
|
||||
mid := (start + end) >> 1
|
||||
if nums[mid] < value {
|
||||
start = mid + 1
|
||||
} else {
|
||||
for mid >= 0 {
|
||||
if nums[mid-1] >= value {
|
||||
mid--
|
||||
} else {
|
||||
return mid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// 查找最后一个小于等于给定值的元素
|
||||
func BinarySearch5(nums []int, value int) int {
|
||||
start := 0
|
||||
end := len(nums) - 1
|
||||
for start <= end {
|
||||
mid := (start + end) >> 1
|
||||
if nums[mid] > value {
|
||||
end = mid - 1
|
||||
} else {
|
||||
for mid < len(nums) {
|
||||
if nums[mid+1] <= value {
|
||||
mid++
|
||||
} else {
|
||||
return mid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
@ -1,164 +1,163 @@
|
||||
/**
|
||||
*
|
||||
* 1)泛型动态数组
|
||||
*
|
||||
* Author: shi
|
||||
*/
|
||||
public class GenericArray<T> {
|
||||
private T[] data;
|
||||
private int size;
|
||||
|
||||
public class GenericArray<T> {
|
||||
private T[] data;
|
||||
private int size;
|
||||
// 根据传入容量,构造Array
|
||||
public GenericArray(int capacity) {
|
||||
data = (T[]) new Object[capacity];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
// 根据传入容量,构造Array
|
||||
public GenericArray(int capacity) {
|
||||
data = (T[]) new Object[capacity];
|
||||
size = 0;
|
||||
}
|
||||
// 无参构造方法,默认数组容量为10
|
||||
public GenericArray() {
|
||||
this(10);
|
||||
}
|
||||
|
||||
// 无参构造方法,默认数组容量为10
|
||||
public GenericArray() {
|
||||
this(10);
|
||||
}
|
||||
// 获取数组容量
|
||||
public int getCapacity() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
// 获取数组容量
|
||||
public int getCapacity() {
|
||||
return data.length;
|
||||
}
|
||||
// 获取当前元素个数
|
||||
public int count() {
|
||||
return size;
|
||||
}
|
||||
|
||||
// 获取当前元素个数
|
||||
public int count() {
|
||||
return size;
|
||||
}
|
||||
// 判断数组是否为空
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
// 判断数组是否为空
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
// 修改 index 位置的元素
|
||||
public void set(int index, T e) {
|
||||
checkIndex(index);
|
||||
data[index] = e;
|
||||
}
|
||||
|
||||
// 修改 index 位置的元素
|
||||
public void set(int index, T e) {
|
||||
checkIndex(index);
|
||||
data[index] = e;
|
||||
}
|
||||
// 获取对应 index 位置的元素
|
||||
public T get(int index) {
|
||||
checkIndex(index);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
// 获取对应 index 位置的元素
|
||||
public T get(int index) {
|
||||
checkIndex(index);
|
||||
return data[index];
|
||||
}
|
||||
// 查看数组是否包含元素e
|
||||
public boolean contains(T e) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (data[i].equals(e)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 查看数组是否包含元素e
|
||||
public boolean contains(T e) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (data[i].equals(e)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取对应元素的下标, 未找到,返回 -1
|
||||
public int find(T e) {
|
||||
for ( int i = 0; i < size; i++) {
|
||||
if (data[i].equals(e)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
// 获取对应元素的下标, 未找到,返回 -1
|
||||
public int find(T e) {
|
||||
for ( int i = 0; i < size; i++) {
|
||||
if (data[i].equals(e)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// 在 index 位置,插入元素e, 时间复杂度 O(m+n)
|
||||
public void add(int index, T e) {
|
||||
checkIndex(index);
|
||||
// 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍
|
||||
if (size == data.length) {
|
||||
resize(2 * data.length);
|
||||
}
|
||||
// 在 index 位置,插入元素e, 时间复杂度 O(m+n)
|
||||
public void add(int index, T e) {
|
||||
checkIndex(index);
|
||||
// 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍
|
||||
if (size == data.length) {
|
||||
resize(2 * data.length);
|
||||
}
|
||||
|
||||
for (int i = size - 1; i >= index; i--) {
|
||||
data[i + 1] = data[i];
|
||||
}
|
||||
data[index] = e;
|
||||
size++;
|
||||
}
|
||||
for (int i = size - 1; i >= index; i--) {
|
||||
data[i + 1] = data[i];
|
||||
}
|
||||
data[index] = e;
|
||||
size++;
|
||||
}
|
||||
|
||||
// 向数组头插入元素
|
||||
public void addFirst(T e) {
|
||||
add(0, e);
|
||||
}
|
||||
// 向数组头插入元素
|
||||
public void addFirst(T e) {
|
||||
add(0, e);
|
||||
}
|
||||
|
||||
// 向数组尾插入元素
|
||||
public void addLast(T e) {
|
||||
add(size, e);
|
||||
}
|
||||
// 向数组尾插入元素
|
||||
public void addLast(T e) {
|
||||
add(size, e);
|
||||
}
|
||||
|
||||
// 删除 index 位置的元素,并返回
|
||||
public T remove(int index) {
|
||||
checkIndex(index);
|
||||
// 删除 index 位置的元素,并返回
|
||||
public T remove(int index) {
|
||||
checkIndexForRemove(index);
|
||||
|
||||
T ret = data[index];
|
||||
for (int i = index + 1; i < size; i++) {
|
||||
data[i - 1] = data[i];
|
||||
}
|
||||
size --;
|
||||
data[size] = null;
|
||||
T ret = data[index];
|
||||
for (int i = index + 1; i < size; i++) {
|
||||
data[i - 1] = data[i];
|
||||
}
|
||||
size --;
|
||||
data[size] = null;
|
||||
|
||||
// 缩容
|
||||
if (size == data.length / 4 && data.length / 2 != 0) {
|
||||
resize(data.length / 2);
|
||||
}
|
||||
// 缩容
|
||||
if (size == data.length / 4 && data.length / 2 != 0) {
|
||||
resize(data.length / 2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 删除第一个元素
|
||||
public T removeFirst() {
|
||||
return remove(0);
|
||||
}
|
||||
// 删除第一个元素
|
||||
public T removeFirst() {
|
||||
return remove(0);
|
||||
}
|
||||
|
||||
// 删除末尾元素
|
||||
public T removeLast() {
|
||||
return remove(size - 1);
|
||||
}
|
||||
// 删除末尾元素
|
||||
public T removeLast() {
|
||||
return remove(size - 1);
|
||||
}
|
||||
|
||||
// 从数组中删除指定元素
|
||||
public void removeElement(T e) {
|
||||
int index = find(e);
|
||||
if (index != -1) {
|
||||
remove(index);
|
||||
}
|
||||
}
|
||||
// 从数组中删除指定元素
|
||||
public void removeElement(T e) {
|
||||
int index = find(e);
|
||||
if (index != -1) {
|
||||
remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length));
|
||||
builder.append('[');
|
||||
for (int i = 0; i < size; i++) {
|
||||
builder.append(data[i]);
|
||||
if (i != size - 1) {
|
||||
builder.append(", ");
|
||||
}
|
||||
}
|
||||
builder.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length));
|
||||
builder.append('[');
|
||||
for (int i = 0; i < size; i++) {
|
||||
builder.append(data[i]);
|
||||
if (i != size - 1) {
|
||||
builder.append(", ");
|
||||
}
|
||||
}
|
||||
builder.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
// 扩容方法,时间复杂度 O(n)
|
||||
private void resize(int capacity) {
|
||||
T[] newData = (T[]) new Object[capacity];
|
||||
// 扩容方法,时间复杂度 O(n)
|
||||
private void resize(int capacity) {
|
||||
T[] newData = (T[]) new Object[capacity];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
newData[i] = data[i];
|
||||
}
|
||||
data = newData;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
newData[i] = data[i];
|
||||
}
|
||||
data = newData;
|
||||
}
|
||||
|
||||
private void checkIndex(int index) {
|
||||
private void checkIndex(int index) {
|
||||
if (index < 0 || index > size) {
|
||||
throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIndexForRemove(int index) {
|
||||
if(index < 0 || index >= size) {
|
||||
throw new IllegalArgumentException("remove failed! Require index >=0 and index < size.");
|
||||
}
|
||||
}
|
||||
}
|
@ -8,160 +8,329 @@ package linkedlist;
|
||||
*/
|
||||
public class SinglyLinkedList {
|
||||
|
||||
private Node head = null;
|
||||
private Node head = null;
|
||||
|
||||
public Node findByValue(int value) {
|
||||
Node p = head;
|
||||
while (p != null && p.data != value) {
|
||||
p = p.next;
|
||||
public Node findByValue(int value) {
|
||||
Node p = head;
|
||||
while (p != null && p.data != value) {
|
||||
p = p.next;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
public Node findByIndex(int index) {
|
||||
Node p = head;
|
||||
int pos = 0;
|
||||
while (p != null && pos != index) {
|
||||
p = p.next;
|
||||
++pos;
|
||||
}
|
||||
|
||||
public Node findByIndex(int index) {
|
||||
Node p = head;
|
||||
int pos = 0;
|
||||
while (p != null && pos != index) {
|
||||
p = p.next;
|
||||
++pos;
|
||||
return p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public void insertToHead(int value) {
|
||||
Node newNode = new Node(value, null);
|
||||
insertToHead(newNode);
|
||||
}
|
||||
|
||||
public void insertToHead(Node newNode) {
|
||||
if (head == null) {
|
||||
head = newNode;
|
||||
} else {
|
||||
newNode.next = head;
|
||||
head = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
public void insertAfter(Node p, int value) {
|
||||
Node newNode = new Node(value, null);
|
||||
insertAfter(p, newNode);
|
||||
}
|
||||
|
||||
public void insertAfter(Node p, Node newNode) {
|
||||
if (p == null) return;
|
||||
|
||||
newNode.next = p.next;
|
||||
p.next = newNode;
|
||||
}
|
||||
|
||||
public void insertBefore(Node p, int value) {
|
||||
Node newNode = new Node(value, null);
|
||||
insertBefore(p, newNode);
|
||||
}
|
||||
|
||||
public void insertBefore(Node p, Node newNode) {
|
||||
if (p == null) return;
|
||||
if (head == p) {
|
||||
insertToHead(newNode);
|
||||
return;
|
||||
//无头结点
|
||||
//表头部插入
|
||||
//这种操作将于输入的顺序相反,逆序
|
||||
public void insertToHead(int value) {
|
||||
Node newNode = new Node(value, null);
|
||||
insertToHead(newNode);
|
||||
}
|
||||
|
||||
Node q = head;
|
||||
while (q != null && q.next != p) {
|
||||
q = q.next;
|
||||
public void insertToHead(Node newNode) {
|
||||
if (head == null) {
|
||||
head = newNode;
|
||||
} else {
|
||||
newNode.next = head;
|
||||
head = newNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (q == null) {
|
||||
return;
|
||||
//顺序插入
|
||||
//链表尾部插入
|
||||
public void insertTail(int value){
|
||||
|
||||
Node newNode = new Node(value, null);
|
||||
//空链表,可以插入新节点作为head,也可以不操作
|
||||
if (head == null){
|
||||
head = newNode;
|
||||
|
||||
}else{
|
||||
Node q = head;
|
||||
while(q.next != null){
|
||||
q = q.next;
|
||||
}
|
||||
newNode.next = q.next;
|
||||
q.next = newNode;
|
||||
}
|
||||
}
|
||||
public void insertAfter(Node p, int value) {
|
||||
Node newNode = new Node(value, null);
|
||||
insertAfter(p, newNode);
|
||||
}
|
||||
|
||||
newNode.next = p;
|
||||
q.next = newNode;
|
||||
public void insertAfter(Node p, Node newNode) {
|
||||
if (p == null) return;
|
||||
|
||||
}
|
||||
|
||||
public void deleteByNode(Node p) {
|
||||
if (p == null || head == null) return;
|
||||
|
||||
if (p == head) {
|
||||
head = head.next;
|
||||
return;
|
||||
newNode.next = p.next;
|
||||
p.next = newNode;
|
||||
}
|
||||
|
||||
Node q = head;
|
||||
while (q != null && q.next != p) {
|
||||
q = q.next;
|
||||
public void insertBefore(Node p, int value) {
|
||||
Node newNode = new Node(value, null);
|
||||
insertBefore(p, newNode);
|
||||
}
|
||||
|
||||
if (q == null) {
|
||||
return;
|
||||
public void insertBefore(Node p, Node newNode) {
|
||||
if (p == null) return;
|
||||
if (head == p) {
|
||||
insertToHead(newNode);
|
||||
return;
|
||||
}
|
||||
|
||||
Node q = head;
|
||||
while (q != null && q.next != p) {
|
||||
q = q.next;
|
||||
}
|
||||
|
||||
if (q == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
newNode.next = p;
|
||||
q.next = newNode;
|
||||
|
||||
}
|
||||
|
||||
q.next = q.next.next;
|
||||
}
|
||||
public void deleteByNode(Node p) {
|
||||
if (p == null || head == null) return;
|
||||
|
||||
public void deleteByValue(int value) {
|
||||
if (head == null) return;
|
||||
if (p == head) {
|
||||
head = head.next;
|
||||
return;
|
||||
}
|
||||
|
||||
Node p = head;
|
||||
Node q = null;
|
||||
while (p != null && p.data != value) {
|
||||
q = p;
|
||||
p = p.next;
|
||||
Node q = head;
|
||||
while (q != null && q.next != p) {
|
||||
q = q.next;
|
||||
}
|
||||
|
||||
if (q == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
q.next = q.next.next;
|
||||
}
|
||||
|
||||
if (p == null) return;
|
||||
public void deleteByValue(int value) {
|
||||
if (head == null) return;
|
||||
|
||||
if (q == null) {
|
||||
head = head.next;
|
||||
} else {
|
||||
q.next = q.next.next;
|
||||
Node p = head;
|
||||
Node q = null;
|
||||
while (p != null && p.data != value) {
|
||||
q = p;
|
||||
p = p.next;
|
||||
}
|
||||
|
||||
if (p == null) return;
|
||||
|
||||
if (q == null) {
|
||||
head = head.next;
|
||||
} else {
|
||||
q.next = q.next.next;
|
||||
}
|
||||
|
||||
// 可重复删除指定value的代码
|
||||
/*
|
||||
if (head != null && head.data == value) {
|
||||
head = head.next;
|
||||
}
|
||||
|
||||
Node pNode = head;
|
||||
while (pNode != null) {
|
||||
if (pNode.next.data == data) {
|
||||
pNode.next = pNode.next.next;
|
||||
continue;
|
||||
}
|
||||
pNode = pNode.next;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// 可重复删除指定value的代码
|
||||
/*
|
||||
if (head != null && head.data == value) {
|
||||
head = head.next;
|
||||
public void printAll() {
|
||||
Node p = head;
|
||||
while (p != null) {
|
||||
System.out.print(p.data + " ");
|
||||
p = p.next;
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
Node pNode = head;
|
||||
while (pNode != null) {
|
||||
if (pNode.next.data == data) {
|
||||
pNode.next = pNode.next.next;
|
||||
continue;
|
||||
}
|
||||
pNode = pNode.next;
|
||||
//判断true or false
|
||||
public boolean TFResult(Node left, Node right){
|
||||
Node l = left;
|
||||
Node r = right;
|
||||
|
||||
System.out.println("left_:"+l.data);
|
||||
System.out.println("right_:"+r.data);
|
||||
while(l != null && r != null){
|
||||
if (l.data == r.data){
|
||||
l = l.next;
|
||||
r = r.next;
|
||||
continue;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
System.out.println("什么结果");
|
||||
if (l==null && r==null){
|
||||
System.out.println("什么结果");
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
// 判断是否为回文
|
||||
|
||||
public void printAll() {
|
||||
Node p = head;
|
||||
while (p != null) {
|
||||
System.out.print(p.data + " ");
|
||||
p = p.next;
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
public boolean palindrome(){
|
||||
if (head == null){
|
||||
return false;
|
||||
}else{
|
||||
System.out.println("开始执行找到中间节点");
|
||||
Node p = head;
|
||||
Node q = head;
|
||||
if (p.next == null){
|
||||
System.out.println("只有一个元素");
|
||||
return true;
|
||||
}
|
||||
while( q.next != null && q.next.next != null){
|
||||
p = p.next;
|
||||
q = q.next.next;
|
||||
|
||||
public static Node createNode(int value) {
|
||||
return new Node(value, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Node {
|
||||
private int data;
|
||||
private Node next;
|
||||
System.out.println("中间节点" + p.data);
|
||||
System.out.println("开始执行奇数节点的回文判断");
|
||||
Node leftLink = null;
|
||||
Node rightLink = null;
|
||||
if(q.next == null){
|
||||
// p 一定为整个链表的中点,且节点数目为奇数
|
||||
rightLink = p.next;
|
||||
leftLink = inverseLinkList(p).next;
|
||||
System.out.println("左边第一个节点"+leftLink.data);
|
||||
System.out.println("右边第一个节点"+rightLink.data);
|
||||
|
||||
public Node(int data, Node next) {
|
||||
this.data = data;
|
||||
this.next = next;
|
||||
}else{
|
||||
//p q 均为中点
|
||||
rightLink = p.next;
|
||||
leftLink = inverseLinkList(p);
|
||||
}
|
||||
return TFResult(leftLink, rightLink);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public int getData() {
|
||||
return data;
|
||||
//带结点的链表翻转
|
||||
public Node inverseLinkList_head(Node p){
|
||||
// Head 为新建的一个头结点
|
||||
Node Head = new Node(9999,null);
|
||||
// p 为原来整个链表的头结点,现在Head指向 整个链表
|
||||
Head.next = p;
|
||||
/*
|
||||
带头结点的链表翻转等价于
|
||||
从第二个元素开始重新头插法建立链表
|
||||
*/
|
||||
Node Cur = p.next;
|
||||
p.next = null;
|
||||
Node next = null;
|
||||
|
||||
while(Cur != null){
|
||||
next = Cur.next;
|
||||
Cur.next = Head.next;
|
||||
Head.next = Cur;
|
||||
System.out.println("first " + Head.data);
|
||||
|
||||
Cur = next;
|
||||
}
|
||||
|
||||
// 返回左半部分的中点之前的那个节点
|
||||
// 从此处开始同步像两边比较
|
||||
return Head;
|
||||
|
||||
}
|
||||
|
||||
//无头结点的链表翻转
|
||||
public Node inverseLinkList(Node p){
|
||||
|
||||
Node pre = null;
|
||||
Node r = head;
|
||||
System.out.println("z---" + r.data);
|
||||
Node next= null;
|
||||
while(r !=p){
|
||||
next = r.next;
|
||||
|
||||
r.next = pre;
|
||||
pre = r;
|
||||
r = next;
|
||||
}
|
||||
|
||||
r.next = pre;
|
||||
// 返回左半部分的中点之前的那个节点
|
||||
// 从此处开始同步像两边比较
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
public static Node createNode(int value) {
|
||||
return new Node(value, null);
|
||||
}
|
||||
|
||||
public static class Node {
|
||||
private int data;
|
||||
private Node next;
|
||||
|
||||
public Node(int data, Node next) {
|
||||
this.data = data;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public int getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
public static void main(String[]args){
|
||||
|
||||
SinglyLinkedList link = new SinglyLinkedList();
|
||||
System.out.println("hello");
|
||||
//int data[] = {1};
|
||||
//int data[] = {1,2};
|
||||
//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("不是回文");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
48
java/11_sorts/InsertionSortAdd.java
Normal file
48
java/11_sorts/InsertionSortAdd.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -49,31 +49,16 @@ public class Sorts {
|
||||
// 选择排序,a表示数组,n表示数组大小
|
||||
public static void selectionSort(int[] a, int n) {
|
||||
if (n <= 1) return;
|
||||
<<<<<<< HEAD
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// 查找最小值
|
||||
int minIndex = i;
|
||||
int minValue = a[i];
|
||||
for (int j = i; j < n; ++j) {
|
||||
if (a[j] < minValue) {
|
||||
minValue = a[j];
|
||||
=======
|
||||
|
||||
for (int i = 0; i < n - 1; ++i) {
|
||||
// 查找最小值
|
||||
int minIndex = i;
|
||||
for (int j = i + 1; j < n; ++j) {
|
||||
if (a[j] < a[minIndex]) {
|
||||
>>>>>>> upstream/master
|
||||
minIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
if (minIndex == i)
|
||||
continue;
|
||||
|
||||
>>>>>>> upstream/master
|
||||
|
||||
// 交换
|
||||
int tmp = a[i];
|
||||
a[i] = a[minIndex];
|
||||
|
@ -21,13 +21,13 @@ public class SkipList {
|
||||
public Node find(int value) {
|
||||
Node p = head;
|
||||
for (int i = levelCount - 1; i >= 0; --i) {
|
||||
while (p.forwords[i] != null && p.forwords[i].data < value) {
|
||||
p = p.forwords[i];
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) {
|
||||
p = p.forwards[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (p.forwords[0] != null && p.forwords[0].data == value) {
|
||||
return p.forwords[0];
|
||||
if (p.forwards[0] != null && p.forwards[0].data == value) {
|
||||
return p.forwards[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -46,16 +46,16 @@ public class SkipList {
|
||||
// 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.forwords[i] != null && p.forwords[i].data < value) {
|
||||
p = p.forwords[i];
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) {
|
||||
p = p.forwards[i];
|
||||
}
|
||||
update[i] = p;// 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.forwords[i] = update[i].forwords[i];
|
||||
update[i].forwords[i] = newNode;
|
||||
newNode.forwards[i] = update[i].forwards[i];
|
||||
update[i].forwards[i] = newNode;
|
||||
}
|
||||
|
||||
// update node hight
|
||||
@ -66,16 +66,16 @@ public class SkipList {
|
||||
Node[] update = new Node[levelCount];
|
||||
Node p = head;
|
||||
for (int i = levelCount - 1; i >= 0; --i) {
|
||||
while (p.forwords[i] != null && p.forwords[i].data < value) {
|
||||
p = p.forwords[i];
|
||||
while (p.forwards[i] != null && p.forwards[i].data < value) {
|
||||
p = p.forwards[i];
|
||||
}
|
||||
update[i] = p;
|
||||
}
|
||||
|
||||
if (p.forwords[0] != null && p.forwords[0].data == value) {
|
||||
if (p.forwards[0] != null && p.forwards[0].data == value) {
|
||||
for (int i = levelCount - 1; i >= 0; --i) {
|
||||
if (update[i].forwords[i] != null && update[i].forwords[i].data == value) {
|
||||
update[i].forwords[i] = update[i].forwords[i].forwords[i];
|
||||
if (update[i].forwards[i] != null && update[i].forwards[i].data == value) {
|
||||
update[i].forwards[i] = update[i].forwards[i].forwards[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,17 +95,16 @@ public class SkipList {
|
||||
|
||||
public void printAll() {
|
||||
Node p = head;
|
||||
while (p.forwords[0] != null) {
|
||||
System.out.print(p.forwords[0] + " ");
|
||||
p = p.forwords[0];
|
||||
while (p.forwards[0] != null) {
|
||||
System.out.print(p.forwards[0] + " ");
|
||||
p = p.forwards[0];
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
public class Node {
|
||||
private int data = -1;
|
||||
// 以数组形式维护下一个结点的指针
|
||||
private Node forwords[] = new Node[MAX_LEVEL];
|
||||
private Node forwards[] = new Node[MAX_LEVEL];
|
||||
private int maxLevel = 0;
|
||||
|
||||
@Override
|
||||
|
99
java/24_tree/BinarySearchTree.java
Normal file
99
java/24_tree/BinarySearchTree.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
27
javascript/15_binary/binaryFind.js
Normal file
27
javascript/15_binary/binaryFind.js
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 二分查找
|
||||
*
|
||||
* Author: nameczz
|
||||
*/
|
||||
// 数组必须有序 不存在重复
|
||||
const biaryFind = (sortedArr, target) => {
|
||||
if (sortedArr.length === 0) return -1
|
||||
let low = 0
|
||||
let high = sortedArr.length - 1
|
||||
while (low <= high) {
|
||||
const mid = Math.floor((low + high) / 2)
|
||||
if (target === sortedArr[mid]) {
|
||||
return mid
|
||||
} else if (target < sortedArr[mid]) {
|
||||
high = mid - 1
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
const arr = [1, 4, 5, 6, 7, 8, 10, 11, 23, 42, 44, 54, 56, 77, 102]
|
||||
console.log(biaryFind(arr, 44))
|
||||
console.log(biaryFind(arr, 1))
|
||||
console.log(biaryFind(arr, 102))
|
||||
console.log(biaryFind(arr, 1111))
|
90
javascript/16_binary/binary-find.js
Normal file
90
javascript/16_binary/binary-find.js
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 二分查找
|
||||
*
|
||||
* Author: nameczz
|
||||
*/
|
||||
|
||||
|
||||
// 查找第一个等于给定值
|
||||
const biaryFindFirst = (sortedArr, target) => {
|
||||
if (sortedArr.length === 0) return -1
|
||||
let low = 0
|
||||
let high = sortedArr.length - 1
|
||||
while (low <= high) {
|
||||
const mid = Math.floor((low + high) / 2)
|
||||
|
||||
if (target < sortedArr[mid]) {
|
||||
high = mid - 1
|
||||
} else if (target > sortedArr[mid]) {
|
||||
low = mid + 1
|
||||
} else {
|
||||
if (mid === 0 || sortedArr[mid - 1] < target) return mid
|
||||
high = mid - 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// 查找最后一个相等的数
|
||||
const biaryFindLast = (sortedArr, target) => {
|
||||
if (sortedArr.length === 0) return -1
|
||||
let low = 0
|
||||
let high = sortedArr.length - 1
|
||||
while (low <= high) {
|
||||
const mid = Math.floor((low + high) / 2)
|
||||
if (target < sortedArr[mid]) {
|
||||
high = mid - 1
|
||||
} else if (target > sortedArr[mid]) {
|
||||
low = mid + 1
|
||||
} else {
|
||||
if (mid === sortedArr.length - 1 || sortedArr[mid + 1] > target) return mid
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// 查找第一个大于等于给定值的元素
|
||||
const biaryFindFistBig = (sortedArr, target) => {
|
||||
if (sortedArr.length === 0) return -1
|
||||
let low = 0
|
||||
let high = sortedArr.length - 1
|
||||
while (low <= high) {
|
||||
const mid = Math.floor((low + high) / 2)
|
||||
if (target <= sortedArr[mid]) {
|
||||
if (mid === 0 || sortedArr[mid - 1] < target) return mid
|
||||
high = mid - 1
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// 查找最后一个小于等于给定值的元素
|
||||
const biaryFindLastSmall = (sortedArr, target) => {
|
||||
if (sortedArr.length === 0) return -1
|
||||
let low = 0
|
||||
let high = sortedArr.length - 1
|
||||
while (low <= high) {
|
||||
const mid = Math.floor((low + high) / 2)
|
||||
if (sortedArr[mid] > target) {
|
||||
high = mid - 1
|
||||
} else {
|
||||
if (mid === sortedArr.length - 1 || sortedArr[mid + 1] > target) return mid
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
const arr = [1, 2, 3, 4, 4, 4, 4, 4, 6, 7, 8, 8, 9]
|
||||
const first = biaryFindFirst(arr, 4)
|
||||
console.log(`FindFirst: ${first}`)
|
||||
|
||||
const last = biaryFindLast(arr, 4)
|
||||
console.log(`FindLast: ${last}`)
|
||||
const FisrtBig = biaryFindFistBig(arr, 5)
|
||||
console.log(`FindFisrtBig: ${FisrtBig}`)
|
||||
const LastSmall = biaryFindLastSmall(arr, 4)
|
||||
console.log(`FindLastSmall: ${LastSmall}`)
|
61
javascript/17_hashmap/HashTable.html
Normal file
61
javascript/17_hashmap/HashTable.html
Normal file
@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
/*
|
||||
最基本的散列表
|
||||
*/
|
||||
|
||||
class HashTable {
|
||||
constructor() {
|
||||
this.table=[];
|
||||
}
|
||||
//散列函数
|
||||
loseHashCode(key){
|
||||
var hash=0;
|
||||
//从ASCII表中查到的ASCII值加到hash中
|
||||
for (var i=0;i<key.length;i++){
|
||||
hash+=key.charCodeAt(i);
|
||||
}
|
||||
//为了得到比较小的数值,我们会用hash和任意数除余
|
||||
return hash%37;
|
||||
}
|
||||
//向散列表增加一个新的项
|
||||
put(key,value){
|
||||
var position=this.loseHashCode(key);
|
||||
console.log(position+'-'+key);
|
||||
this.table[position]=value;
|
||||
}
|
||||
//根据键从散列表删除值
|
||||
remove(key){
|
||||
this.table[this.loseHashCode(key)]=undefined;
|
||||
}
|
||||
//返回根据键值检索到的特定的值
|
||||
get(key){
|
||||
console.log(this.table[this.loseHashCode(key)])
|
||||
}
|
||||
print(){
|
||||
for (var i=0;i<this.table.length;++i){
|
||||
if (this.table[i]!==undefined){
|
||||
console.log(i+':'+this.table[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var hash = new HashTable();
|
||||
hash.put('Gandalf', 'gandalf@email.com');
|
||||
hash.put('John', 'johnsnow@email.com');
|
||||
hash.put('Tyrion', 'tyrion@email.com');
|
||||
hash.remove('Gandalf')
|
||||
hash.get('Gandalf')
|
||||
hash.get('Tyrion')
|
||||
hash.print()
|
||||
|
||||
//
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
65
javascript/28_heapsort/heap-sort.js
Normal file
65
javascript/28_heapsort/heap-sort.js
Normal file
@ -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()
|
@ -1,4 +1,4 @@
|
||||
# 排序(上)
|
||||
# 排序(平方时间复杂度排序算法)
|
||||
|
||||
| 排序算法 | 时间复杂度 | 是否基于比较 |
|
||||
|---------|----|----|
|
||||
|
0
notes/12_sorts/.gitkeep
Normal file
0
notes/12_sorts/.gitkeep
Normal file
176
notes/12_sorts/readme.md
Normal file
176
notes/12_sorts/readme.md
Normal file
@ -0,0 +1,176 @@
|
||||
# 排序(线性对数时间复杂度排序算法)
|
||||
|
||||
开篇问题:如何在 $O(n)$ 时间复杂度内寻找一个无序数组中第 K 大的元素?
|
||||
|
||||
## 归并排序
|
||||
|
||||
* 归并排序使用了「分治」思想(Divide and Conquer)
|
||||
* 分:把数组分成前后两部分,分别排序
|
||||
* 合:将有序的两部分合并
|
||||
|
||||
![归并排序分解图](https://static001.geekbang.org/resource/image/db/2b/db7f892d3355ef74da9cd64aa926dc2b.jpg)
|
||||
|
||||
* 分治与递归
|
||||
* 分治:解决问题的处理办法
|
||||
* 递归:实现算法的手段
|
||||
* ——分治算法经常用递归来实现
|
||||
* 递归实现:
|
||||
* 终止条件:区间 `[first, last)` 内不足 2 个元素
|
||||
* 递归公式:`merge_sort(first, last) = merge(merge_sort(first, mid), merge_sort(mid, last))`,其中 `mid = first + (last - first) / 2`
|
||||
|
||||
C++ 实现:
|
||||
|
||||
```cpp
|
||||
template <typename FrwdIt,
|
||||
typename T = typename std::iterator_traits<FrwdIt>::value_type,
|
||||
typename BinaryPred = std::less<T>>
|
||||
void merge_sort(FrwdIt first, FrwdIt last, BinaryPred comp = BinaryPred()) {
|
||||
const auto len = std::distance(first, last);
|
||||
if (len <= 1) { return; }
|
||||
auto cut = first + len / 2;
|
||||
merge_sort(first, cut, comp);
|
||||
merge_sort(cut, last, comp);
|
||||
std::vector<T> tmp;
|
||||
tmp.reserve(len);
|
||||
detail::merge(first, cut, cut, last, std::back_inserter(tmp), comp);
|
||||
std::copy(tmp.begin(), tmp.end(), first);
|
||||
}
|
||||
```
|
||||
|
||||
这里涉及到一个 `merge` 的过程,它的实现大致是:
|
||||
|
||||
```cpp
|
||||
namespace detail {
|
||||
template <typename InputIt1, typename InputIt2, typename OutputIt,
|
||||
typename BinaryPred = std::less<typename std::iterator_traits<InputIt1>::value_type>>
|
||||
OutputIt merge(InputIt1 first1, InputIt1 last1,
|
||||
InputIt2 first2, InputIt2 last2,
|
||||
OutputIt d_first,
|
||||
BinaryPred comp = BinaryPred()) {
|
||||
for (; first1 != last1; ++d_first) {
|
||||
if (first2 == last2) {
|
||||
return std::copy(first1, last1, d_first);
|
||||
}
|
||||
if (comp(*first2, *first1)) {
|
||||
*d_first = *first2;
|
||||
++first2;
|
||||
} else {
|
||||
*d_first = *first1;
|
||||
++first1;
|
||||
}
|
||||
}
|
||||
return std::copy(first2, last2, d_first);
|
||||
}
|
||||
} // namespace detail
|
||||
```
|
||||
|
||||
![`merge` 的过程](https://static001.geekbang.org/resource/image/95/2f/95897ade4f7ad5d10af057b1d144a22f.jpg)
|
||||
|
||||
### 算法分析
|
||||
|
||||
* 稳定性
|
||||
* 由于 `comp` 是严格偏序,所以 `!comp(*first2, *first1)` 时,取用 `first1` 的元素放入 `d_first` 保证了算法稳定性
|
||||
* 时间复杂度
|
||||
* 定义 $T(n)$ 表示问题规模为 $n$ 时算法的耗时,
|
||||
* 有递推公式:$T(n) = 2T(n/2) + n$
|
||||
* 展开得 $T(n) = 2^{k}T(1) + k * n$
|
||||
* 考虑 $k$ 是递归深度,它的值是 $\log_2 n$,因此 $T(n) = n + n\log_2 n$
|
||||
* 因此,归并排序的时间复杂度为 $\Theta(n\log n)$
|
||||
* 空间复杂度
|
||||
* 一般来说,空间复杂度是 $\Theta(n)$
|
||||
|
||||
## 快速排序(quick sort,快排)
|
||||
|
||||
原理:
|
||||
|
||||
* 在待排序区间 `[first, last)` 中选取一个元素,称为主元(pivot,枢轴)
|
||||
* 对待排序区间进行划分,使得 `[first, cut)` 中的元素满足 `comp(element, pivot)` 而 `[cut, last)` 中的元素不满足 `comp(element, pivot)`
|
||||
* 对划分的两个区间,继续划分,直到区间 `[first, last)` 内不足 2 个元素
|
||||
|
||||
![快排分区示例](https://static001.geekbang.org/resource/image/4d/81/4d892c3a2e08a17f16097d07ea088a81.jpg)
|
||||
|
||||
显然,这又是一个递归:
|
||||
|
||||
* 终止条件:区间 `[first, last)` 内不足 2 个元素
|
||||
* 递归公式:`quick_sort(first, last) = quick_sort(first, cut) + quick_sort(cut, last)`
|
||||
|
||||
```cpp
|
||||
template <typename IterT, typename T = typename std::iterator_traits<IterT>::value_type>
|
||||
void quick_sort(IterT first, IterT last) {
|
||||
if (std::distance(first, last) > 1) {
|
||||
IterT prev_last = std::prev(last);
|
||||
IterT cut = std::partition(first, prev_last, [prev_last](T v) { return v < *prev_last; });
|
||||
std::iter_swap(cut, prev_last);
|
||||
quick_sort(first, cut);
|
||||
quick_sort(cut, last);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 一点优化(Liam Huang):通过将 `if` 改为 `while` 同时修改 `last` 迭代器的值,可以节省一半递归调用的开销。
|
||||
|
||||
```cpp
|
||||
template <typename IterT, typename T = typename std::iterator_traits<IterT>::value_type>
|
||||
void quick_sort(IterT first, IterT last) {
|
||||
while (std::distance(first, last) > 1) {
|
||||
IterT prev_last = std::prev(last);
|
||||
IterT cut = std::partition(first, prev_last, [prev_last](T v) { return v < *prev_last; });
|
||||
std::iter_swap(cut, prev_last);
|
||||
quick_sort(cut, last);
|
||||
last = cut;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果不要求空间复杂度,分区函数实现起来很容易。
|
||||
|
||||
![非原地分区](https://static001.geekbang.org/resource/image/66/dc/6643bc3cef766f5b3e4526c332c60adc.jpg)
|
||||
|
||||
若要求原地分区,则不那么容易了。下面的实现实现了原地分区函数,并且能将所有相等的主元排在一起。
|
||||
|
||||
```cpp
|
||||
template <typename BidirIt,
|
||||
typename T = typename std::iterator_traits<BidirIt>::value_type,
|
||||
typename Compare = std::less<T>>
|
||||
std::pair<BidirIt, BidirIt> inplace_partition(BidirIt first,
|
||||
BidirIt last,
|
||||
const T& pivot,
|
||||
Compare comp = Compare()) {
|
||||
BidirIt last_less, last_greater, first_equal, last_equal;
|
||||
for (last_less = first, last_greater = first, first_equal = last;
|
||||
last_greater != first_equal; ) {
|
||||
if (comp(*last_greater, pivot)) {
|
||||
std::iter_swap(last_greater++, last_less++);
|
||||
} else if (comp(pivot, *last_greater)) {
|
||||
++last_greater;
|
||||
} else { // pivot == *last_greater
|
||||
std::iter_swap(last_greater, --first_equal);
|
||||
}
|
||||
}
|
||||
const auto cnt = std::distance(first_equal, last);
|
||||
std::swap_ranges(first_equal, last, last_less);
|
||||
first_equal = last_less;
|
||||
last_equal = first_equal + cnt;
|
||||
return {first_equal, last_equal};
|
||||
}
|
||||
```
|
||||
|
||||
### 算法分析
|
||||
|
||||
* 稳定性
|
||||
* 由于 `inplace_partition` 使用了大量 `std::iter_swap` 操作,所以不是稳定排序
|
||||
* 时间复杂度
|
||||
* 定义 $T(n)$ 表示问题规模为 $n$ 时算法的耗时,
|
||||
* 有递推公式:$T(n) = 2T(n/2) + n$(假定每次分割都是均衡分割)
|
||||
* 展开得 $T(n) = 2^{k}T(1) + k * n$
|
||||
* 考虑 $k$ 是递归深度,它的值是 $\log_2 n$,因此 $T(n) = n + n\log_2 n$
|
||||
* 因此,快速排序的时间复杂度为 $\Theta(n\log n)$
|
||||
* 空间复杂度
|
||||
* 一般来说,空间复杂度是 $\Theta(1)$,因此是原地排序算法
|
||||
|
||||
## 开篇问题
|
||||
|
||||
* 分区,看前半段元素数量
|
||||
* 前半段元素数量 < K,对后半段进行分区
|
||||
* 前半段元素数量 > K,对前半段进行分区
|
||||
* 前半段元素数量 = K,前半段末位元素即是所求
|
0
notes/13_sorts/.gitkeep
Normal file
0
notes/13_sorts/.gitkeep
Normal file
77
notes/13_sorts/readme.md
Normal file
77
notes/13_sorts/readme.md
Normal file
@ -0,0 +1,77 @@
|
||||
# 线性排序
|
||||
|
||||
## 开篇问题
|
||||
|
||||
如何按年龄给 100 万用户排序?
|
||||
|
||||
## 桶排序(Bucket Sort)
|
||||
|
||||
算法思想:
|
||||
|
||||
* 按待排序数据的 key 分有序桶
|
||||
* 桶内排序
|
||||
* 有序桶依次输出
|
||||
|
||||
![桶排序示例](https://static001.geekbang.org/resource/image/98/ae/987564607b864255f81686829503abae.jpg)
|
||||
|
||||
### 算法分析
|
||||
|
||||
* 时间复杂度 $O(n)$
|
||||
* $n$ 个元素,分 $m$ 个有序桶,每个桶里平均 $k = n / m$ 个元素
|
||||
* 桶内快排,复杂度 $O(k \log k)$,$m$ 个桶一共 $O(n \log k)$
|
||||
* 当 $m$ 接近 $n$,例如当 $k = 4$ 时,这个复杂度近似 $O(n)$
|
||||
* 使用条件
|
||||
* 数据易于分如有序桶
|
||||
* 数据在各个有序桶之间分布均匀
|
||||
* 适合外部排序——数据不全部载入磁盘
|
||||
|
||||
## 计数排序(Counting Sort)
|
||||
|
||||
计数排序可以视作是桶排序的一个特殊情况:
|
||||
|
||||
* 数据的取值范围很小
|
||||
* 每个分桶内的元素 key 值都一样
|
||||
|
||||
此时,由于分桶内的元素 key 值都一样,所以桶内的排序操作可以省略,以及桶的编号本身就能记录桶内元素的值。因此,算法只需遍历一遍所有的数据,统计每个取值上有多少元素即可。这个过程时间复杂度是 $O(n)$。
|
||||
|
||||
* 假设待排序的数组 `A = {2, 5, 3, 0, 2, 3, 0, 3}`,我们有计数数组 `C = {2, 0, 2, 3, 0, 1}`
|
||||
|
||||
接下来,我们要对 `C` 进行计数操作,具体来说,对从下标为 1 的元素开始累加 `C[i] += C[i - 1]`。
|
||||
|
||||
* 计数累加 `C = {2, 2, 4, 7, 7, 8}`
|
||||
|
||||
此时,`C` 中的元素表示「小于等于下标的元素的个数」。接下来,我们从尾至头扫描待排序数组 `A`,将其中元素依次拷贝到输出数组 `R` 的相应位置。我们注意到,`A[7] = 3` 而 `C[3] == 4` 。这意味着,待排序的数组中,包括 3 本身在内,不超过 3 的元素共有 4 个。因此,我们可以将这个 3 放置在 `R[C[3] - 1]` 的位置,而后将 `C[3]` 的计数减一——这是由于待排序数组中未处理的部分,不超过 3 的元素现在只剩下 3 个了。如此遍历整个待排序数组 `A`,即可得到排序后的结果 `R`。
|
||||
|
||||
![计数排序示例](https://static001.geekbang.org/resource/image/1d/84/1d730cb17249f8e92ef5cab53ae65784.jpg)
|
||||
|
||||
### 算法分析
|
||||
|
||||
* 时间复杂度
|
||||
* $n$ 个元素,最大值是 $k$,分 $k$ 个「桶」;时间复杂度 $O(n)$
|
||||
* 桶内计数累加;时间复杂度 $O(k)$
|
||||
* 摆放元素;时间复杂度 $O(n)$
|
||||
* 当 $k < n$ 时,总体时间复杂度是 $O(n)$
|
||||
* 使用条件
|
||||
* $k < n$
|
||||
* 待排序数据的 key 是非负整数
|
||||
|
||||
## 基数排序(Radix Sort)
|
||||
|
||||
基数排序适用于等长数据的排序。对于不等长数据,可以在较短的数据后面做 padding,使得数据等长。
|
||||
|
||||
* 先就 least significant digit 进行稳定排序——通常可以用桶排序或者计数排序;时间复杂度 $O(n)$
|
||||
* 而后依次向 greatest significant digit 移动,进行稳定排序
|
||||
|
||||
![基数排序示例](https://static001.geekbang.org/resource/image/df/0c/df0cdbb73bd19a2d69a52c54d8b9fc0c.jpg)
|
||||
|
||||
### 算法分析
|
||||
|
||||
* 时间复杂度
|
||||
* 对每一位的排序时间复杂度是 $O(n)$
|
||||
* 总共 $k$ 位,因此总的时间复杂度是 $O(kn)$;考虑到 $k$ 是常数,因此总的时间复杂度是 $O(n)$
|
||||
* 使用条件
|
||||
* 等长数据
|
||||
|
||||
## 解答开篇
|
||||
|
||||
桶排序。
|
0
notes/14_sorts/.gitkeep
Normal file
0
notes/14_sorts/.gitkeep
Normal file
10
notes/14_sorts/readme.md
Normal file
10
notes/14_sorts/readme.md
Normal file
@ -0,0 +1,10 @@
|
||||
# 排序优化
|
||||
|
||||
## 如何取舍排序算法?
|
||||
|
||||
* 排序规模小 —— $O(n^2)$ 的算法(通常是插排)
|
||||
* 排序规模大 —— $O(n\log n)$ 的算法(通常不用归并排序)
|
||||
|
||||
## 如何优化快速排序?
|
||||
|
||||
参考:[谈谈内省式排序算法](https://liam.page/2018/08/29/introspective-sort/)
|
0
notes/15_bsearch/.gitkeep
Normal file
0
notes/15_bsearch/.gitkeep
Normal file
23
notes/15_bsearch/readme.md
Normal file
23
notes/15_bsearch/readme.md
Normal file
@ -0,0 +1,23 @@
|
||||
# 二分查找(上)
|
||||
|
||||
## 算法描述
|
||||
|
||||
二分查找(Binary Search)也叫折半查找,是针对有序数据集合的查找算法。其描述十分简单:
|
||||
|
||||
* 折半取中,判断元素与目标元素的大小关系
|
||||
* 小于——往前继续折半
|
||||
* 大于——往后继续折半
|
||||
* 等于——返回
|
||||
|
||||
关于它的复杂度分析,参见[谈谈基于比较的排序算法的复杂度下界](https://liam.page/2018/08/28/lower-bound-of-comparation-based-sort-algorithm/)中的相关信息。它的复杂度是 $O(\log n)$。
|
||||
|
||||
## $O(\log n)$ 的惊人之处
|
||||
|
||||
在 42 亿个数据中用二分查找一个数据,最多需要比较 32 次。
|
||||
|
||||
## 适用场景
|
||||
|
||||
* 依赖顺序表结构
|
||||
* 数据本身必须有序
|
||||
* 数据量相对比较元素的开销要足够大——不然遍历即可
|
||||
* 数据量相对内存空间不能太大——不然顺序表装不下
|
0
notes/16_bsearch/.gitkeep
Normal file
0
notes/16_bsearch/.gitkeep
Normal file
100
notes/16_bsearch/readme.md
Normal file
100
notes/16_bsearch/readme.md
Normal file
@ -0,0 +1,100 @@
|
||||
# 二分查找(下)
|
||||
|
||||
本节课讨论二分的各种变体。实际上在针对上一节的代码中,已经实现了两个变体。本次实现四个变体:
|
||||
|
||||
* 第一个等于给定值的元素
|
||||
* 最后一个等于给定值的元素
|
||||
* 第一个不小于给定值的元素
|
||||
* 最后一个不大于给定值的元素
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* Created by Liam Huang (Liam0205) on 2018/10/26.
|
||||
*/
|
||||
|
||||
#ifndef BSEARCH_BSEARCH_VARIENTS_HPP_
|
||||
#define BSEARCH_BSEARCH_VARIENTS_HPP_
|
||||
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
|
||||
enum class BsearchPolicy { UNSPECIFIED, FIRST, LAST, FIRST_NOT_LESS, LAST_NOT_GREATER };
|
||||
|
||||
// Liam Huang: The algorithm works right with iterators that meet the ForwardIterator requirement,
|
||||
// but with a bad time complexity. For better performance, iterators should meet
|
||||
// the RandomAccessIterator requirement.
|
||||
template <typename IterT,
|
||||
typename ValueT = typename std::iterator_traits<IterT>::value_type,
|
||||
typename Compare>
|
||||
IterT bsearch(IterT first,
|
||||
IterT last,
|
||||
ValueT target,
|
||||
Compare comp,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
IterT result = last;
|
||||
while (std::distance(first, last) > 0) {
|
||||
IterT mid = first + std::distance(first, last) / 2;
|
||||
if (policy == BsearchPolicy::FIRST_NOT_LESS) {
|
||||
if (!comp(*mid, target)) {
|
||||
if (mid == first or comp(*(mid - 1), target)) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
last = mid;
|
||||
}
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
} else if (policy == BsearchPolicy::LAST_NOT_GREATER) {
|
||||
if (comp(target, *mid)) {
|
||||
last = mid;
|
||||
} else {
|
||||
if (std::distance(mid, last) == 1 or comp(target, *(mid + 1))) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
}
|
||||
} else { // policy == UNSPECIFIED or FIRST or LAST
|
||||
if (comp(*mid, target)) {
|
||||
first = mid + 1;
|
||||
} else if (comp(target, *mid)) {
|
||||
last = mid;
|
||||
} else { // equal
|
||||
if (policy == BsearchPolicy::FIRST) {
|
||||
if (mid == first or comp(*(mid - 1), *mid)) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
last = mid;
|
||||
}
|
||||
} else if (policy == BsearchPolicy::LAST) {
|
||||
if (std::distance(mid, last) == 1 or comp(*mid, *(mid + 1))) {
|
||||
result = mid;
|
||||
break;
|
||||
} else {
|
||||
first = mid + 1;
|
||||
}
|
||||
} else {
|
||||
result = mid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename IterT,
|
||||
typename ValueT = typename std::iterator_traits<IterT>::value_type,
|
||||
typename Compare = std::less<ValueT>>
|
||||
IterT bsearch(IterT first,
|
||||
IterT last,
|
||||
ValueT target,
|
||||
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
|
||||
return bsearch(first, last, target, Compare(), policy);
|
||||
}
|
||||
|
||||
#endif // BSEARCH_BSEARCH_VARIENTS_HPP_
|
||||
```
|
0
notes/17_skiplist/.gitkeep
Normal file
0
notes/17_skiplist/.gitkeep
Normal file
43
notes/17_skiplist/readme.md
Normal file
43
notes/17_skiplist/readme.md
Normal file
@ -0,0 +1,43 @@
|
||||
# 跳表(Skip List)
|
||||
|
||||
支持快速地:
|
||||
|
||||
* 插入
|
||||
* 删除
|
||||
* 查找
|
||||
|
||||
某些情况下,跳表甚至可以替代红黑树(Red-Black tree)。Redis 当中的有序集合(Sorted Set)是用跳表实现的。
|
||||
|
||||
## 跳表的结构
|
||||
|
||||
跳表是对链表的改进。对于单链表来说,即使内容是有序的,查找具体某个元素的时间复杂度也要达到 $O(n)$。对于二分查找来说,由于链表不支持随机访问,根据 `first` 和 `last` 确定 `cut` 时,必须沿着链表依次迭代 `std::distance(first, last) / 2` 步;特别地,计算 `std::(first, last)` 本身,就必须沿着链表迭代才行。此时,二分查找的效率甚至退化到了 $O(n \log n)$,甚至还不如顺序遍历。
|
||||
|
||||
![单链表查找示例](https://static001.geekbang.org/resource/image/e1/6d/e18303fcedc068e5a168de04df956f6d.jpg)
|
||||
|
||||
跳表的核心思想是用空间换时间,构建足够多级数的索引,来缩短查找具体值的时间开销。
|
||||
|
||||
![具有二级索引的跳表示例](https://static001.geekbang.org/resource/image/49/65/492206afe5e2fef9f683c7cff83afa65.jpg)
|
||||
|
||||
例如对于一个具有 64 个有序元素的五级跳表,查找起来的过程大约如下图所示。
|
||||
|
||||
![五级跳表示例](https://static001.geekbang.org/resource/image/46/a9/46d283cd82c987153b3fe0c76dfba8a9.jpg)
|
||||
|
||||
## 复杂度分析
|
||||
|
||||
对于一个每一级索引的跨度是下一级索引 $k$ 倍的跳表,每一次 `down` 操作,相当于将搜索范围缩小到「剩余的可能性的 $1 / k$」。因此,查找具体某个元素的时间复杂度大约需要 $\lfloor \log_k n\rfloor + 1$ 次操作;也就是说时间复杂度是 $O(\log n)$。
|
||||
|
||||
![跳表查询过程示例](https://static001.geekbang.org/resource/image/d0/0c/d03bef9a64a0368e6a0d23ace8bd450c.jpg)
|
||||
|
||||
前面说了,跳表是一种用空间换时间的数据结构。因此它的空间复杂度一定不小。我们考虑原链表有 $n$ 个元素,那么第一级索引就有 $n / k$ 个元素,剩余的索引依次有 $n / k^2$, $n / k^3$, ..., $1$ 个元素。总共的元素个数是一个等比数列求和问题,它的值是 $\frac{n - 1}{k - 1}$。可见,不论 $k$ 是多少,跳表的空间复杂度都是 $O(n)$;但随着 $k$ 的增加,实际需要的额外节点数会下降。
|
||||
|
||||
## 高效地插入和删除
|
||||
|
||||
对于链表来说,插入或删除一个给定结点的时间复杂度是 $O(1)$。因此,对于跳表来说,插入或删除某个结点,其时间复杂度完全依赖于查找这类结点的耗时。而我们知道,在跳表中查找某个元素的时间复杂度是 $O(\log n)$。因此,在跳表中插入或删除某个结点的时间复杂度是 $O(\log n)$。
|
||||
|
||||
![在跳表中插入一个元素](https://static001.geekbang.org/resource/image/65/6c/65379f0651bc3a7cfd13ab8694c4d26c.jpg)
|
||||
|
||||
## 跳表索引的动态更新
|
||||
|
||||
为了维护跳表的结构,在不断插入数据的过程中,有必要动态维护跳表的索引结构。一般来说,可以采用随机层级法。具体来说是引入一个输出整数的随机函数。当随机函数输出 $K$,则更新从第 $1$ 级至第 $K$ 级的索引。为了保证索引结构和数据规模大小的匹配,一般采用二项分布的随机函数。
|
||||
|
||||
![在跳表中插入一个元素并更新索引](https://static001.geekbang.org/resource/image/a8/a7/a861445d0b53fc842f38919365b004a7.jpg)
|
0
notes/18_hashtable/.gitkeep
Normal file
0
notes/18_hashtable/.gitkeep
Normal file
69
notes/18_hashtable/readme.md
Normal file
69
notes/18_hashtable/readme.md
Normal file
@ -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)
|
||||
|
||||
插入时,不论是否有冲突,直接插入目标位置的链表。
|
||||
|
||||
查找时,遍历目标位置的链表来查询。
|
||||
|
||||
删除时,遍历目标位置的链表来删除。
|
0
notes/19_hashtable/.gitkeep
Normal file
0
notes/19_hashtable/.gitkeep
Normal file
59
notes/19_hashtable/readme.md
Normal file
59
notes/19_hashtable/readme.md
Normal file
@ -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 时使用红黑树,否则使用链表)
|
@ -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)');
|
||||
|
47
php/12_sort/quicksort.php
Normal file
47
php/12_sort/quicksort.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
function quickSort(array &$a)
|
||||
{
|
||||
$n = count($a);
|
||||
|
||||
quickSortInternally($a, 0, $n-1);
|
||||
}
|
||||
|
||||
function quickSortInternally(array &$a, int $l, int $r)
|
||||
{
|
||||
if ($l >= $r) return;
|
||||
|
||||
$q = partition($a, $l, $r);
|
||||
quickSortInternally($a, $l, $q-1);
|
||||
quickSortInternally($a, $q+1, $r);
|
||||
}
|
||||
|
||||
function partition(&$a, $l, $r): int
|
||||
{
|
||||
$pivot = $a[$r];
|
||||
$i = $l;
|
||||
|
||||
for ($j = $l; $j < $r; ++$j) {
|
||||
if ($a[$j] < $pivot) {
|
||||
[$a[$j], $a[$i]] = [$a[$i], $a[$j]];
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
|
||||
[$a[$r], $a[$i]] = [$a[$i], $a[$r]];
|
||||
|
||||
return $i;
|
||||
}
|
||||
|
||||
$a1 = [1,4,6,2,3,5,4];
|
||||
$a2 = [2, 2, 2, 2];
|
||||
$a3 = [4, 3, 2, 1];
|
||||
$a4 = [5, -1, 9, 3, 7, 8, 3, -2, 9];
|
||||
quickSort($a1);
|
||||
print_r($a1);
|
||||
quickSort($a2);
|
||||
print_r($a2);
|
||||
quickSort($a3);
|
||||
print_r($a3);
|
||||
quickSort($a4);
|
||||
print_r($a4);
|
50
php/13_sort/bucketSort.php
Normal file
50
php/13_sort/bucketSort.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
require_once '../12_sort/quickSort.php';
|
||||
|
||||
|
||||
$numbers = [11,23,45,67,88,99,22,34,56,78,90,12,34,5,6,91,92,93,93,94,95,94,95,96,97,98,99,100];
|
||||
$size = 10;
|
||||
var_dump(bucketSort($numbers,10));//加在了quickSort文件,请忽略前几个打印
|
||||
|
||||
|
||||
/**
|
||||
* 桶排序
|
||||
* 假设一个桶只能放置10个元素
|
||||
* 当一个桶内元素过多,需要继续分桶
|
||||
* @param array $numbers
|
||||
* @param [type] $size
|
||||
*
|
||||
* @return void
|
||||
* @date 2018/11/25
|
||||
* @author yuanliandu
|
||||
*/
|
||||
function bucketSort(array $numbers) {
|
||||
$min = min($numbers);
|
||||
$max = max($numbers);
|
||||
$length = count($numbers);
|
||||
$bucketNumber = ceil(($max-$min)/$length) + 1;
|
||||
$buckets = [];
|
||||
foreach($numbers as $key => $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;
|
||||
}
|
||||
|
43
php/13_sort/countingSort.php
Normal file
43
php/13_sort/countingSort.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 计数排序
|
||||
* 五分制
|
||||
* 13个人
|
||||
*/
|
||||
$score = [0,1,5,3,2,4,1,2,4,2,1,4,4];
|
||||
|
||||
var_dump(countingSort($score));die();
|
||||
function countingSort(array $score) {
|
||||
|
||||
$length = count($score);
|
||||
if($length <= 1) {return $score;}
|
||||
|
||||
/**
|
||||
* 统计每个分数的人数
|
||||
*/
|
||||
$temp = [];
|
||||
$countScore = [];
|
||||
foreach ($score as $key => $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;
|
||||
}
|
48
php/13_sort/radixSort.php
Normal file
48
php/13_sort/radixSort.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 基数排序
|
||||
* 先根据个位排序、百位、千位........
|
||||
*/
|
||||
$numbers = [
|
||||
1234,
|
||||
4321,
|
||||
12,
|
||||
31,
|
||||
412,
|
||||
];
|
||||
$max = (string) max($numbers);//求出最大数字
|
||||
$loop = strlen($max);//计算最大数字的长度,决定循环次数
|
||||
|
||||
for($i=0;$i<$loop;$i++) {
|
||||
radixSort($numbers,$i);
|
||||
}
|
||||
var_dump($numbers);
|
||||
|
||||
/**
|
||||
* 基数排序
|
||||
* @param array $numbers
|
||||
* @param [type] $loop
|
||||
*
|
||||
* @return void
|
||||
* @date 2018/11/26
|
||||
* @author yuanliandu
|
||||
*/
|
||||
function radixSort(array &$numbers,$loop) {
|
||||
|
||||
$divisor = pow(10,$loop);//除数 主要决定比较个位数、百位.....
|
||||
$buckets = (new \SplFixedArray(10))->toArray();
|
||||
foreach ($numbers as $key => $value) {
|
||||
$index = ($value/$divisor)%10;//计算该数字在哪个桶中
|
||||
$buckets[$index][] = $value;
|
||||
}
|
||||
/**
|
||||
* 从桶中取出数字
|
||||
*/
|
||||
$k=0;
|
||||
for($i=0;$i<10;$i++) {
|
||||
while(count($buckets[$i]) > 0) {
|
||||
$numbers[$k++] = array_shift($buckets[$i]);
|
||||
}
|
||||
}
|
||||
}
|
98
php/15_binary/binary.php
Normal file
98
php/15_binary/binary.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* 二分查找 查找=find的元素
|
||||
* @param array $numbers
|
||||
* @param [type] $find
|
||||
*
|
||||
* @return void
|
||||
* @date 2018/11/26
|
||||
* @author yuanliandu
|
||||
*/
|
||||
function binarySearch(array $numbers, $find)
|
||||
{
|
||||
$low = 0;
|
||||
$high = count($numbers) - 1;
|
||||
return search($numbers, $low, $high, $find);
|
||||
}
|
||||
|
||||
function search(array $numbers, $low, $high, $find)
|
||||
{
|
||||
/**
|
||||
* notice1 循环退出条件
|
||||
*/
|
||||
if ($low > $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 <yuanliandu@qq.com>
|
||||
*/
|
||||
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));
|
191
php/16_binary/binary.php
Normal file
191
php/16_binary/binary.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 找到第一个=value的元素
|
||||
* @param array $numbers
|
||||
*
|
||||
* @return void
|
||||
* @date 2018/11/27
|
||||
* @author yuanliandu <yuanliandu@qq.com>
|
||||
*/
|
||||
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 <yuanliandu@qq.com>
|
||||
*/
|
||||
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 <yuanliandu@qq.com>
|
||||
*/
|
||||
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 <yuanliandu@qq.com>
|
||||
*/
|
||||
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 <yuanliandu@qq.com>
|
||||
*/
|
||||
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));
|
@ -17,11 +17,7 @@
|
||||
* findMiddleNode 求链表的中间结点
|
||||
|
||||
#### 08_stack
|
||||
<<<<<<< HEAD
|
||||
* 链栈实现
|
||||
=======
|
||||
* 链栈实现
|
||||
|
||||
#### 09_stack
|
||||
* 队列链表实现
|
||||
>>>>>>> upstream/master
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
python/.vs/slnx.sqlite
Normal file
BIN
python/.vs/slnx.sqlite
Normal file
Binary file not shown.
@ -1,4 +1,6 @@
|
||||
from typing import Optional
|
||||
|
||||
|
||||
#
|
||||
# 1) Insertion, deletion and random access of array
|
||||
# 2) Assumes int for element type
|
||||
@ -15,7 +17,7 @@ class MyArray:
|
||||
self._data = []
|
||||
self._count = 0
|
||||
self._capacity = capacity
|
||||
|
||||
|
||||
def __getitem__(self, position: int) -> int:
|
||||
|
||||
"""Support for subscript.
|
||||
@ -25,45 +27,75 @@ class MyArray:
|
||||
|
||||
def find(self, index: int) -> Optional[int]:
|
||||
|
||||
if index >= self._count or index <= -self._count: return None
|
||||
if index >= self._count or index <= -self._count:
|
||||
return None
|
||||
return self._data[index]
|
||||
|
||||
def delete(self, index: int) -> bool:
|
||||
|
||||
if index >= self._count or index <= -self._count: return False
|
||||
|
||||
self._data[index:-1] = self._data[index+1:]
|
||||
|
||||
if index >= self._count or index <= -self._count:
|
||||
return False
|
||||
|
||||
self._data[index:-1] = self._data[index + 1:]
|
||||
self._count -= 1
|
||||
# 真正将数据删除并覆盖原来的数据 ,这个需要增加
|
||||
self._data = self._data[0:self._count]
|
||||
print ('delet function',self._data)
|
||||
print('delete function', self._data)
|
||||
return True
|
||||
|
||||
def insert(self, index: int, value: int) -> bool:
|
||||
|
||||
#if index >= self._count or index <= -self._count: return False
|
||||
if self._capacity == self._count: return False
|
||||
# if index >= self._count or index <= -self._count: return False
|
||||
if self._capacity == self._count:
|
||||
return False
|
||||
# 如果还有空间,那么插入位置大于当前的元素个数,可以插入最后的位置
|
||||
if index >= self._count:
|
||||
self._data.append(value)
|
||||
# 同上,如果位置小于0 可以插入第0个位置.
|
||||
if index < 0:
|
||||
print (index)
|
||||
print(index)
|
||||
self._data.insert(0, value)
|
||||
|
||||
self._count += 1
|
||||
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 @@ class MyArray:
|
||||
def print_all(self):
|
||||
|
||||
for num in self._data[:self._count]:
|
||||
print("{num}", end=" ")
|
||||
print(f"{num}", end=" ")
|
||||
print("\n", flush=True)
|
||||
|
||||
|
||||
def test_myarray():
|
||||
array_a = MyArray(6)
|
||||
for num in range(6):
|
||||
array_a.insert_to_tail(num)
|
||||
assert array_a.find(0) == 0
|
||||
assert array_a[0] == 0
|
||||
array_a.delete(0)
|
||||
assert array_a[0] == 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
a = MyArray(6)
|
||||
for i in range(6):
|
||||
a.insert_to_tail(i)
|
||||
|
||||
<<<<<<< HEAD
|
||||
a.delete(2)
|
||||
print(a)
|
||||
a.insert_to_tail(7)
|
||||
print(a)
|
||||
=======
|
||||
print('origin',a)
|
||||
print('origin', a)
|
||||
a.delete(4)
|
||||
print ('delete ',a)
|
||||
print('delete ', a)
|
||||
|
||||
a.insert(100,10000)
|
||||
print (a)
|
||||
|
||||
>>>>>>> upstream/master
|
||||
a.insert(100, 10000)
|
||||
print(a)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user