commit
b9ef965456
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,6 +19,7 @@
|
||||
*.tar.gz
|
||||
*.rar
|
||||
*.DS_Store
|
||||
*.exe
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
76
README.md
76
README.md
@ -1,6 +1,74 @@
|
||||
# 数据结构和算法之美
|
||||
# [https://time.geekbang.org/column/intro/126](https://time.geekbang.org/column/intro/126)
|
||||
# 数据结构和算法必知必会的50个代码实现
|
||||
|
||||
# Java rate limiting library/framework
|
||||
# https://github.com/wangzheng0822/ratelimiter4j
|
||||
## 数组
|
||||
* 实现一个支持动态扩容的数组
|
||||
* 实现一个大小固定的有序数组,支持动态增删改操作
|
||||
* 实现两个有序数组合并为一个有序数组
|
||||
|
||||
## 链表
|
||||
* 实现单链表、循环链表、双向链表,支持增删操作
|
||||
* 实现单链表反转
|
||||
* 实现两个有序的链表合并为一个有序链表
|
||||
* 实现求链表的中间结点
|
||||
|
||||
## 栈
|
||||
* 用数组实现一个顺序栈
|
||||
* 用链表实现一个链式栈
|
||||
* 编程模拟实现一个浏览器的前进、后退功能
|
||||
|
||||
## 队列
|
||||
* 用数组实现一个顺序队列
|
||||
* 用链表实现一个链式队列
|
||||
* 实现一个循环队列
|
||||
|
||||
## 递归
|
||||
* 编程实现斐波那契数列求值f(n)=f(n-1)+f(n-2)
|
||||
* 编程实现求阶乘n!
|
||||
* 编程实现一组数据集合的全排列
|
||||
|
||||
## 排序
|
||||
* 实现归并排序、快速排序、插入排序、冒泡排序、选择排序
|
||||
* 编程实现O(n)时间复杂度内找到一组数据的第K大元素
|
||||
|
||||
## 二分查找
|
||||
* 实现一个有序数组的二分查找算法
|
||||
* 实现模糊二分查找算法(比如大于等于给定值的第一个元素)
|
||||
|
||||
## 散列表
|
||||
* 实现一个基于链表法解决冲突问题的散列表
|
||||
* 实现一个LRU缓存淘汰算法
|
||||
|
||||
## 字符串
|
||||
* 实现一个字符集,只包含a~z这26个英文字母的Trie树
|
||||
* 实现朴素的字符串匹配算法
|
||||
|
||||
## 二叉树
|
||||
* 实现一个二叉查找树,并且支持插入、删除、查找操作
|
||||
* 实现查找二叉查找树中某个节点的后继、前驱节点
|
||||
* 实现二叉树前、中、后序以及按层遍历
|
||||
|
||||
## 堆
|
||||
* 实现一个小顶堆、大顶堆、优先级队列
|
||||
* 实现堆排序
|
||||
* 利用优先级队列合并K个有序数组
|
||||
* 求一组动态数据集合的最大Top K
|
||||
|
||||
## 图
|
||||
* 实现有向图、无向图、有权图、无权图的邻接矩阵和邻接表表示方法
|
||||
* 实现图的深度优先搜索、广度优先搜索
|
||||
* 实现Dijkstra算法、A*算法
|
||||
* 实现拓扑排序的Kahn算法、DFS算法
|
||||
|
||||
## 回溯
|
||||
* 利用回溯算法求解八皇后问题
|
||||
* 利用回溯算法求解0-1背包问题
|
||||
|
||||
## 分治
|
||||
* 利用分治算法求一组数据的逆序对个数
|
||||
|
||||
## 动态规划
|
||||
* 0-1背包问题
|
||||
* 最小路径和
|
||||
* 编程实现莱文斯坦最短编辑距离
|
||||
* 编程实现查找两个字符串的最长公共子序列
|
||||
* 编程实现一个数据序列的最长递增子序列
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace _05_array
|
||||
namespace algo05_array
|
||||
{
|
||||
public sealed class Array<T> where T : IComparable<T>
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using _05_array;
|
||||
using algo05_array;
|
||||
|
||||
namespace _06_linked_list
|
||||
namespace algo06_linked_list
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用数组实现LRU缓存淘汰算法
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace _06_linked_list
|
||||
namespace algo06_linked_list
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用单链表实现LRU缓存淘汰算法
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace _06_linked_list
|
||||
namespace algo06_linked_list
|
||||
{
|
||||
/// <summary>
|
||||
/// 单链表的插入、删除、清空、查找
|
||||
|
@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\05-array\_05_array.csproj" />
|
||||
<ProjectReference Include="..\05-array\algo05_array.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using _06_linked_list;
|
||||
using algo06_linked_list;
|
||||
|
||||
namespace _07_linkedlist
|
||||
namespace algo07_linkedlist
|
||||
{
|
||||
/// <summary>
|
||||
/// 单链表常用算法操作
|
||||
|
@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\06-linkedlist\_06_linked_list.csproj" />
|
||||
<ProjectReference Include="..\..\06-linkedlist\algo06_linked_list.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
41
csharp/08-stack/algo08_stack/ArrayStack.cs
Normal file
41
csharp/08-stack/algo08_stack/ArrayStack.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace algo08_stack
|
||||
{
|
||||
public class ArrayStack<T>
|
||||
{
|
||||
private readonly int _capacity;
|
||||
|
||||
private readonly T[] _data;
|
||||
|
||||
private int _top = -1; // 指向栈顶元素,当为-1时表示栈为空
|
||||
|
||||
public ArrayStack(int capacity)
|
||||
{
|
||||
_capacity = capacity;
|
||||
|
||||
_data = new T[capacity];
|
||||
}
|
||||
|
||||
public int Count => _top + 1;
|
||||
|
||||
public void Push(T val)
|
||||
{
|
||||
if (Count == _capacity) throw new InvalidOperationException("Stack full.");
|
||||
|
||||
_top++;
|
||||
|
||||
_data[_top] = val;
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (_top == -1) throw new InvalidOperationException("Stack empty.");
|
||||
|
||||
T val = _data[_top];
|
||||
_top--;
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
51
csharp/08-stack/algo08_stack/LinkedStack.cs
Normal file
51
csharp/08-stack/algo08_stack/LinkedStack.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace algo08_stack
|
||||
{
|
||||
public class LinkedStack<T>
|
||||
{
|
||||
private StackListNode<T> _top;
|
||||
|
||||
public int Count { get; private set; }
|
||||
|
||||
public void Push(T val)
|
||||
{
|
||||
var newNode = new StackListNode<T>(val);
|
||||
newNode.Next = _top;
|
||||
_top = newNode;
|
||||
|
||||
Count++;
|
||||
}
|
||||
|
||||
public T Pop()
|
||||
{
|
||||
if (_top == null) throw new InvalidOperationException("Stack empty");
|
||||
|
||||
T val = _top.Value;
|
||||
_top = _top.Next;
|
||||
|
||||
Count--;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
while (Count > 0)
|
||||
{
|
||||
Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class StackListNode<T>
|
||||
{
|
||||
public StackListNode(T nodeValue)
|
||||
{
|
||||
Value = nodeValue;
|
||||
}
|
||||
|
||||
public T Value { get; set; }
|
||||
public StackListNode<T> Next { get; set; }
|
||||
}
|
||||
}
|
39
csharp/08-stack/algo08_stack/LinkedStackBrowser.cs
Normal file
39
csharp/08-stack/algo08_stack/LinkedStackBrowser.cs
Normal file
@ -0,0 +1,39 @@
|
||||
namespace algo08_stack
|
||||
{
|
||||
/// <summary>
|
||||
/// 利用链栈实现浏览器怎么进后退
|
||||
/// </summary>
|
||||
public class LinkedStackBrowser
|
||||
{
|
||||
private readonly LinkedStack<string> _backStack = new LinkedStack<string>();
|
||||
private readonly LinkedStack<string> _forwardStack = new LinkedStack<string>();
|
||||
|
||||
public void Open(string url)
|
||||
{
|
||||
_backStack.Push(url);
|
||||
|
||||
_forwardStack.Clear();
|
||||
}
|
||||
|
||||
public string Backward()
|
||||
{
|
||||
if (_backStack.Count == 0) return string.Empty;
|
||||
|
||||
string url = _backStack.Pop();
|
||||
|
||||
_forwardStack.Push(url);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
public string Forward()
|
||||
{
|
||||
if (_forwardStack.Count == 0) return string.Empty;
|
||||
|
||||
string url = _forwardStack.Pop();
|
||||
_backStack.Push(url);
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
7
csharp/08-stack/algo08_stack/algo08_stack.csproj
Normal file
7
csharp/08-stack/algo08_stack/algo08_stack.csproj
Normal file
@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using algo05_array;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using _05_array;
|
||||
|
||||
namespace _05_array_tests
|
||||
{
|
||||
|
@ -15,7 +15,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\05-array\_05_array.csproj" />
|
||||
<ProjectReference Include="..\..\05-array\algo05_array.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using _06_linked_list;
|
||||
using algo06_linked_list;
|
||||
|
||||
namespace _06_linkedlist_tests
|
||||
namespace algo06_linkedlist_tests
|
||||
{
|
||||
public class BaseLinkedListTests
|
||||
{
|
||||
|
@ -1,9 +1,9 @@
|
||||
using algo05_array;
|
||||
using algo06_linked_list;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using _05_array;
|
||||
using _06_linked_list;
|
||||
|
||||
namespace _06_linkedlist_tests
|
||||
namespace algo06_linkedlist_tests
|
||||
{
|
||||
public class LRUWithArrayTests
|
||||
{
|
||||
|
@ -1,8 +1,8 @@
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using _06_linked_list;
|
||||
using algo06_linked_list;
|
||||
|
||||
namespace _06_linkedlist_tests
|
||||
namespace algo06_linkedlist_tests
|
||||
{
|
||||
public class LRUWithLinkedListTests : BaseLinkedListTests
|
||||
{
|
||||
|
@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using _06_linked_list;
|
||||
using algo06_linked_list;
|
||||
|
||||
namespace _06_linkedlist_tests
|
||||
namespace algo06_linkedlist_tests
|
||||
{
|
||||
public class SingleLinkedListTests : BaseLinkedListTests
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<RootNamespace>_06_linkedlist_tests</RootNamespace>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
@ -14,8 +13,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\05-array\_05_array.csproj" />
|
||||
<ProjectReference Include="..\..\06-linkedlist\_06_linked_list.csproj" />
|
||||
<ProjectReference Include="..\..\05-array\algo05_array.csproj" />
|
||||
<ProjectReference Include="..\..\06-linkedlist\algo06_linked_list.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
using _06_linkedlist_tests;
|
||||
using _06_linked_list;
|
||||
using _07_linkedlist;
|
||||
using algo06_linkedlist_tests;
|
||||
using algo06_linked_list;
|
||||
using algo07_linkedlist;
|
||||
|
||||
namespace _07_linkedlist_tests
|
||||
namespace algo07_linkedlist_tests
|
||||
{
|
||||
public class SingleLinkedListAlgoTests : BaseLinkedListTests
|
||||
{
|
||||
|
@ -13,9 +13,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\06-linkedlist\_06_linked_list.csproj" />
|
||||
<ProjectReference Include="..\..\07-linkedlist\_07_linkedlist\_07_linkedlist.csproj" />
|
||||
<ProjectReference Include="..\_06_linkedlist_tests\_06_linkedlist_tests.csproj" />
|
||||
<ProjectReference Include="..\..\06-linkedlist\algo06_linked_list.csproj" />
|
||||
<ProjectReference Include="..\..\07-linkedlist\_07_linkedlist\algo07_linkedlist.csproj" />
|
||||
<ProjectReference Include="..\_06_linkedlist_tests\algo06_linkedlist_tests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
81
csharp/Tests/algo08_stack_tests/ArrayStack.Tests.cs
Normal file
81
csharp/Tests/algo08_stack_tests/ArrayStack.Tests.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using algo08_stack;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace algo08_stack_tests
|
||||
{
|
||||
public class ArrayStackTests
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public ArrayStackTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
private void PrintStackArray<T>(ArrayStack<T> list)
|
||||
{
|
||||
if (list.Count == 0) return;
|
||||
|
||||
while (list.Count > 0)
|
||||
{
|
||||
T item = list.Pop();
|
||||
_output.WriteLine(item.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Push_3_Elements_Then_Length_Equal_3()
|
||||
{
|
||||
var stack = new ArrayStack<int>(5);
|
||||
stack.Push(2);
|
||||
stack.Push(4);
|
||||
stack.Push(6);
|
||||
|
||||
Assert.Equal(3, stack.Count);
|
||||
|
||||
PrintStackArray(stack);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Push_Throw_InvalidOperationException_When_Stack_Full()
|
||||
{
|
||||
var stack = new ArrayStack<int>(5);
|
||||
stack.Push(2);
|
||||
stack.Push(4);
|
||||
stack.Push(6);
|
||||
stack.Push(8);
|
||||
stack.Push(10);
|
||||
|
||||
Exception ex = Assert.Throws<InvalidOperationException>(() => stack.Push(11));
|
||||
Assert.IsType<InvalidOperationException>(ex);
|
||||
|
||||
PrintStackArray(stack);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pop_Throw_InvalidOperationException_When_Stack_Empty()
|
||||
{
|
||||
var stack = new ArrayStack<int>(5);
|
||||
|
||||
Exception ex = Assert.Throws<InvalidOperationException>(() => stack.Pop());
|
||||
Assert.IsType<InvalidOperationException>(ex);
|
||||
|
||||
PrintStackArray(stack);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pop_Valid_When_Stack_Not_Empty()
|
||||
{
|
||||
var stack = new ArrayStack<int>(5);
|
||||
stack.Push(2);
|
||||
stack.Push(4);
|
||||
|
||||
int val = stack.Pop();
|
||||
Assert.Equal(4, val);
|
||||
|
||||
PrintStackArray(stack);
|
||||
}
|
||||
}
|
||||
}
|
65
csharp/Tests/algo08_stack_tests/LinkedStack.Tests.cs
Normal file
65
csharp/Tests/algo08_stack_tests/LinkedStack.Tests.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using algo08_stack;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace algo08_stack_tests
|
||||
{
|
||||
public class LinkedStackTests
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public LinkedStackTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
private void PrintStackLinkedList<T>(LinkedStack<T> list)
|
||||
{
|
||||
if (list.Count == 0) return;
|
||||
|
||||
while (list.Count > 0)
|
||||
{
|
||||
var val = list.Pop();
|
||||
_output.WriteLine(val.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Push_3_Elements_Then_Length_Equal_3()
|
||||
{
|
||||
var stack = new LinkedStack<int>();
|
||||
stack.Push(2);
|
||||
stack.Push(4);
|
||||
stack.Push(6);
|
||||
|
||||
Assert.Equal(3, stack.Count);
|
||||
|
||||
PrintStackLinkedList(stack);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pop_Throw_InvalidOperationException_When_Stack_Empty()
|
||||
{
|
||||
var stack = new LinkedStack<int>();
|
||||
|
||||
Exception ex = Assert.Throws<InvalidOperationException>(() => stack.Pop());
|
||||
Assert.IsType<InvalidOperationException>(ex);
|
||||
|
||||
PrintStackLinkedList(stack);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pop_Valid_When_Stack_Not_Empty()
|
||||
{
|
||||
var stack = new LinkedStack<int>();
|
||||
stack.Push(2);
|
||||
stack.Push(4);
|
||||
|
||||
var nodeVal = stack.Pop();
|
||||
Assert.Equal(4, nodeVal);
|
||||
|
||||
PrintStackLinkedList(stack);
|
||||
}
|
||||
}
|
||||
}
|
107
csharp/Tests/algo08_stack_tests/LinkedStackBrowser.Tests.cs
Normal file
107
csharp/Tests/algo08_stack_tests/LinkedStackBrowser.Tests.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using algo08_stack;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace algo08_stack_tests
|
||||
{
|
||||
public class LinkedStackBrowserTests
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public LinkedStackBrowserTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Browser_Open_4_Links_Back_2_Return_Right_Link()
|
||||
{
|
||||
var browser = new LinkedStackBrowser();
|
||||
browser.Open("www.google.com");
|
||||
browser.Open("www.baidu.com");
|
||||
browser.Open("www.qq.com");
|
||||
browser.Open("www.dadu.com");
|
||||
|
||||
string url = browser.Backward();
|
||||
url = browser.Backward();
|
||||
|
||||
Assert.Equal("www.qq.com", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Browser_Open_4_Links_Back_4_Return_Empty()
|
||||
{
|
||||
var browser = new LinkedStackBrowser();
|
||||
browser.Open("www.google.com");
|
||||
browser.Open("www.baidu.com");
|
||||
browser.Open("www.qq.com");
|
||||
browser.Open("www.dadu.com");
|
||||
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
string url = browser.Backward();
|
||||
|
||||
Assert.Equal(string.Empty, url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Browser_Forward_Before_End()
|
||||
{
|
||||
var browser = new LinkedStackBrowser();
|
||||
browser.Open("www.google.com");
|
||||
browser.Open("www.baidu.com");
|
||||
browser.Open("www.qq.com");
|
||||
browser.Open("www.dadu.com");
|
||||
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
|
||||
browser.Forward();
|
||||
string url = browser.Forward();
|
||||
|
||||
Assert.Equal("www.qq.com", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Browser_Forward_Until_End()
|
||||
{
|
||||
var browser = new LinkedStackBrowser();
|
||||
browser.Open("www.google.com");
|
||||
browser.Open("www.baidu.com");
|
||||
browser.Open("www.qq.com");
|
||||
browser.Open("www.dadu.com");
|
||||
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
|
||||
browser.Forward();
|
||||
browser.Forward();
|
||||
browser.Forward();
|
||||
string url = browser.Forward();
|
||||
|
||||
Assert.Equal(string.Empty, url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Browser_Backward_And_Open_New_Then_Cannot_Forward()
|
||||
{
|
||||
var browser = new LinkedStackBrowser();
|
||||
browser.Open("www.google.com");
|
||||
browser.Open("www.baidu.com");
|
||||
browser.Open("www.qq.com");
|
||||
|
||||
browser.Backward();
|
||||
browser.Backward();
|
||||
|
||||
browser.Open("www.dadu.com");
|
||||
|
||||
string url = browser.Forward();
|
||||
|
||||
Assert.Equal(string.Empty, url);
|
||||
}
|
||||
}
|
||||
}
|
19
csharp/Tests/algo08_stack_tests/algo08_stack_tests.csproj
Normal file
19
csharp/Tests/algo08_stack_tests/algo08_stack_tests.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\08-stack\algo08_stack\algo08_stack.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -3,19 +3,23 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26124.0
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_05_array", "05-array\_05_array.csproj", "{B88033F6-FF08-434A-AED7-91F5CDB73402}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo05_array", "05-array\algo05_array.csproj", "{B88033F6-FF08-434A-AED7-91F5CDB73402}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_06_linked_list", "06-linkedlist\_06_linked_list.csproj", "{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo06_linked_list", "06-linkedlist\algo06_linked_list.csproj", "{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_05_array_tests", "Tests\_05_array_tests\_05_array_tests.csproj", "{14982212-49E4-4409-8BFD-2D8A2945BD83}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo05_array_tests", "Tests\_05_array_tests\algo05_array_tests.csproj", "{14982212-49E4-4409-8BFD-2D8A2945BD83}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_06_linkedlist_tests", "Tests\_06_linkedlist_tests\_06_linkedlist_tests.csproj", "{1B93D9C6-D6C1-4619-BFB9-D84C29099223}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo06_linkedlist_tests", "Tests\_06_linkedlist_tests\algo06_linkedlist_tests.csproj", "{1B93D9C6-D6C1-4619-BFB9-D84C29099223}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_07_linkedlist", "07-linkedlist\_07_linkedlist\_07_linkedlist.csproj", "{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo07_linkedlist", "07-linkedlist\_07_linkedlist\algo07_linkedlist.csproj", "{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_07_linkedlist_tests", "Tests\_07_linkedlist_tests\_07_linkedlist_tests.csproj", "{66C3BC00-C135-4279-A666-A330A86F20D5}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo07_linkedlist_tests", "Tests\_07_linkedlist_tests\algo07_linkedlist_tests.csproj", "{66C3BC00-C135-4279-A666-A330A86F20D5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo08_stack", "08-stack\algo08_stack\algo08_stack.csproj", "{E080D481-C98E-43F3-B1D1-51DCF4CF7146}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo08_stack_tests", "Tests\algo08_stack_tests\algo08_stack_tests.csproj", "{6A249475-54EA-4039-9B0C-DC0E0A884C07}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -102,10 +106,35 @@ Global
|
||||
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{14982212-49E4-4409-8BFD-2D8A2945BD83} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}
|
||||
{1B93D9C6-D6C1-4619-BFB9-D84C29099223} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}
|
||||
{66C3BC00-C135-4279-A666-A330A86F20D5} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}
|
||||
{6A249475-54EA-4039-9B0C-DC0E0A884C07} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
41
go/06_linkedlist/palindrome-linked-list.go
Normal file
41
go/06_linkedlist/palindrome-linked-list.go
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* type ListNode struct {
|
||||
* Val int
|
||||
* Next *ListNode
|
||||
* }
|
||||
*/
|
||||
func isPalindrome(head *ListNode) bool {
|
||||
var slow *ListNode = head
|
||||
var fast *ListNode = head
|
||||
var prev *ListNode = nil
|
||||
var temp *ListNode = nil
|
||||
|
||||
if (head == nil || head.Next == nil) {
|
||||
return true
|
||||
}
|
||||
|
||||
for (fast != nil && fast.Next !=nil){
|
||||
fast = fast.Next.Next
|
||||
temp = slow.Next
|
||||
slow.Next = prev
|
||||
prev = slow
|
||||
slow = temp
|
||||
} // 快的先跑完,同时反转了一半链表,剪短
|
||||
|
||||
if fast != nil {
|
||||
slow = slow.Next // 处理余数,跨过中位数
|
||||
// prev 增加中 2->1->nil
|
||||
}
|
||||
|
||||
var l1 *ListNode = prev
|
||||
var l2 *ListNode = slow
|
||||
|
||||
for (l1 != nil && l2 !=nil && l1.Val == l2.Val){
|
||||
l1 = l1.Next
|
||||
l2 = l2.Next
|
||||
}
|
||||
|
||||
return (l1 == nil && l2 == nil)
|
||||
|
||||
}
|
73
go/34_kmp/kmp.go
Normal file
73
go/34_kmp/kmp.go
Normal file
@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func getNexts(pattern string) []int {
|
||||
m := len(pattern)
|
||||
nexts := make([]int, m)
|
||||
for index := range nexts {
|
||||
nexts[index] = -1
|
||||
}
|
||||
|
||||
for i := 1; i < m - 1; i++ {
|
||||
j := nexts[i - 1]
|
||||
|
||||
for pattern[j + 1] != pattern[i] && j >= 0 {
|
||||
j = nexts[j]
|
||||
}
|
||||
|
||||
if pattern[j + 1] == pattern[i] {
|
||||
j += 1
|
||||
}
|
||||
|
||||
nexts[i] = j
|
||||
}
|
||||
|
||||
return nexts
|
||||
}
|
||||
|
||||
func findByKMP(s string, pattern string) int {
|
||||
n := len(s)
|
||||
m := len(pattern)
|
||||
if n < m {
|
||||
return -1
|
||||
}
|
||||
|
||||
nexts := getNexts(pattern)
|
||||
|
||||
j := 0
|
||||
for i := 0; i < n; i++ {
|
||||
for j > 0 && s[i] != pattern[j] {
|
||||
j = nexts[j - 1] + 1
|
||||
}
|
||||
|
||||
if s[i] == pattern[j] {
|
||||
if j == m - 1 {
|
||||
return i - m + 1
|
||||
}
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func main(){
|
||||
s := "abc abcdab abcdabcdabde"
|
||||
pattern := "bcdabd"
|
||||
fmt.Println(findByKMP(s, pattern)) //16
|
||||
|
||||
s = "aabbbbaaabbababbabbbabaaabb"
|
||||
pattern = "abab"
|
||||
fmt.Println(findByKMP(s, pattern)) //11
|
||||
|
||||
s = "aabbbbaaabbababbabbbabaaabb"
|
||||
pattern = "ababacd"
|
||||
fmt.Println(findByKMP(s, pattern)) //-1
|
||||
|
||||
s = "hello"
|
||||
pattern = "ll"
|
||||
fmt.Println(findByKMP(s, pattern)) //2
|
||||
}
|
29
go/45_bitmap/bitmap.go
Normal file
29
go/45_bitmap/bitmap.go
Normal file
@ -0,0 +1,29 @@
|
||||
package bitmap
|
||||
|
||||
// BitMap implement bitmap
|
||||
type BitMap []byte
|
||||
|
||||
// New create BitMap
|
||||
func New(length uint) BitMap {
|
||||
return make([]byte, length/8+1)
|
||||
}
|
||||
|
||||
// Set set value in bitmap
|
||||
func (b BitMap) Set(value uint) {
|
||||
byteIndex := value / 8
|
||||
if byteIndex >= uint(len(b)) {
|
||||
return
|
||||
}
|
||||
bitIndex := value % 8
|
||||
[]byte(b)[byteIndex] |= 1 << bitIndex
|
||||
}
|
||||
|
||||
// Get check whether value exist or not
|
||||
func (b BitMap) Get(value uint) bool {
|
||||
byteIndex := value / 8
|
||||
if byteIndex >= uint(len(b)) {
|
||||
return false
|
||||
}
|
||||
bitIndex := value % 8
|
||||
return []byte(b)[byteIndex]&(1<<bitIndex) != 0
|
||||
}
|
15
go/45_bitmap/bitmap_test.go
Normal file
15
go/45_bitmap/bitmap_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package bitmap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBitMap(t *testing.T) {
|
||||
bitMap := New(80)
|
||||
for i := 0; i <= 100; i += 10 {
|
||||
bitMap.Set(uint(i))
|
||||
}
|
||||
for i := 0; i <= 100; i += 10 {
|
||||
t.Log(bitMap.Get(uint(i)))
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ package array;
|
||||
* 2)数组中的数据是int类型的;
|
||||
*
|
||||
* Author: Zheng
|
||||
* modify: xing
|
||||
* modify: xing, Gsealy
|
||||
*/
|
||||
public class Array {
|
||||
//定义整型数据data保存数据
|
||||
@ -71,7 +71,6 @@ public class Array {
|
||||
}
|
||||
this.data = arr;*/
|
||||
|
||||
|
||||
--count;
|
||||
return true;
|
||||
}
|
||||
@ -83,7 +82,7 @@ public class Array {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ArrayOperate array = new ArrayOperate(5);
|
||||
Array array = new Array(5);
|
||||
array.printAll();
|
||||
array.insert(0, 3);
|
||||
array.insert(0, 4);
|
||||
@ -93,6 +92,4 @@ public class Array {
|
||||
//array.insert(3, 11);
|
||||
array.printAll();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -81,7 +81,8 @@ public class LRUBasedArray<T> {
|
||||
* @param object
|
||||
*/
|
||||
public void removeAndCache(T object) {
|
||||
value[--count] = null;
|
||||
T key = value[--count];
|
||||
holder.remove(key);
|
||||
cache(object, count);
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ function isEven(num){
|
||||
}
|
||||
var num = [1,2,3,4,5,6,7,8];
|
||||
var someEven = num.some(isEven);
|
||||
if(even){
|
||||
if(someEven){
|
||||
console.log("有些数字是偶数");
|
||||
}else{
|
||||
console.log("没有数字是偶数");
|
||||
@ -208,14 +208,24 @@ console.log(pass);
|
||||
#### 二维数组
|
||||
JavaScript 可以通过在数组里在嵌套一个数组来形成二维数组。
|
||||
```
|
||||
var grades = [[88,86,82],[91,82,83],[77,72,79]];
|
||||
var grades = [
|
||||
[88,86,82],
|
||||
[91,82,83],
|
||||
[77,72,79],
|
||||
[86,80,82]
|
||||
];
|
||||
console.log(grades[1][2]); // 83
|
||||
```
|
||||
#### 处理二维数组
|
||||
对于二维数组的处理可以分为两种,一种按列访问,一种是按行访问。
|
||||
按列访问,外层循环对应行,内层循环对应列。例如,上述的数组,每一行对应一个学生的成绩记录,可以通过相加所有成绩,然后除以科目数来得到该生的平均成绩。
|
||||
按列访问,外层循环对应行,内层循环对应列。例如,上述的数组,每一行对应一个学生三门科目的成绩记录,可以通过相加所有成绩,然后除以科目数来得到该生的平均成绩。
|
||||
```
|
||||
var grades = [[88,86,82],[91,82,83],[77,72,79]];
|
||||
var grades = [
|
||||
[88,86,82],
|
||||
[91,82,83],
|
||||
[77,72,79],
|
||||
[86,80,82]
|
||||
];
|
||||
var total = 0;
|
||||
var average = 0.0;
|
||||
for(var row = 0;row<grades.length;++row){
|
||||
@ -232,27 +242,34 @@ for(var row = 0;row<grades.length;++row){
|
||||
> student 1 average: 85.33
|
||||
student 2 average: 85.33
|
||||
student 3 average: 76.00
|
||||
student 4 average: 82.67
|
||||
|
||||
|
||||
对于按行访问,则外层循环对应列,内城循环对应行,例如还是上述数组,现在的数组表示一个学生各科的分数,我们来求其平均成绩
|
||||
对于按行访问,则外层循环对应列,内层循环对应行,例如还是上述数组,现在的数组表示一个学生三场考试四门科目的各科分数,我们来求每场考试的平均成绩
|
||||
```
|
||||
var grades = [[88,86,82],[91,82,83],[77,72,79]];
|
||||
var grades = [
|
||||
[88,86,82],
|
||||
[91,82,83],
|
||||
[77,72,79],
|
||||
[86,80,82]
|
||||
];
|
||||
var total = 0;
|
||||
var average = 0.0;
|
||||
for(var col = 0;col <grades.length;++col ){
|
||||
for(var row= 0;row<grades[col ].length;++row){
|
||||
//这里假设每场考试的科目都一样,所以可以通过grades[0].length来获取考试数量
|
||||
for(var col = 0;col <grades[0].length;++col ){
|
||||
for(var row= 0;row<grades.length;++row){
|
||||
total += grades[row][col];
|
||||
}
|
||||
average = total/grades[col ].length;
|
||||
average = total/grades.length;
|
||||
console.log("exam "+parseInt(col +1)+" average: "+average.toFixed(2));
|
||||
total = 0;
|
||||
average = 0.0;
|
||||
}
|
||||
```
|
||||
输出结果为:
|
||||
> exam 1 average: 85.33
|
||||
> exam 1 average: 85.50
|
||||
exam 2 average: 80.00
|
||||
exam 3 average: 81.33
|
||||
exam 3 average: 81.50
|
||||
|
||||
其实只要调整 for 循环的顺序就可以控制是按行还是按列来输出,此外,JavaScript 还可以处理一些参差不齐的数组,比如一个二维数组中的数组,有的是两个元素,有的是四个元素,并不是都相同,在这种情况下,JavaScript 依然可以处理运行而不报错,这是因为不管多或少,都可以通过 length 属性来计算。
|
||||
#### 对象数组
|
||||
|
56
javascript/35_trie/trie.js
Normal file
56
javascript/35_trie/trie.js
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
|
||||
class TrieNode {
|
||||
constructor(data){
|
||||
this.data = data;
|
||||
this.children = new Array(26);
|
||||
this.isEndingChar = false
|
||||
}
|
||||
}
|
||||
|
||||
class TrieTree {
|
||||
|
||||
constructor(data){
|
||||
this.root = new TrieNode('/')
|
||||
}
|
||||
|
||||
insert (text) {
|
||||
let node = this.root;
|
||||
for (let char of text) {
|
||||
let index = char.charCodeAt() - 'a'.charCodeAt();
|
||||
if(!node.children[index]) {
|
||||
node.children[index] = new TrieNode(char);
|
||||
}
|
||||
node = node.children[index];
|
||||
}
|
||||
|
||||
node.isEndingChar = true;
|
||||
}
|
||||
|
||||
find (text) {
|
||||
let node = this.root;
|
||||
|
||||
for(let char of text) {
|
||||
let index = char.charCodeAt() - 'a'.charCodeAt();
|
||||
if(node.children[index]) {
|
||||
node = node.children[index];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return node.isEndingChar;
|
||||
}
|
||||
}
|
||||
|
||||
var tree = new TrieTree();
|
||||
var strs = ["how", "hi", "her", "hello", "so", "see"];
|
||||
for(let str of strs) {
|
||||
tree.insert(str);
|
||||
}
|
||||
|
||||
for(let str of strs) {
|
||||
console.log(tree.find(str));
|
||||
}
|
||||
|
||||
console.log(tree.find('world'));
|
103
javascript/36_ac_automata/ac_automata.js
Normal file
103
javascript/36_ac_automata/ac_automata.js
Normal file
@ -0,0 +1,103 @@
|
||||
|
||||
MAX_LEN = 128;
|
||||
|
||||
class ACNode {
|
||||
constructor(data){
|
||||
this.data = data;
|
||||
this.children = new Array(MAX_LEN);
|
||||
this.isEndingChar = false;
|
||||
this.length = 0;
|
||||
this.fail = null;
|
||||
}
|
||||
}
|
||||
|
||||
class ACTree {
|
||||
|
||||
constructor(data){
|
||||
this.root = new ACNode('/')
|
||||
}
|
||||
|
||||
insert (text) {
|
||||
let node = this.root;
|
||||
for (let char of text) {
|
||||
let index = char.charCodeAt() + 1;
|
||||
if(!node.children[index]) {
|
||||
node.children[index] = new ACNode(char);
|
||||
}
|
||||
node = node.children[index];
|
||||
}
|
||||
|
||||
node.isEndingChar = true;
|
||||
node.length = text.length;
|
||||
}
|
||||
|
||||
buildFailurePointer() {
|
||||
let root = this.root;
|
||||
let queue = [];
|
||||
queue.push(root);
|
||||
|
||||
while (queue.length > 0) {
|
||||
let p = queue.shift();
|
||||
|
||||
for (let i = 0; i < MAX_LEN; i++) {
|
||||
let pc = p.children[i];
|
||||
if (!pc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(p == root) {
|
||||
pc.fail = root;
|
||||
} else {
|
||||
let q = p.fail;
|
||||
while (q) {
|
||||
let qc = q.children[pc.data.charCodeAt() + 1];
|
||||
if(qc) {
|
||||
pc.fail = qc;
|
||||
break;
|
||||
}
|
||||
q = q.fail;
|
||||
}
|
||||
if(!q) {
|
||||
pc.fail = root;
|
||||
}
|
||||
}
|
||||
queue.push(pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match (text) {
|
||||
let root = this.root;
|
||||
let n = text.length;
|
||||
let p = root;
|
||||
|
||||
for(let i = 0; i < n; i++) {
|
||||
let idx = text[i].charCodeAt() + 1;
|
||||
while(!p.children[idx] && p != root){
|
||||
p = p.fail;
|
||||
}
|
||||
|
||||
p = p.children[idx];
|
||||
if(!p) {
|
||||
p = root;
|
||||
}
|
||||
|
||||
let tmp = p;
|
||||
while ( tmp != root) {
|
||||
if (tmp.isEndingChar == true) {
|
||||
console.log(`Start from ${i - p.length + 1}, length: ${p.length}`);
|
||||
}
|
||||
tmp = tmp.fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let automata = new ACTree();
|
||||
let patterns = ["at", "art", "oars", "soar"];
|
||||
for (let pattern of patterns) {
|
||||
automata.insert(pattern);
|
||||
}
|
||||
|
||||
automata.buildFailurePointer()
|
||||
automata.match("soarsoars");
|
74
php/39_backtracking/queens.php
Normal file
74
php/39_backtracking/queens.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 8皇后解法,共92种解法 回溯思想
|
||||
* Class Queen
|
||||
*/
|
||||
class Queen
|
||||
{
|
||||
public $result = [];
|
||||
|
||||
function cal8queens($row)
|
||||
{
|
||||
if ($row == 8) {
|
||||
$this->printQueens();
|
||||
return;
|
||||
}
|
||||
|
||||
//每一行有8中放法
|
||||
for($column = 0; $column < 8; $column++) {
|
||||
if ($this->isOk($row, $column)) {
|
||||
$this->result[$row] = $column;
|
||||
$this->cal8queens($row + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//row行的column列是否合适
|
||||
function isOk($row, $column)
|
||||
{
|
||||
$leftup = $column - 1;
|
||||
$rightdown = $column + 1;
|
||||
|
||||
for ($i = $row - 1; $i >= 0; $i--) {
|
||||
//判断上一行的 column 列是否有值
|
||||
if ($this->result[$i] == $column) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//左上角是否有值
|
||||
if ($leftup >= 0 && $this->result[$i] == $leftup) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//右下角是否有值
|
||||
if ($rightdown < 8 && $this->result[$i] == $rightdown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$leftup--;
|
||||
$rightdown++;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//打印
|
||||
function printQueens()
|
||||
{
|
||||
for ($row = 0; $row < 8; $row++) {
|
||||
for ($column = 0; $column < 8; $column++) {
|
||||
if ($this->result[$row] == $column) {
|
||||
echo 'Q';
|
||||
} else {
|
||||
echo '*';
|
||||
}
|
||||
}
|
||||
echo '<br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$queen = new Queen();
|
||||
$queen->cal8queens(0);
|
25
scala/src/main/scala/ch39_back_tracking/BagWeight.scala
Normal file
25
scala/src/main/scala/ch39_back_tracking/BagWeight.scala
Normal file
@ -0,0 +1,25 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
class BagWeight(maxBagItemCount: Int, maxBagWeight: Int) {
|
||||
|
||||
def calculateMaxWeight(items: Array[Int]): Int = {
|
||||
var maxWeight = 0
|
||||
|
||||
def _calcMaxWeight(itemIndex: Int, currentWeight: Int): Unit = {
|
||||
if (currentWeight == maxBagWeight || itemIndex == items.length) {
|
||||
if (currentWeight > maxWeight) {
|
||||
maxWeight = currentWeight
|
||||
}
|
||||
} else {
|
||||
//check next item
|
||||
_calcMaxWeight(itemIndex + 1, currentWeight)
|
||||
if (currentWeight + items(itemIndex) <= maxBagWeight) {
|
||||
_calcMaxWeight(itemIndex + 1, currentWeight + items(itemIndex))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_calcMaxWeight(0, 0)
|
||||
maxWeight
|
||||
}
|
||||
}
|
78
scala/src/main/scala/ch39_back_tracking/EightQueens.scala
Normal file
78
scala/src/main/scala/ch39_back_tracking/EightQueens.scala
Normal file
@ -0,0 +1,78 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
import scala.util.control.Breaks._
|
||||
|
||||
class EightQueens {
|
||||
|
||||
//use array index to identify the row,the value of the row to identify the column
|
||||
val result = new Array[Int](8)
|
||||
var count = 0
|
||||
|
||||
def calc8Queues(row: Int): Unit = {
|
||||
if (row == 8) {
|
||||
//everything is done
|
||||
print8Queens()
|
||||
return
|
||||
}
|
||||
|
||||
for (column <- Range(0, 8)) {
|
||||
if (isOkOnColumn(row, column)) {
|
||||
result(row) = column //place the column value into the array
|
||||
calc8Queues(row + 1) //calculate next row
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def isOkOnColumn(row: Int, column: Int): Boolean = {
|
||||
var ok = true
|
||||
var leftUp = column - 1
|
||||
var rightUp = column + 1
|
||||
|
||||
breakable {
|
||||
//will compare all the rows above current row
|
||||
for (i <- row - 1 to 0 by -1) {
|
||||
//check current column
|
||||
if (result(i) == column) {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
//check left up
|
||||
if (leftUp >= 0) {
|
||||
if (result(i) == leftUp) {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
//check right up
|
||||
if (rightUp < 8) {
|
||||
if (result(i) == rightUp) {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
//move leftUp and rightUp
|
||||
leftUp -= 1
|
||||
rightUp += 1
|
||||
}
|
||||
}
|
||||
|
||||
ok
|
||||
}
|
||||
|
||||
def print8Queens(): Unit = {
|
||||
count +=1
|
||||
for (row <- Range(0, 8)) {
|
||||
for (column <- Range(0, 8)) {
|
||||
if (result(row) == column) {
|
||||
print("Q ")
|
||||
} else {
|
||||
print("* ")
|
||||
}
|
||||
}
|
||||
//new line for next row
|
||||
println("")
|
||||
}
|
||||
println(count+"==============")
|
||||
}
|
||||
}
|
77
scala/src/main/scala/ch39_back_tracking/NQueens.scala
Normal file
77
scala/src/main/scala/ch39_back_tracking/NQueens.scala
Normal file
@ -0,0 +1,77 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
import scala.util.control.Breaks.{break, breakable}
|
||||
|
||||
class NQueens(numberOfQueens:Int) {
|
||||
//use array index to identify the row,the value of the row to identify the column
|
||||
val result = new Array[Int](numberOfQueens)
|
||||
var count = 0
|
||||
|
||||
def calcNQueues(row: Int): Unit = {
|
||||
if (row == numberOfQueens) {
|
||||
//everything is done
|
||||
printNQueens()
|
||||
return
|
||||
}
|
||||
|
||||
for (column <- Range(0, numberOfQueens)) {
|
||||
if (isOkOnColumn(row, column)) {
|
||||
result(row) = column //place the column value into the array
|
||||
calcNQueues(row + 1) //calculate next row
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def isOkOnColumn(row: Int, column: Int): Boolean = {
|
||||
var ok = true
|
||||
var leftUp = column - 1
|
||||
var rightUp = column + 1
|
||||
|
||||
breakable {
|
||||
//will compare all the rows above current row
|
||||
for (i <- row - 1 to 0 by -1) {
|
||||
//check current column
|
||||
if (result(i) == column) {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
//check left up
|
||||
if (leftUp >= 0) {
|
||||
if (result(i) == leftUp) {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
//check right up
|
||||
if (rightUp < numberOfQueens) {
|
||||
if (result(i) == rightUp) {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
//move leftUp and rightUp
|
||||
leftUp -= 1
|
||||
rightUp += 1
|
||||
}
|
||||
}
|
||||
|
||||
ok
|
||||
}
|
||||
|
||||
def printNQueens(): Unit = {
|
||||
count +=1
|
||||
for (row <- Range(0, numberOfQueens)) {
|
||||
for (column <- Range(0, numberOfQueens)) {
|
||||
if (result(row) == column) {
|
||||
print("Q ")
|
||||
} else {
|
||||
print("* ")
|
||||
}
|
||||
}
|
||||
//new line for next row
|
||||
println("")
|
||||
}
|
||||
println(count+"==============")
|
||||
}
|
||||
}
|
113
scala/src/main/scala/ch39_back_tracking/Sudoku.scala
Normal file
113
scala/src/main/scala/ch39_back_tracking/Sudoku.scala
Normal file
@ -0,0 +1,113 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
import scala.util.control.Breaks._
|
||||
|
||||
class Sudoku {
|
||||
|
||||
def resolve(grid: Array[Array[Int]]): Unit = {
|
||||
printGrid(grid)
|
||||
println("")
|
||||
if (resolve(grid, 0, 0)) {
|
||||
printGrid(grid)
|
||||
} else {
|
||||
println("no result")
|
||||
printGrid(grid)
|
||||
}
|
||||
}
|
||||
|
||||
private[this] def resolve(grid: Array[Array[Int]], row: Int, column: Int): Boolean = {
|
||||
if (row == 8 && column == 9) {
|
||||
//find the result
|
||||
return true
|
||||
}
|
||||
|
||||
if (column == 9) {
|
||||
//move to next line
|
||||
return resolve(grid, row + 1, 0)
|
||||
}
|
||||
|
||||
if (grid(row)(column) != 0) {
|
||||
//given number, resolve next one
|
||||
return resolve(grid, row, column + 1)
|
||||
}
|
||||
|
||||
//start the real resolve
|
||||
for (num <- 1 to 9) {
|
||||
if (isOk(grid, row, column, num)) {
|
||||
grid(row)(column) = num
|
||||
if (resolve(grid, row, column + 1)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//do not find anything, reset given row and column
|
||||
grid(row)(column) = 0
|
||||
false
|
||||
}
|
||||
|
||||
def isOk(grid: Array[Array[Int]], row: Int, column: Int, num: Int): Boolean = {
|
||||
isRowOk(grid, row, num) && isColumnOk(grid, column, num) && isSmallBoxOk(grid, row, column, num)
|
||||
}
|
||||
|
||||
def isRowOk(grid: Array[Array[Int]], row: Int, num: Int): Boolean = {
|
||||
var isOk = true
|
||||
breakable {
|
||||
for (column <- Range(0, 9)) {
|
||||
if (grid(row)(column) == num) {
|
||||
isOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
isOk
|
||||
}
|
||||
|
||||
def isColumnOk(grid: Array[Array[Int]], column: Int, num: Int): Boolean = {
|
||||
var isOk = true
|
||||
breakable {
|
||||
for (row <- Range(0, 9)) {
|
||||
if (grid(row)(column) == num) {
|
||||
isOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
isOk
|
||||
}
|
||||
|
||||
def isSmallBoxOk(grid: Array[Array[Int]], row: Int, column: Int, num: Int): Boolean = {
|
||||
val rowOffSet = (row / 3) * 3
|
||||
val columnOffSet = (column / 3) * 3
|
||||
var isOk = true
|
||||
breakable {
|
||||
for (i <- Range(0, 3)) {
|
||||
for (j <- Range(0, 3)) {
|
||||
if (grid(i + rowOffSet)(j + columnOffSet) == num) {
|
||||
isOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
isOk
|
||||
}
|
||||
|
||||
def printGrid(grid: Array[Array[Int]]): Unit = {
|
||||
for (i <- Range(0, 9)) {
|
||||
if (i % 3 == 0) {
|
||||
println("-------------------------")
|
||||
}
|
||||
for (j <- Range(0, 9)) {
|
||||
if (j % 3 == 0) {
|
||||
print("| ")
|
||||
}
|
||||
print(grid(i)(j) + " ")
|
||||
}
|
||||
println("| ")
|
||||
|
||||
}
|
||||
println("-------------------------")
|
||||
}
|
||||
|
||||
}
|
100
scala/src/main/scala/ch43_topology_sort/GraphTopology.scala
Normal file
100
scala/src/main/scala/ch43_topology_sort/GraphTopology.scala
Normal file
@ -0,0 +1,100 @@
|
||||
package ch43_topology_sort
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
class GraphTopology(vertex: Int) {
|
||||
|
||||
//define the graph
|
||||
val adjacency = new Array[mutable.MutableList[Int]](vertex)
|
||||
for (i <- Range(0, vertex)) {
|
||||
adjacency(i) = new mutable.MutableList[Int]()
|
||||
}
|
||||
|
||||
def addEdge(startIndex: Int, targetIndex: Int) = {
|
||||
adjacency(startIndex) += targetIndex
|
||||
}
|
||||
|
||||
def topologySortByKahn(): Array[Int] = {
|
||||
val seq = new mutable.ArrayBuffer[Int]()
|
||||
//inDegrees contains all the inDegree for a given node
|
||||
val inDegrees = new Array[Int](vertex)
|
||||
for (i <- Range(0, vertex)) {
|
||||
for (j <- adjacency(i).indices) {
|
||||
val index = adjacency(i).get(j).get
|
||||
inDegrees(index) += 1
|
||||
}
|
||||
}
|
||||
|
||||
val queue = new mutable.Queue[Int]()
|
||||
for (i <- inDegrees.indices) {
|
||||
if (inDegrees(i) == 0) {
|
||||
// means there is no inDegree for this node,
|
||||
// this could be the starting point of the dependency graph
|
||||
queue += i
|
||||
}
|
||||
}
|
||||
|
||||
//start to navigating the graph from the starting point
|
||||
while (queue.nonEmpty) {
|
||||
val index = queue.dequeue()
|
||||
|
||||
//push to the result
|
||||
seq += index
|
||||
|
||||
for (i <- adjacency(index).indices) {
|
||||
val inDegreeIndex = adjacency(index).get(i).get
|
||||
inDegrees(inDegreeIndex) -= 1
|
||||
|
||||
if (inDegrees(inDegreeIndex) == 0) {
|
||||
queue += inDegreeIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seq.toArray
|
||||
}
|
||||
|
||||
def topologySortByDFS(): Array[Int] = {
|
||||
val inverseAdj = new Array[mutable.MutableList[Int]](vertex)
|
||||
for (i <- Range(0, vertex)) {
|
||||
inverseAdj(i) = new mutable.MutableList[Int]()
|
||||
}
|
||||
|
||||
//build the inverse adj
|
||||
for (i <- Range(0, vertex)) {
|
||||
for (j <- adjacency(i).indices) {
|
||||
val index = adjacency(i).get(j).get
|
||||
inverseAdj(index) += i
|
||||
}
|
||||
}
|
||||
|
||||
val visited = new Array[Boolean](vertex)
|
||||
val seq = new ArrayBuffer[Int]()
|
||||
for (i <- Range(0, vertex)) {
|
||||
if (!visited(i)) {
|
||||
visited(i) = true
|
||||
//call dfs
|
||||
seq ++= dfs(i, inverseAdj, visited)
|
||||
}
|
||||
}
|
||||
|
||||
seq.toArray
|
||||
}
|
||||
|
||||
def dfs(index: Int, inverseAdj: Array[mutable.MutableList[Int]], visited: Array[Boolean]): ArrayBuffer[Int] = {
|
||||
val seq = new ArrayBuffer[Int]()
|
||||
|
||||
for (i <- inverseAdj(index).indices) {
|
||||
val sourceIndex = inverseAdj(index).get(i).get
|
||||
if (!visited(sourceIndex)) {
|
||||
visited(sourceIndex) = true
|
||||
seq ++= dfs(sourceIndex, inverseAdj, visited)
|
||||
}
|
||||
}
|
||||
seq += index
|
||||
seq
|
||||
}
|
||||
}
|
||||
|
||||
|
15
scala/src/test/scala/ch39_back_tracking/BagWeightTest.scala
Normal file
15
scala/src/test/scala/ch39_back_tracking/BagWeightTest.scala
Normal file
@ -0,0 +1,15 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
import org.scalatest.FlatSpec
|
||||
|
||||
class BagWeightTest extends FlatSpec {
|
||||
|
||||
behavior of "BagWeightTest"
|
||||
|
||||
it should "calculateMaxWeight" in {
|
||||
val bagWeight = new BagWeight(5,9)
|
||||
val maxWeight = bagWeight.calculateMaxWeight(Array(1,2,3,5,6))
|
||||
println(maxWeight)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
import org.scalatest.FlatSpec
|
||||
|
||||
class EightQueensTest extends FlatSpec {
|
||||
|
||||
behavior of "EightQueensTest"
|
||||
|
||||
it should "calc8Queues" in {
|
||||
val eightQueens = new EightQueens()
|
||||
eightQueens.calc8Queues(0)
|
||||
}
|
||||
|
||||
}
|
21
scala/src/test/scala/ch39_back_tracking/NQueensTest.scala
Normal file
21
scala/src/test/scala/ch39_back_tracking/NQueensTest.scala
Normal file
@ -0,0 +1,21 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
import org.scalatest.FlatSpec
|
||||
|
||||
class NQueensTest extends FlatSpec {
|
||||
|
||||
behavior of "NQueensTest"
|
||||
|
||||
it should "calc8Queues" in {
|
||||
val eightQueens = new NQueens(8)
|
||||
eightQueens.calcNQueues(0)
|
||||
|
||||
}
|
||||
|
||||
it should "calc4Queues" in {
|
||||
val eightQueens = new NQueens(4)
|
||||
eightQueens.calcNQueues(0)
|
||||
|
||||
}
|
||||
|
||||
}
|
74
scala/src/test/scala/ch39_back_tracking/SudokuTest.scala
Normal file
74
scala/src/test/scala/ch39_back_tracking/SudokuTest.scala
Normal file
@ -0,0 +1,74 @@
|
||||
package ch39_back_tracking
|
||||
|
||||
import org.scalatest.FlatSpec
|
||||
|
||||
class SudokuTest extends FlatSpec {
|
||||
|
||||
behavior of "SudokuTest"
|
||||
|
||||
it should "resolve - 1" in {
|
||||
val grid = Array(
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
)
|
||||
val sudoku = new Sudoku()
|
||||
sudoku.resolve(grid)
|
||||
}
|
||||
|
||||
it should "resolve - 2" in {
|
||||
val grid = Array(
|
||||
Array(0, 0, 7, 2, 5, 6, 4, 0 ,0),
|
||||
Array(4, 0, 0, 0, 0, 0, 0, 0, 5),
|
||||
Array(0, 1, 0, 0, 3, 9, 0, 6, 0),
|
||||
Array(0, 0, 0, 5, 0, 8, 0, 0, 0),
|
||||
Array(0, 0, 8, 0, 6, 0, 2, 0, 0),
|
||||
Array(0, 9, 0, 1, 0, 7, 0, 0, 0),
|
||||
Array(0, 3, 0, 0, 7, 0, 0, 9, 0),
|
||||
Array(2, 0, 0, 0, 0, 0, 0, 0, 4),
|
||||
Array(0, 0, 6, 3, 1, 2, 7, 0, 8)
|
||||
)
|
||||
val sudoku = new Sudoku()
|
||||
sudoku.resolve(grid)
|
||||
}
|
||||
|
||||
it should "resolve - 3" in {
|
||||
val grid = Array(
|
||||
Array(3, 8, 0, 0, 0, 0, 0, 0, 1),
|
||||
Array(0, 0, 6, 4, 0, 0, 7, 8, 5),
|
||||
Array(0, 0, 9, 0, 2, 0, 3, 0, 0),
|
||||
Array(0, 6, 0, 0, 9, 0, 0, 0, 0),
|
||||
Array(8, 0, 0, 3, 0, 2, 0, 0, 9),
|
||||
Array(0, 0, 0, 0, 4, 0, 0, 7, 0),
|
||||
Array(0, 0, 1, 0, 7, 0, 5, 0, 0),
|
||||
Array(4, 9, 5, 0, 0, 6, 1, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 9, 2)
|
||||
)
|
||||
val sudoku = new Sudoku()
|
||||
sudoku.resolve(grid)
|
||||
}
|
||||
|
||||
it should "print grid" in {
|
||||
val grid = Array(
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
Array(0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
)
|
||||
|
||||
val sudoku = new Sudoku()
|
||||
sudoku.printGrid(grid)
|
||||
}
|
||||
|
||||
}
|
120
scala/src/test/scala/ch43_topology_sort/GraphTopologyTest.scala
Normal file
120
scala/src/test/scala/ch43_topology_sort/GraphTopologyTest.scala
Normal file
@ -0,0 +1,120 @@
|
||||
package ch43_topology_sort
|
||||
|
||||
import org.scalatest.{FlatSpec, Matchers}
|
||||
|
||||
class GraphTopologyTest extends FlatSpec with Matchers {
|
||||
|
||||
behavior of "GraphTopologyTest"
|
||||
|
||||
/*
|
||||
a -> b
|
||||
| |
|
||||
\|/ \|/
|
||||
c -> d -> e
|
||||
*/
|
||||
it should "topologySortByKahn - 1" in {
|
||||
val nodes = Array("a", "b", "c", "d", "e")
|
||||
val graphTopology = new GraphTopology(nodes.length)
|
||||
graphTopology.addEdge(0, 1)
|
||||
graphTopology.addEdge(0, 2)
|
||||
graphTopology.addEdge(1, 3)
|
||||
graphTopology.addEdge(2, 3)
|
||||
graphTopology.addEdge(3, 4)
|
||||
|
||||
val seq = graphTopology.topologySortByKahn()
|
||||
seq.map(nodes(_)).mkString(",") should equal("a,b,c,d,e")
|
||||
}
|
||||
|
||||
/*
|
||||
a -> d ---
|
||||
| |
|
||||
\|/ \|/
|
||||
e -> c
|
||||
*/
|
||||
it should "topologySortByKahn - 2" in {
|
||||
val nodes = Array("a", "b", "c", "d", "e")
|
||||
val graphTopology = new GraphTopology(nodes.length)
|
||||
graphTopology.addEdge(0, 3)
|
||||
graphTopology.addEdge(3, 4)
|
||||
graphTopology.addEdge(3, 2)
|
||||
graphTopology.addEdge(4, 2)
|
||||
|
||||
val seq = graphTopology.topologySortByKahn()
|
||||
seq.map(nodes(_)).mkString(",") should equal("a,b,d,e,c")
|
||||
}
|
||||
|
||||
/*
|
||||
a -> d <- b
|
||||
| /|\
|
||||
\|/ |
|
||||
e -> c
|
||||
*/
|
||||
it should "topologySortByKahn - 3" in {
|
||||
val nodes = Array("a", "b", "c", "d", "e")
|
||||
val graphTopology = new GraphTopology(nodes.length)
|
||||
graphTopology.addEdge(0, 3)
|
||||
graphTopology.addEdge(3, 4)
|
||||
graphTopology.addEdge(4, 2)
|
||||
graphTopology.addEdge(2, 1)
|
||||
graphTopology.addEdge(1, 3)
|
||||
|
||||
val seq = graphTopology.topologySortByKahn()
|
||||
seq.map(nodes(_)).mkString(",") should equal("a")
|
||||
}
|
||||
|
||||
/*
|
||||
a -> b
|
||||
| |
|
||||
\|/ \|/
|
||||
c -> d -> e
|
||||
*/
|
||||
it should "topologySortByDFS - 1" in {
|
||||
val nodes = Array("a", "b", "c", "d", "e")
|
||||
val graphTopology = new GraphTopology(nodes.length)
|
||||
graphTopology.addEdge(0, 1)
|
||||
graphTopology.addEdge(0, 2)
|
||||
graphTopology.addEdge(1, 3)
|
||||
graphTopology.addEdge(2, 3)
|
||||
graphTopology.addEdge(3, 4)
|
||||
|
||||
val seq = graphTopology.topologySortByDFS()
|
||||
seq.map(nodes(_)).mkString(",") should equal("a,b,c,d,e")
|
||||
}
|
||||
|
||||
/*
|
||||
a -> d ---
|
||||
| |
|
||||
\|/ \|/
|
||||
e -> c
|
||||
*/
|
||||
it should "topologySortByDFS - 2" in {
|
||||
val nodes = Array("a", "b", "c", "d", "e")
|
||||
val graphTopology = new GraphTopology(nodes.length)
|
||||
graphTopology.addEdge(0, 3)
|
||||
graphTopology.addEdge(3, 4)
|
||||
graphTopology.addEdge(3, 2)
|
||||
graphTopology.addEdge(4, 2)
|
||||
|
||||
val seq = graphTopology.topologySortByDFS()
|
||||
seq.map(nodes(_)).mkString(",") should equal("a,b,d,e,c")
|
||||
}
|
||||
|
||||
/*
|
||||
a -> d <- b
|
||||
| /|\
|
||||
\|/ |
|
||||
e -> c
|
||||
*/
|
||||
it should "topologySortByDFS - 3" in {
|
||||
val nodes = Array("a", "b", "c", "d", "e")
|
||||
val graphTopology = new GraphTopology(nodes.length)
|
||||
graphTopology.addEdge(0, 3)
|
||||
graphTopology.addEdge(3, 4)
|
||||
graphTopology.addEdge(4, 2)
|
||||
graphTopology.addEdge(2, 1)
|
||||
graphTopology.addEdge(1, 3)
|
||||
|
||||
val seq = graphTopology.topologySortByKahn()
|
||||
seq.map(nodes(_)).mkString(",") should equal("a")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user