Skip to content

Commit

Permalink
全面重构了代码,版本号V1.0.0,发布至nuget
Browse files Browse the repository at this point in the history
  • Loading branch information
guogangj committed Dec 30, 2021
1 parent 7133285 commit 276d81e
Show file tree
Hide file tree
Showing 6 changed files with 409 additions and 173 deletions.
6 changes: 6 additions & 0 deletions AlgorithmLib/AlgorithmLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>1.0.0</Version>
<PackageId>AlgorithmLib</PackageId>
<Authors>Jiang Guogang</Authors>
<Company></Company>
<Description>一些常用的算法</Description>
<RepositoryUrl>https://github.com/guogangj/AlgorithmLib</RepositoryUrl>
</PropertyGroup>

</Project>
166 changes: 97 additions & 69 deletions AlgorithmLib/CombinationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,53 @@

namespace AlgorithmLib {

/// <summary>
/// 组合算法,实测发现在元素多的时候,回溯法速度更快一些
/// </summary>
public enum CombinationMethod {
/// <summary>
/// 标志位选择法(无递归)
/// </summary>
FlagDrift,
/// <summary>
/// 回溯法(有递归)
/// </summary>
Backtrack
}

/// <summary>
/// 组合算法类
/// 提供了“标志位选择法”和“回溯法”两种方法,实测下来,两种方法不管是执行时间还是内存消耗都相差无几
/// </summary>
public static class CombinationHelper {

/// <summary>
/// 组合算法,可以使用标志位选择法和回溯法,默认是标志位选择法
/// </summary>
public static CombinationMethod Method { get; set; } = CombinationMethod.FlagDrift;

/// <summary>
/// 组合算法(全组合)
/// 使用“标志位选择法”,通过移动选择标志位来达成目标,此方法没有使用递归
/// </summary>
/// <param name="arr">要进行组合的数组</param>
/// <param name="callback">回调方法</param>
public static void Combination1<T>(T[] arr, Action<T[]> callback) {
for(int n=1; n<=arr.Length; n++) {
Combination1(arr, n, callback);
public static void Combination<T>(T[] arr, Func<T[], bool> callback) {
for (int n = 1; n <= arr.Length; n++) {
switch (Method) {
case CombinationMethod.Backtrack: {
if(!_Backtrack(arr, n, 0, new List<T>(), callback)) {
return;
}
break;
}
default: { // CombinationMethod.FlagDrift
if (!_CombinationByFlagDrift(arr, n, callback)) {
return;
}
break;
}
}
}
}

Expand All @@ -28,10 +60,55 @@ public static void Combination1<T>(T[] arr, Action<T[]> callback) {
/// <param name="arr">要进行组合的数组</param>
/// <param name="n">要组合的元素数目</param>
/// <param name="callback">回调方法</param>
public static void Combination1<T>(T[] arr, int n, Action<T[]> callback) {
public static void Combination<T>(T[] arr, int n, Func<T[], bool> callback) {
switch (Method) {
case CombinationMethod.Backtrack: {
_Backtrack(arr, n, 0, new List<T>(), callback);
break;
}
default: { // CombinationMethod.FlagDrift
_CombinationByFlagDrift(arr, n, callback);
break;
}
}
}

/// <summary>
/// 组合算法(取n1-n2个元素)
/// 使用“标志位选择法”,通过移动选择标志位来达成目标,此方法没有使用递归
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="n1">取n1个数</param>
/// <param name="n2">到取n2个数</param>
/// <param name="callback">回调方法</param>
public static void Combination<T>(T[] arr, int n1, int n2, Func<T[], bool> callback) {
for (int n = n1; n <= n2; n++) {
switch (Method) {
case CombinationMethod.Backtrack: {
if(!_Backtrack(arr, n, 0, new List<T>(), callback)) {
return;
}
break;
}
default: { // CombinationMethod.FlagDrift
if (!_CombinationByFlagDrift(arr, n, callback)) {
return;
}
break;
}
}

}
}

/// <summary>
/// 组合算法:标志位选择法
/// </summary>
private static bool _CombinationByFlagDrift<T>(T[] arr, int n, Func<T[], bool> callback) {
int arrLen = arr.Length;
if (arrLen == 0 || n == 0 || n > arrLen || callback == null) {
return;
return false;
}
bool[] choosingFlags = new bool[arrLen];
for (int i = 0; i < n; i++) {
Expand All @@ -45,9 +122,11 @@ public static void Combination1<T>(T[] arr, int n, Action<T[]> callback) {
oneComb[j++] = arr[i];
}
}
callback(oneComb);

//如果最右不是true,从右边开始寻找第一个ture,将其右移一位
if (!callback(oneComb)) {
return false;
}

//如果最右不是true,从右边开始寻找第一个ture,将其右移一位
if (!choosingFlags[arrLen - 1]) {
int i = arrLen - 2;
for (; i >= 0; i--) {
Expand Down Expand Up @@ -89,33 +168,7 @@ public static void Combination1<T>(T[] arr, int n, Action<T[]> callback) {
}
}
} while (true);
}

/// <summary>
/// 组合算法(取n1-n2个元素)
/// 使用“标志位选择法”,通过移动选择标志位来达成目标,此方法没有使用递归
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="n1">取n1个数</param>
/// <param name="n2">到取n2个数</param>
/// <param name="callback">回调方法</param>
public static void Combination1<T>(T[] arr, int n1, int n2, Action<T[]> callback) {
for(int n=n1; n<=n2; n++) {
Combination1(arr, n, callback);
}
}

/// <summary>
/// 组合算法(全组合)
/// 使用“回溯法”,就是常规的递归方法
/// </summary>
/// <param name="arr">要进行组合的数组</param>
/// <param name="callback">回调方法</param>
public static void Combination2<T>(T[] arr, Action<T[]> callback) {
for (int n = 1; n <= arr.Length; n++) {
Combination1(arr, n, callback);
}
return true;
}

/// <summary>
Expand All @@ -126,50 +179,25 @@ public static void Combination2<T>(T[] arr, Action<T[]> callback) {
/// <param name="start">从哪个开始</param>
/// <param name="tempList">递归上一级组合的结果</param>
/// <param name="callback">回调方法</param>
private static void Backtrack<T>(T[] arr, int n, int start, List<T> tempList, Action<T[]> callback) {
private static bool _Backtrack<T>(T[] arr, int n, int start, List<T> tempList, Func<T[], bool> callback) {
//终止条件,找到一对组合
if (n == 0) {
callback(tempList.ToArray());
return;
return callback(tempList.ToArray());
}
if (start < arr.Length - n) {
//不选当前值,k不变
Backtrack(arr, n, start + 1, tempList, callback);
if(!_Backtrack(arr, n, start + 1, tempList, callback)) {
return false;
}
}
//选择当前值,k要减1
tempList.Add(arr[start]);
Backtrack(arr, n - 1, start + 1, tempList, callback);
if(!_Backtrack(arr, n - 1, start + 1, tempList, callback)) {
return false;
}
//因为是递归调用,跳到下一个分支的时候,要把这个分支选的值给移除
tempList.RemoveAt(tempList.Count - 1);
}

/// <summary>
/// 组合算法(取n个元素)
/// 使用“回溯法”,就是常规的递归方法
/// </summary>
/// <param name="arr">要进行组合的数组</param>
/// <param name="n">要组合的元素数目</param>
/// <param name="callback">回调方法</param>
public static void Combination2<T>(T[] arr, int n, Action<T[]> callback) {
int arrLen = arr.Length;
if (arrLen == 0 || n == 0 || n > arrLen || callback == null) {
return;
}
Backtrack(arr, n, 0, new List<T>(), callback);
}

/// <summary>
/// 组合算法(取n1-n2个元素)
/// 使用“回溯法”,就是常规的递归方法
/// </summary>
/// <param name="arr">原始数组</param>
/// <param name="n1">取n1个数</param>
/// <param name="n2">到取n2个数</param>
/// <param name="callback">回调方法</param>
public static void Combination2<T>(T[] arr, int n1, int n2, Action<T[]> callback) {
for (int n = n1; n <= n2; n++) {
Combination2(arr, n, callback);
}
return true;
}
}
}
85 changes: 49 additions & 36 deletions AlgorithmLib/PermutationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,73 @@ namespace AlgorithmLib {
/// 排列算法类
/// </summary>
public static class PermutationHelper {

/// <summary>
/// 排列算法(全排列)
/// </summary>
/// <param name="arr">要进行排列的数组</param>
/// <param name="callback">回调方法</param>
public static void Permutation1<T>(T[] arr, Action<T[]> callback) {
public static void Permutation<T>(T[] arr, Func<T[], bool> callback) {
for (int n = 1; n <= arr.Length; n++) {
Permutation1(arr, n, callback);
}
}

private static void SubPermutation<T>(T[] arr, int len, int start, Action<T[]> callback) {
if (len == 0) {
T[] onePerm = new T[start];
Array.Copy(arr, onePerm, start);
callback(onePerm);
return;
}
for(int i=start; i<arr.Length; i++) {
T tmp = arr[i];
arr[i] = arr[start];
arr[start] = tmp;
SubPermutation(arr, len-1, start + 1, callback);
tmp = arr[i];
arr[i] = arr[start];
arr[start] = tmp;
if (!_Permutation(arr, n, callback)) {
return;
}
}
}

}

/// <summary>
/// 排列算法(取n个元素)
/// 排列算法(取n1-n2个元素)
/// </summary>
/// <param name="arr">要进行排列的数组</param>
/// <param name="n">要排列的元素数目</param>
/// <param name="n1">排列结果取n1个数</param>
/// <param name="n2">到取n2个数</param>
/// <param name="callback">回调方法</param>
public static void Permutation1<T>(T[] arr, int n, Action<T[]> callback) {
int arrLen = arr.Length;
if (arrLen == 0 || n == 0 || n > arrLen || callback == null) {
return;
public static void Permutation<T>(T[] arr, int n1, int n2, Func<T[], bool> callback) {
for (int n = n1; n <= n2; n++) {
if (!_Permutation(arr, n, callback)) {
return;
}
}
SubPermutation(arr, n, 0, callback);
}

/// <summary>
/// 排列算法(取n1-n2个元素)
/// 排列算法(取n个元素)
/// </summary>
/// <param name="arr"></param>
/// <param name="n1">取n1个数</param>
/// <param name="n2">到取n2个数</param>
/// <param name="arr">要进行排列的数组</param>
/// <param name="n">排列结果取多少个元素</param>
/// <param name="callback">回调方法</param>
public static void Permutation1<T>(T[] arr, int n1, int n2, Action<T[]> callback) {
for (int n = n1; n <= n2; n++) {
Permutation1(arr, n, callback);
/// <returns>true为正常结束,false为中断</returns>
public static void Permutation<T>(T[] arr, int n, Func<T[], bool> callback) {
_Permutation(arr, n, callback);
}

private static bool _Permutation<T>(T[] arr, int n, Func<T[], bool> callback) {

bool SubPermutation(int len, int start) {
if (len == 0) {
T[] onePerm = new T[start];
Array.Copy(arr, onePerm, start);
return callback(onePerm);
}
for (int i = start; i < arr.Length; i++) {
T tmp = arr[i];
arr[i] = arr[start];
arr[start] = tmp;
if (!SubPermutation(len - 1, start + 1)) {
return false;
}
tmp = arr[i];
arr[i] = arr[start];
arr[start] = tmp;
}
return true;
}

int arrLen = arr.Length;
if (arrLen == 0 || n == 0 || n > arrLen || callback == null) {
return false;
}
return SubPermutation(n, 0);
}
}
}
Loading

0 comments on commit 276d81e

Please sign in to comment.