最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#洗牌算法的具體實(shí)現(xiàn)

 更新時(shí)間:2025年07月27日 09:50:50   作者:張謹(jǐn)?shù)W  
洗牌算法是一種將序列元素隨機(jī)打亂的經(jīng)典算法,讓每個(gè)元素在打亂后出現(xiàn)在任意位置的概率均等,下面就來具體介紹一下洗牌算法的實(shí)現(xiàn),感興趣的可以了解一下

洗牌算法是一種將序列(如數(shù)組、列表)元素隨機(jī)打亂的經(jīng)典算法,核心目標(biāo)是讓每個(gè)元素在打亂后出現(xiàn)在任意位置的概率均等。在 C# 中,常用的洗牌算法有Fisher-Yates 洗牌算法(也稱 Knuth 洗牌算法),它高效且公平,時(shí)間復(fù)雜度為 O (n),空間復(fù)雜度為 O (1)。

一、Fisher-Yates 洗牌算法原理

  1. 核心思想:從序列的最后一個(gè)元素開始,依次與前面的隨機(jī)位置元素交換,直到處理完第一個(gè)元素。
  2. 公平性保證:每個(gè)元素被放置在任意位置的概率均為 1/n(n 為序列長度),避免了 “部分隨機(jī)” 導(dǎo)致的分布不均問題。

二、C# 實(shí)現(xiàn)示例

以下是使用 Fisher-Yates 算法對(duì)整數(shù)數(shù)組、字符串列表進(jìn)行洗牌的實(shí)現(xiàn):

代碼分塊分析

這段代碼是一個(gè)簡化的斗地主游戲?qū)崿F(xiàn),主要包含撲克牌的生成、洗牌、發(fā)牌和排序功能。下面我將對(duì)代碼進(jìn)行分塊分析。

1. 主程序結(jié)構(gòu)與初始化

static void Main(string[] args)
{
    int[] ints1 = new int[54];
    ints1 = RandomUNorepeatArray(ints1);
    
    // 后續(xù)代碼...
}

這部分代碼首先創(chuàng)建了一個(gè)包含 54 個(gè)元素的整數(shù)數(shù)組ints1,并調(diào)用RandomUNorepeatArray方法生成 0-53 的隨機(jī)不重復(fù)數(shù)組,用于作為撲克牌的隨機(jī)索引。

2. 撲克牌對(duì)象模型

class Puke
{
    public string number;
    public char color;
    
    public override string ToString()
    {
        return $"[{number},{color}]";
    }
}

Puke類表示一張撲克牌,包含兩個(gè)屬性:

  • number:牌面數(shù)字(字符串類型,"1"-"13" 或 "joker")
  • color:花色(字符類型,' 黑 '、' 紅 '、' 梅 '、' 方 ')
  • 重寫的ToString方法用于格式化輸出牌的信息

3. 撲克牌生成與初始化

Puke[] puke = new Puke[54];
int num = 1;
char[] str = new char[4] {'黑', '紅', '梅', '方' };
int num2 = 3;
for (int i = 0; i < 52; i++)
{
    puke[i] = new Puke();
    if (num > 13)
    {
        num = 1;
        num2--;
    }
    puke[i].number = num.ToString();
    num++;
    puke[i].color = str[num2];
}
puke[52] = new Puke { number = "joker", color = '黑' };
puke[53] = new Puke { number = "joker", color = '紅' };

這段代碼生成了 54 張撲克牌:

  • 前 52 張是四種花色的 A-K(用數(shù)字 1-13 表示)
  • 最后兩張是大小王("joker")

4. 洗牌與發(fā)牌

Puke[] puke2 = new Puke[54];
for (int i = 0; i < 54; i++)
{
    puke2[i] = puke[ints1[i]];
}
?
// 發(fā)牌給三個(gè)玩家和底牌
Puke[] puke3 = new Puke[17];
Puke[] puke4 = new Puke[17];
Puke[] puke5 = new Puke[17];
Puke[] puke6 = new Puke[3];
for (int i = 0; i < 17; i++)
{
    puke3[i] = puke2[ints1[i]];
    puke4[i] = puke2[ints1[i + 17]];
    puke5[i] = puke2[ints1[i + 24]]; // 這里索引計(jì)算有問題!
}
for(int i = 0; i < 3; i++)
{
    puke6[i] = puke2[ints1[i+51]];
}

這部分代碼實(shí)現(xiàn)了洗牌和發(fā)牌:

  • 使用隨機(jī)索引數(shù)組ints1重新排列撲克牌數(shù)組
  • 將牌分發(fā)給三個(gè)玩家(各 17 張)和底牌(3 張)

5. 排序算法

Array.Sort(puke3, (a, b) =>
{
    int numA = a.number == "joker" ? 100 : int.Parse(a.number);
    int numB = b.number == "joker" ? 100 : int.Parse(b.number);
    int result = numA.CompareTo(numB);
    if (result == 0)
        return a.color.CompareTo(b.color);
    return result;
});
?
// 對(duì)puke4和puke5有相同的排序代碼...

這部分代碼對(duì)每個(gè)玩家的手牌進(jìn)行排序:

  • 將牌面值轉(zhuǎn)換為整數(shù)進(jìn)行比較(Joker 設(shè)為 100)
  • 牌面值相同則比較花色

6. 輔助方法:生成隨機(jī)不重復(fù)數(shù)組

static int[] RandomUNorepeatArray(int[] ints )
{
    int min = 0;
    int max = 53;
    int count = 54;
?
    List<int> pool = new List<int>();
    for (int i = min; i <= max; i++)
        pool.Add(i);
?
    Random rand = new Random();
    // 洗牌算法
    for (int i = pool.Count - 1; i > 0; i--)
    {
        int j = rand.Next(0, i + 1);
        int temp = pool[i];
        pool[i] = pool[j];
        pool[j] = temp;
    }
?
    return pool.ToArray();
}

這個(gè)方法使用 Fisher-Yates 洗牌算法生成 0-53 的隨機(jī)排列數(shù)組。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
?
namespace 斗地主
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] ints1 = new int[54];
            ints1 = RandomUNorepeatArray(ints1);
?
            // //Console.WriteLine(string.Join(" ", ints1));
?
            // string[] strings = new string[]
            //{
            //     "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
            //     "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
            //     "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
            //     "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
            //     "j1", "j2"
            //};
?
            // string[] strings2 = new string[60];
?
            // Random random = new Random();
?
            // for (int i = 0; i < ints1.Length; i++)
            // {
            //    // int ints3 = random.Next(ints1.Length);
            //     strings2[i] = strings[ints1[i]];
            // }
            // int num = 0;
?
            // foreach (string s in strings2)
            // {
            //     Console.Write($"{s,-4}");
            //     num++;
            //     if (num % 17 == 0) Console.WriteLine();
            // }
?
            Puke[] puke = new Puke[54];
            int num = 1;
            char[] str = new char[4] {'黑', '紅', '梅', '方' };
            int num2 = 3;
            for (int i = 0; i < 52; i++)
            {
                puke[i] = new Puke();
                if (num > 13)
                {
                    num = 1;
                    num2--;
                }
                puke[i].number = num.ToString();
                num++;
                puke[i].color = str[num2];
            }
            puke[52] = new Puke { number = "joker", color = '黑' };
            puke[53] = new Puke { number = "joker", color = '紅' };
?
            Puke[] puke2 = new Puke[54];
            for (int i = 0; i < 54; i++)
            {
               puke2[i] = puke[ints1[i]];
            }
?
            int count = 0;
            foreach (var item in puke2)
            {
                Console.Write($"{item,-4}");
                count++;
                if (count % 17 == 0) Console.WriteLine();
?
                //count++;
                //if (count%13 == 0) Console.WriteLine();
            }
?
            Puke[] puke3 = new Puke[17];
            Puke[] puke4 = new Puke[17];
            Puke[] puke5 = new Puke[17];
            Puke[] puke6 = new Puke[3];
            for (int i = 0; i < 17; i++)
            {
                puke3[i] = puke2[ints1[i]];
                puke4[i] = puke2[ints1[i + 17]];
                puke5[i] = puke2[ints1[i + 24]];
            }
            for(int i = 0; i < 3; i++)
            {
                puke6[i] = puke2[ints1[i+51]];
            }
?
            Array.Sort(puke3, (a, b) =>
            {
                int numA = a.number == "joker" ? 100 : int.Parse(a.number);
                int numB = b.number == "joker" ? 100 : int.Parse(b.number);
                int result = numA.CompareTo(numB);
                if (result == 0)
                    return a.color.CompareTo(b.color);
                return result;
            });
?
            Array.Sort(puke4, (a, b) =>
            {
                int numA = a.number == "joker" ? 100 : int.Parse(a.number);
                int numB = b.number == "joker" ? 100 : int.Parse(b.number);
                int result = numA.CompareTo(numB);
                if (result == 0)
                    return a.color.CompareTo(b.color);
                return result;
            });
?
            Array.Sort(puke5, (a, b) =>
            {
                int numA = a.number == "joker" ? 100 : int.Parse(a.number);
                int numB = b.number == "joker" ? 100 : int.Parse(b.number);
                int result = numA.CompareTo(numB);
                if (result == 0)
                    return a.color.CompareTo(b.color);
                return result;
            });
?
            Console.WriteLine();
            Console.Write("=============================");
            Console.WriteLine();
?
            int c = 0;
            foreach (var item in puke3)
            {
                Console.Write($"{item,-6}");
                
                //count++;
                //if (count%13 == 0) Console.WriteLine();
            }
            Console.WriteLine();
            foreach (var item in puke4)
            {
                Console.Write($"{item,-6}");
            
                //count++;
                //if (count%13 == 0) Console.WriteLine();
            }
            Console.WriteLine();
            foreach (var item in puke5)
            {
                Console.Write($"{item,-6}");
                //count++;
                //if (count%13 == 0) Console.WriteLine();
            }
            Console.WriteLine();
            foreach (var item in puke6)
            {
                Console.Write($"{item,-6}");
                //count++;
                //if (count%13 == 0) Console.WriteLine();
            }
?
            //Array.Sort(puke2, (a, b) =>
            //{
            //    int result = a.number.CompareTo(b.number);
            //    if (result == 0)
            //    {
            //        return b.color.CompareTo(a.color);
            //    }
            //    return result;
            //});
?
        }
?
        
        //生成一定范圍內(nèi)隨機(jī)不成重復(fù)數(shù)字的數(shù)組
        static int[] RandomUNorepeatArray(int[] ints )
        {
            int min = 0;
            int max = 53; // 生成1~20之間的不重復(fù)數(shù)字
            int count = 54; // 需要的數(shù)量
?
            List<int> pool = new List<int>();
            for (int i = min; i <= max; i++)
                pool.Add(i);
?
            //Fisher-Yates 洗牌算法
            Random rand = new Random();
            // 洗牌
            for (int i = pool.Count - 1; i > 0; i--)
            {
                int j = rand.Next(0, i + 1);
                int temp = pool[i];
                pool[i] = pool[j];
                pool[j] = temp;
            }
?
            // 取前count個(gè)
            //for (int i = 0; i < count; i++)
            //{
            //    Console.Write(pool[i] + " ");
            //}
            //Console.WriteLine();
?
?
            return pool.ToArray();
        }
    }
?
?
    class Puke
    {
        // 牌的數(shù)字  A-K    用1-13表示
        public string number;
        // 牌的花色  黑紅梅方   4321
        public char color;
        public override string ToString()
        {
            return $"[{number},{color}]";
        }
?
    }
?
}
?

三、代碼說明

  1. 泛型方法Shuffle<T> 支持任意類型的數(shù)組和列表,通用性強(qiáng)。
  2. 隨機(jī)索引生成random.Next(i + 1) 確保生成的索引 j[0, i] 范圍內(nèi),避免越界。
  3. 元素交換:使用 C# 7.0 引入的元組交換語法 (a, b) = (b, a),簡潔高效(也可使用臨時(shí)變量交換)。
  4. Random 實(shí)例:在方法內(nèi)創(chuàng)建單個(gè) Random 實(shí)例,避免短時(shí)間內(nèi)多次創(chuàng)建導(dǎo)致的隨機(jī)序列重復(fù)問題。

四、算法優(yōu)勢

  • 公平性:每個(gè)元素在每個(gè)位置的概率嚴(yán)格相等,無偏差。
  • 高效性:僅需一次遍歷和 n-1 次交換,時(shí)間復(fù)雜度 O (n),空間復(fù)雜度 O (1)(原地洗牌,無需額外空間)。
  • 適用性:適用于任何可索引的序列(數(shù)組、列表等),廣泛應(yīng)用于卡牌游戲、隨機(jī)排序、數(shù)據(jù)打亂等場景。

五、注意事項(xiàng)

  • Random 的線程安全:若在多線程環(huán)境中使用,需確保 Random 實(shí)例的線程安全(可使用 Random.Shared 或加鎖)。
  • 重復(fù)執(zhí)行的隨機(jī)性:若需每次運(yùn)行生成不同的打亂結(jié)果,不要手動(dòng)指定 Random 的種子(默認(rèn)使用系統(tǒng)時(shí)間作為種子)。

示例輸出

[8,梅][4,方][1,梅][3,梅][12,方][4,紅][9,黑][2,方][13,梅][9,方][7,黑][joker,紅][11,方][joker,黑][13,黑][9,紅][6,紅]
[10,紅][12,黑][9,梅][11,黑][3,紅][10,方][11,梅][12,梅][10,黑][6,梅][7,梅][2,紅][5,梅][12,紅][4,黑][3,黑][1,紅]
[10,梅][8,紅][6,方][5,紅][11,紅][1,黑][3,方][6,黑][5,黑][1,方][2,梅][13,紅][8,方][4,梅][8,黑][5,方][2,黑]
[7,方][7,紅][13,方]
=============================
[3,梅] [4,方] [4,梅] [4,黑] [5,梅] [7,方] [7,紅] [7,黑] [9,紅] [10,梅][10,黑][11,黑][13,方][13,梅][13,紅][joker,紅][joker,黑]
[2,紅] [2,黑] [3,紅] [5,方] [5,紅] [5,黑] [6,梅] [6,黑] [7,梅] [8,紅] [8,黑] [9,方] [9,梅] [10,紅][11,梅][12,梅][12,黑]
[1,梅] [1,紅] [1,黑] [4,紅] [5,紅] [5,黑] [6,方] [6,梅] [6,黑] [7,梅] [8,黑] [9,梅] [10,方][10,紅][12,梅][12,紅][12,黑]
[9,黑] [3,黑] [11,方]

到此這篇關(guān)于C#洗牌算法的具體實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C#洗牌算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • c#EXCEL關(guān)閉方式(關(guān)閉EXCEL進(jìn)程)

    c#EXCEL關(guān)閉方式(關(guān)閉EXCEL進(jìn)程)

    文章介紹了在C#中關(guān)閉Excel進(jìn)程的問題,并提供了一個(gè)解決方案,通過獲取當(dāng)前進(jìn)程的ID來關(guān)閉特定的Excel進(jìn)程,而不是關(guān)閉所有Excel進(jìn)程
    2025-11-11
  • UnityUI中繪制線狀統(tǒng)計(jì)圖

    UnityUI中繪制線狀統(tǒng)計(jì)圖

    這篇文章介紹了UnityUI中繪制線狀統(tǒng)計(jì)圖的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • C#子線程執(zhí)行完后通知主線程的方法

    C#子線程執(zhí)行完后通知主線程的方法

    下面小編就為大家?guī)硪黄狢#子線程執(zhí)行完后通知主線程的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-12-12
  • 淺析C#如何在自定義事件里傳遞數(shù)據(jù)

    淺析C#如何在自定義事件里傳遞數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了C#在自定義事件里傳遞數(shù)據(jù)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下
    2024-12-12
  • c# 如何實(shí)現(xiàn)代碼生成器

    c# 如何實(shí)現(xiàn)代碼生成器

    這篇文章主要介紹了c# 如何實(shí)現(xiàn)代碼生成器,幫助大家更好的理解和使用c# 編程語言,感興趣的朋友可以了解下
    2020-12-12
  • C# 使用 log4net 日志組件的方法

    C# 使用 log4net 日志組件的方法

    這篇文章主要介紹了C# 使用 log4net 日志組件的方法,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2020-12-12
  • 分享用于操作FTP的客戶端C#類

    分享用于操作FTP的客戶端C#類

    用.net自帶的FtpWebRequest做的ftp客戶端得程序,有一個(gè)功能實(shí)現(xiàn)起來會(huì)非常苦難,就是移動(dòng)文件和文件夾的功能。所以后來又找了一個(gè)類,用socket實(shí)現(xiàn)的,發(fā)現(xiàn)比用ftpWebRequest功能要強(qiáng)?;镜膄tp客戶端得命令都實(shí)現(xiàn)了。
    2015-05-05
  • C# wx獲取token的基本方法

    C# wx獲取token的基本方法

    這篇文章主要為大家詳細(xì)介紹了C# wx獲取token的基本方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • C#中實(shí)現(xiàn)深度優(yōu)先搜索

    C#中實(shí)現(xiàn)深度優(yōu)先搜索

    深度優(yōu)先搜索(DFS)是一種遍歷或搜索圖或樹的算法,廣泛應(yīng)用于迷宮尋路、圖像處理、路徑規(guī)劃、模式識(shí)別、社交網(wǎng)絡(luò)分析等領(lǐng)域,學(xué)習(xí)DFS有助于理解圖結(jié)構(gòu),解決回溯問題,提升算法設(shè)計(jì)與分析能力,下面就來介紹一下
    2024-10-10
  • C#實(shí)現(xiàn)跨線程操作控件方法

    C#實(shí)現(xiàn)跨線程操作控件方法

    這篇文章主要介紹了C#實(shí)現(xiàn)跨線程操作控件方法,主要采用異步訪問方式實(shí)現(xiàn),需要的朋友可以參考下
    2014-10-10

最新評(píng)論

双牌县| 宜兰市| 无极县| 龙井市| 嘉禾县| 罗甸县| 合川市| 桑日县| 荔波县| 会同县| 锡林浩特市| 喀喇| 浑源县| 吐鲁番市| 揭西县| 运城市| 清水县| 武宁县| 临城县| 拜泉县| 德昌县| 南京市| 德钦县| 赣州市| 息烽县| 灯塔市| 随州市| 丰城市| 洛南县| 苗栗市| 句容市| 正安县| 大厂| 济宁市| 昌宁县| 义乌市| 阳新县| 巴青县| 玉门市| 鄂伦春自治旗| 金川县|