c#随机权重一些算法(免费)

  

在C#中,有以下几种常见的随机抽取方法:

1. `Random` 类:
Random random = new Random();
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int index = random.Next(array.Length); // 获取一个随机索引
int randomValue = array[index]; // 随机抽取数组中的一个元素

2. `Random` 类结合 ` LINQ`:
Random random = new Random();
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int randomValue = array.OrderBy(x => random.Next()).First(); // 随机抽取并返回数组中的一个元素

3. ` Fisher-Yates 洗牌算法`:
Random random = new Random();
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int i = array.Length - 1; i >= 0; i--)
{
    int j = random.Next(i + 1);
    int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}
int randomValue = array[0]; // 随机抽取并返回数组中的一个元素,同时原数组已经被随机打乱

4. 使用 `HashSet` 避免重复抽取:
Random random = new Random();
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
HashSet<int> usedNumbers = new HashSet<int>();
int randomValue;
do
{
    randomValue = array[random.Next(array.Length)];
} while (!usedNumbers.Add(randomValue)); // 循环直到抽取到一个未使用过的随机数

      以上就是在C#中进行随机抽取的几种常见方法,选择哪种方法取决于你的具体需求,如是否允许重复抽取、是否需要打乱原数组等。

        在C#中,如果你想要根据权重进行随机抽取,你可以创建一个字典,其中键代表选项,值代表相应的权重。然后,你可以实现一个算法来计算每个选项的累积权重,并基于生成的随机数在累积权重之间进行选择。

以下是一个简单的示例:
using System;
using System.Collections.Generic;
using System.Linq;

class WeightedRandomSelector
{
    public static T Select<T>(Dictionary<T, int> weights)
    {
        int totalWeight = weights.Values.Sum();
        Random random = new Random();

        // Generate a random number between 0 and the total weight
        int randomValue = random.Next(totalWeight);

        // Iterate through the dictionary, keeping track of the cumulative weight
        foreach (var item in weights)
        {
            randomValue -= item.Value;
            if (randomValue < 0)
            {
                return item.Key; // Return the current key when the random value is within its weight range
            }
        }

        // If the loop completes without returning a key, it means there was an error in the weights calculation
        throw new InvalidOperationException("Error in weight calculation.");
    }
}

// Example usage
Dictionary<string, int> options = new Dictionary<string, int>
{
    { "Option 1", 3 },
    { "Option 2", 2},
    { "Option 3", 1}
};

string selectedOption = WeightedRandomSelector.Select(options);
Console.WriteLine($"Selected option: {selectedOption}");

     在这个示例中,`Select`方法接收一个表示权重的字典,然后生成一个随机数并遍历字典,减去每个选项的权重。当随机数小于或等于零时,返回当前选项作为结果。这样,权重较高的选项被选中的概率就会更高。

    

        Fisher-Yates洗牌算法(也称为Knuth shuffle)是一种用于随机打乱数组元素顺序的算法。在C#中,以下是一个详细的Fisher-Yates洗牌算法的实现和说明:
using System;

class Program
{
    static void Main(string[] args)
    {
        int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        Console.WriteLine("Original array:");
        PrintArray(array);

        FisherYatesShuffle(array);

        Console.WriteLine("\nShuffled array:");
        PrintArray(array);
    }

    static void FisherYatesShuffle(int[] array)
    {
        Random random = new Random(); // 创建一个随机数生成器

        for (int i = array.Length - 1; i >= 0; i--)
        {
            // 生成一个从0到i(包括i)的随机索引
            int j = random.Next(i + 1);

            // 交换数组中的i和j位置的元素
            int temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
    }

    static void PrintArray(int[] array)
    {
        foreach (int item in array)
        {
            Console.Write(item + " ");
        }
        Console.WriteLine();
    }
}

以下是对该算法的详细说明:

1. 首先,我们创建一个包含待洗牌元素的数组。

2. 然后,我们调用`FisherYatesShuffle`函数来对数组进行洗牌。

3. 在`FisherYatesShuffle`函数中,我们首先创建一个`Random`对象,用于生成随机数。

4. 接下来,我们使用一个for循环,从数组的最后一个元素开始向前遍历。

5. 在每次循环中,我们生成一个随机索引`j`,它介于0和当前元素的索引`i`之间(包括`i`)。

6. 然后,我们将数组中索引为`i`和`j`的元素互换。这样就实现了将当前元素与一个随机选择的后续元素进行交换。

7. 这个过程会持续到遍历到数组的第一个元素。由于每个元素都有可能被后面的元素替换,所以最后得到的就是一个随机排列的数组。

8. 最后,我们在主程序中打印出原始数组和洗牌后的数组,以验证算法的效果。

     通过这个例子,我们可以看到Fisher-Yates洗牌算法如何在O(n)的时间复杂度内有效地随机打乱一个数组的元素顺序。在C#中,以下是一些可以用来随机打乱列表(List)的方法:

1. **使用 Fisher-Yates 洗牌算法**:

   这是一种常用的打乱列表顺序的算法。以下是一个简单的实现:

   public static void Shuffle<T>(this List<T> list)

   {

       Random rng = new Random();

       int n = list.Count;

       while (n > 1)

       {

           n--;

           int k = rng.Next(n + 1);

           T value = list[k];

           list[k] = list[n];

           list[n] = value;

       }

   }

  使用这种方式,你可以直接调用 `list.Shuffle()` 来打乱列表。

2. **使用 Linq**:

   虽然不是最高效的方法,但你可以使用 Linq 的 `OrderBy` 函数配合随机数生成器来打乱列表:

   Random rng = new Random();

   List<T> shuffledList = list.OrderBy(x => rng.Next()).ToList();

3. **使用 `Random` 类和 `Swap` 函数**:

   可以创建一个 `Swap` 函数来交换列表中的元素,然后使用 `Random` 类来随机选择要交换的元素位置。

   public static void Swap<T>(ref T a, ref T b)

   {

       T temp = a;

       a = b;

       b = temp;

   }

   public static void Shuffle<T>(this List<T> list)

   {

       Random rng = new Random();

       for (int i = list.Count - 1; i >= 0; i--)

       {

           int j = rng.Next(i + 1);

           Swap(ref list[i], ref list[j]);

       }

   }

        以上就是C#中几种常见的随机打乱列表的方法。其中,Fisher-Yates洗牌算法通常是效率最高的选择。

        在C#中,可以使用Fisher-Yates(也称为Knuth)洗牌算法来随机打乱数组内元素的顺序。以下是一个简单的实现:
public static void Shuffle<T>(this T[] array)
{
    Random rng = new Random();
    int n = array.Length;
    while (n > 1)
    {
        n--;
        int k = rng.Next(n + 1);
        T value = array[k];
        array[k] = array[n];
        array[n] = value;
    }
}
        这个扩展方法接受一个泛型数组,并在其上进行操作。它首先创建一个`Random`对象,然后遍历数组的每个元素(从最后一个元素开始)。对于每个元素,它生成一个随机索引(在当前元素及其之前的元素之间),然后将当前元素与随机索引处的元素交换。

要使用这个方法,你可以像这样调用:
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
numbers.Shuffle();
       这将会打乱`numbers`数组中的元素顺序。注意,由于随机数生成器的使用,每次调用`Shuffle`方法时,数组的打乱顺序都可能不同。

        一个C#方法,它根据源列表(source)和对应的权重列表(sourceWeight)进行随机抽取:
public static T GetRandomItemByWeight<T>(List<T> source, List<int> sourceWeight)
{
    if (source.Count != sourceWeight.Count)
    {
        throw new ArgumentException("Source list and weight list must have the same count.");
    }

    int totalWeight = sourceWeight.Sum();
    int randomWeight = new Random().Next(totalWeight);

    int currentWeight = 0;
    for (int i = 0; i < source.Count; i++)
    {
        currentWeight += sourceWeight[i];
        if (randomWeight <= currentWeight)
        {
            return source[i];
        }
    }

    // This line should never be reached if the input lists are valid.
    throw new InvalidOperationException("Unexpected error during random selection.");
}

       这个方法首先检查源列表和权重列表的长度是否相等。然后,它计算所有权重的总和,并生成一个介于0(包括)和总权重(不包括)之间的随机数。

        接下来,方法遍历源列表和权重列表,累加每个元素的权重。当累加的权重大于或等于随机权重时,返回对应源列表中的元素。

       请注意,这个方法假设权重列表的元素表示源列表中相应元素被选中的概率。如果权重列表的元素之和不是总权重(例如,它们只是相对权重而不是绝对权重),你需要在调用此方法之前先将权重归一化。

      以下是如何调用上面的 `GetRandomItemByWeight` 方法的示例:

      假设你有一个字符串列表和对应的权重列表:
List<string> source = new List<string> { "Apple", "Banana", "Cherry", "Date" };
List<int> sourceWeight = new List<int> { 2, 3, 1, 4};

      在这个例子中,"Apple" 的权重是2,"Banana" 的权重是3,"Cherry" 的权重是1,"Date" 的权重是4。这意味着 "Date" 被选中的概率最高,其次是 "Banana",然后是 "Apple","Cherry" 的概率最低。

        要根据这些权重随机抽取一个元素,你可以这样调用 `GetRandomItemByWeight` 方法:
string randomItem = GetRandomItemByWeight(source, sourceWeight);
Console.WriteLine($"Randomly selected item: {randomItem}");
       每次运行这段代码,你都可能得到不同的结果,因为它是基于权重进行随机抽取的。例如,你可能会得到 "Date"、"Banana"、"Apple" 或 "Cherry" 中的任意一个。

        Dijkstra算法是一种用于寻找图中两点之间最短路径的算法。以下是一个C#实现的Dijkstra算法,包括权重:
using System;
using System.Collections.Generic;

class Node
{
    public int Id { get; set; }
    public double Distance { get; set; }
    public bool Visited { get; set; }
    public List<Edge> Edges { get; set; }

    public Node(int id)
    {
        Id = id;
        Distance = double.PositiveInfinity;
        Visited = false;
        Edges = new List<Edge>();
    }
}

class Edge
{
    public Node Target { get; set; }
    public double Weight { get; set; }

    public Edge(Node target, double weight)
    {
        Target = target;
        Weight = weight;
    }
}

class DijkstraAlgorithm
{
    public static void FindShortestPath(Node startNode)
    {
        startNode.Distance = 0;

        var unvisitedNodes = new List<Node>(startNode.Edges.Select(e => e.Target));
        while (unvisitedNodes.Count > 0)
        {
            unvisitedNodes.Sort((a, b) => a.Distance.CompareTo(b.Distance));

            var currentNode = unvisitedNodes[0];
            if (currentNode.Distance == double.PositiveInfinity)
                break;

            currentNode.Visited = true;
            unvisitedNodes.Remove(currentNode);

            foreach (var edge in currentNode.Edges)
            {
                var neighbor = edge.Target;
                var distanceThroughCurrentNode = currentNode.Distance + edge.Weight;
                if (!neighbor.Visited && distanceThroughCurrentNode < neighbor.Distance)
                {
                    neighbor.Distance = distanceThroughCurrentNode;
                    unvisitedNodes.Add(neighbor);
                }
            }
        }
    }
}

        在这个实现中,我们定义了两个类:`Node` 和 `Edge`。每个节点都有一个ID、一个距离(初始时为正无穷大,表示尚未找到路径)、一个访问标志(初始时为false)和一个边列表。每条边都有一个目标节点和一个权重。

       `DijkstraAlgorithm` 类包含一个静态方法 `FindShortestPath`,该方法接受一个起始节点作为参数。方法内部首先将起始节点的距离设置为0,然后创建一个未访问节点列表。

       在主循环中,算法每次选择未访问节点中距离最小的一个,并将其标记为已访问。然后,对于当前节点的每一条边,算法检查是否可以通过这条边到达一个更近的邻居节点。如果是,就更新邻居节点的距离,并将其添加到未访问节点列表中。

       当所有节点都被访问过或者没有更近的邻居节点可以到达时,算法结束。此时,每个节点的距离字段就包含了从起始节点到该节点的最短距离。你可以通过遍历节点和边来构建最短路径。

       以下是如何调用上面的 `DijkstraAlgorithm` 方法的示例:

       首先,我们需要创建一个图。假设我们有一个简单的图,包含以下节点和边:

1. 节点A:连接到节点B(权重为2),节点C(权重为5)
2. 节点B:连接到节点A(权重为2),节点C(权重为1),节点D(权重为3)
3. 节点C:连接到节点A(权重为5),节点B(权重为1),节点D(权重为2)
4. 节点D:连接到节点B(权重为3),节点C(权重为2)

以下是创建这个图并调用 `DijkstraAlgorithm` 的代码:
class Program
{
    static void Main(string[] args)
    {
        Node nodeA = new Node(0);
        Node nodeB = new Node(1);
        Node nodeC = new Node(2);
        Node nodeD = new Node(3);

        nodeA.Edges.Add(new Edge(nodeB, 2));
        nodeA.Edges.Add(new Edge(nodeC, 5));

        nodeB.Edges.Add(new Edge(nodeA, 2));
        nodeB.Edges.Add(new Edge(nodeC, 1));
        nodeB.Edges.Add(new Edge(nodeD, 3));

        nodeC.Edges.Add(new Edge(nodeA, 5));
        nodeC.Edges.Add(new Edge(nodeB, 1));
        nodeC.Edges.Add(new Edge(nodeD, 2));

        nodeD.Edges.Add(new Edge(nodeB, 3));
        nodeD.Edges.Add(new Edge(nodeC, 2));

        DijkstraAlgorithm.FindShortestPath(nodeA);

        Console.WriteLine($"Shortest path from node A to other nodes:");
        Console.WriteLine($"Node B: {nodeB.Distance}");
        Console.WriteLine($"Node C: {nodeC.Distance}");
        Console.WriteLine($"Node D: {nodeD.Distance}");
    }
}
        在这个例子中,我们首先创建了四个节点和相应的边。然后,我们调用 `DijkstraAlgorithm.FindShortestPath` 方法,传入节点A作为起始节点。

        算法运行后,每个节点的距离字段将包含从节点A到该节点的最短距离。在 `Main` 方法的最后,我们打印出从节点A到其他节点的最短路径长度。

        请注意,这个实现只计算了最短路径的长度,但没有实际构建最短路径。如果你需要构建最短路径,你可以在 `Node` 类中添加一个父节点字段,并在更新节点距离时同时更新其父节点。然后,你可以通过回溯父节点来构建最短路径。

        以下是一个简单的C#实现 of the KMP (Knuth-Morris-Pratt) algorithm for string matching:
using System;

class KMPAlgorithm
{
    static void GetNext(string pattern, int[] next)
    {
        int j = 0;
        next[0] = -1;
        for (int i = 1; i < pattern.Length; i++)
        {
            while (j > -1 && pattern[i] != pattern[j])
            {
                j = next[j];
            }
            j++;
            next[i] = j;
        }
    }

    static void KMPSearch(string text, string pattern)
    {
        int[] next = new int[pattern.Length];
        GetNext(pattern, next);

        int j = 0;
        for (int i = 0; i < text.Length; i++)
        {
            while (j > -1 && text[i] != pattern[j])
            {
                j = next[j];
            }
            j++;
            if (j == pattern.Length)
            {
                Console.WriteLine("Pattern found at index: " + (i - pattern.Length + 1));
                j = next[j];
            }
        }
    }

    public static void Main()
    {
        string text = "ABCDABCDABCD";
        string pattern = "ABCDA";
        KMPSearch(text, pattern);
    }
}
       在这个实现中,`GetNext`函数用于计算模式串的next数组,这个数组用于在匹配过程中快速回溯。`KMPSearch`函数则实现了实际的字符串搜索过程。

       当在文本中找到一个模式匹配时,它会打印出模式在文本中的起始位置索引。在这个例子中,我们在文本"ABCDABCDABCD"中搜索模式"ABCDA",输出结果应该是"Pattern found at index: 0"和"Pattern found at index: 5",因为模式在文本的这两个位置出现。

     

         在C#中,你可以使用Dictionary<TKey, TValue>来计算一个数字序列中每个数字出现的次数。以下是一个简单的示例,它计算一个整数数组中每个数字的出现次数:
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        int[] numbers = { 1, 2, 3, 2, 1, 3, 4, 2, 5, 1 };

        Dictionary<int, int> countMap = new Dictionary<int, int>();

        foreach (int num in numbers)
        {
            if (countMap.ContainsKey(num))
            {
                countMap[num]++;
            }
            else
            {
                countMap.Add(num, 1);
            }
        }

        foreach (KeyValuePair<int, int> pair in countMap)
        {
            Console.WriteLine("Number {0} appears {1} times.", pair.Key, pair.Value);
        }
    }
}
        在这个示例中,我们首先创建了一个空的Dictionary `countMap`,然后遍历数组`numbers`。对于数组中的每个数字,如果该数字已经在字典中,我们就增加它的计数;如果不在,我们就将该数字添加到字典中并设置其计数为1。最后,我们遍历字典并打印出每个数字及其出现的次数。

 

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值