Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 随机播放列表算法_C#_Algorithm_Playlist_Smart Playlist - Fatal编程技术网

C# 随机播放列表算法

C# 随机播放列表算法,c#,algorithm,playlist,smart-playlist,C#,Algorithm,Playlist,Smart Playlist,我需要创建一个随机顺序范围内的数字列表(例如从x到y),这样每个顺序都有相同的机会 我需要一个我用C#写的音乐播放器,以随机顺序创建播放列表 有什么想法吗 谢谢 编辑:我对更改原始列表不感兴趣,只需按随机顺序从范围中选取随机索引,以便每个顺序都有相同的机会 以下是我到目前为止写的: public static IEnumerable<int> RandomIndexes(int count) { if (count > 0) {

我需要创建一个随机顺序范围内的数字列表(例如从x到y),这样每个顺序都有相同的机会

我需要一个我用C#写的音乐播放器,以随机顺序创建播放列表

有什么想法吗

谢谢

编辑:我对更改原始列表不感兴趣,只需按随机顺序从范围中选取随机索引,以便每个顺序都有相同的机会

以下是我到目前为止写的:

    public static IEnumerable<int> RandomIndexes(int count)
    {
        if (count > 0)
        {
            int[] indexes = new int[count];
            int indexesCountMinus1 = count - 1;

            for (int i = 0; i < count; i++)
            {
                indexes[i] = i;
            }

            Random random = new Random();

            while (indexesCountMinus1 > 0)
            {
                int currIndex = random.Next(0, indexesCountMinus1 + 1);
                yield return indexes[currIndex];

                indexes[currIndex] = indexes[indexesCountMinus1];
                indexesCountMinus1--;
            }

            yield return indexes[0];
        }
    }
公共静态IEnumerable随机索引(int计数)
{
如果(计数>0)
{
int[]索引=新的int[count];
int indexConsontMinus1=计数-1;
for(int i=0;i0)
{
int currIndex=random.Next(0,INDEXESCONNTMINUS1+1);
收益率指数[货币指数];
索引[currIndex]=索引[IndexExcontMinus1];
IndexeConntMinus1--;
}
收益率指标[0];
}
}
它正在工作,但唯一的问题是我需要在内存中分配一个大小为
count
的数组。我正在寻找不需要内存分配的东西


谢谢。

如果你不小心(例如,使用幼稚的洗牌算法),这实际上可能会很棘手。请看一看正确的值分布

一旦你有了洗牌算法,剩下的应该很简单

这是杰夫·阿特伍德的来信

最后,这是乔恩·斯基特的

编辑

我不相信有一种解决方案能够满足您的两个相互冲突的需求(第一,随机无重复,第二,不分配任何额外内存)。我相信您可能过早地优化了您的解决方案,因为内存影响应该可以忽略不计,除非您是嵌入式的。或者,也许我不够聪明,无法想出一个答案

下面的代码将使用Knuth-Fisher-Yates算法(稍加修改)创建一个均匀分布的随机索引数组。您可以缓存生成的数组,或者根据实现的其余部分执行任意数量的优化

  private static int[] BuildShuffledIndexArray( int size ) {

     int[] array = new int[size];
     Random rand = new Random();
     for ( int currentIndex = array.Length - 1; currentIndex > 0; currentIndex-- ) {
        int nextIndex = rand.Next( currentIndex + 1 );
        Swap( array, currentIndex, nextIndex );
     }
     return array;
  }

  private static void Swap( IList<int> array, int firstIndex, int secondIndex ) {

     if ( array[firstIndex] == 0 ) {
        array[firstIndex] = firstIndex;
     }
     if ( array[secondIndex] == 0 ) {
        array[secondIndex] = secondIndex;
     }
     int temp = array[secondIndex];
     array[secondIndex] = array[firstIndex];
     array[firstIndex] = temp;
  }
private static int[]BuildShuffledIndexArray(int size){
int[]数组=新的int[size];
Random rand=新的Random();
对于(int currentIndex=array.Length-1;currentIndex>0;currentIndex--){
int-nextIndex=rand.Next(当前索引+1);
交换(数组、currentIndex、nextIndex);
}
返回数组;
}
专用静态无效交换(IList数组、int firstIndex、int secondIndex){
if(数组[firstIndex]==0){
数组[firstIndex]=firstIndex;
}
if(数组[secondIndex]==0){
数组[secondIndex]=secondIndex;
}
int temp=数组[secondIndex];
数组[secondIndex]=数组[firstIndex];
数组[firstIndex]=温度;
}
注意:只要播放列表中的项目不超过65535个,就可以使用
ushort
而不是
int
将内存大小减半。如果大小超过
ushort.MaxValue
,则始终可以通过编程方式切换到
int
。如果我个人在一个播放列表中添加了超过65K个项目,我不会对内存利用率的提高感到震惊

还要记住,这是一种托管语言。虚拟机将始终保留比您使用的内存更多的内存,以限制它向操作系统请求更多RAM和限制碎片的次数

  private static int[] BuildShuffledIndexArray( int size ) {

     int[] array = new int[size];
     Random rand = new Random();
     for ( int currentIndex = array.Length - 1; currentIndex > 0; currentIndex-- ) {
        int nextIndex = rand.Next( currentIndex + 1 );
        Swap( array, currentIndex, nextIndex );
     }
     return array;
  }

  private static void Swap( IList<int> array, int firstIndex, int secondIndex ) {

     if ( array[firstIndex] == 0 ) {
        array[firstIndex] = firstIndex;
     }
     if ( array[secondIndex] == 0 ) {
        array[secondIndex] = secondIndex;
     }
     int temp = array[secondIndex];
     array[secondIndex] = array[firstIndex];
     array[firstIndex] = temp;
  }
编辑

好的,最后一次尝试:我们可以调整性能/内存权衡:您可以创建整数列表,然后将其写入磁盘。然后在文件中保留一个指向偏移量的指针。然后,每当您需要一个新号码时,您只需要处理磁盘I/O。也许您可以在这里找到一些平衡,只需将N个大小的数据块读入内存,其中N是您熟悉的数字


洗牌算法似乎需要做很多工作,但如果你死心塌地地想保存内存,那么至少这是一个选择。

就个人而言,对于音乐播放器而言,我不会生成一个洗牌列表,然后播放该列表,然后在该列表用完时生成另一个洗牌列表,但可以执行以下操作:

IEnumerable<Song> GetSongOrder(List<Song> allSongs)
{
    var playOrder = new List<Song>();
    while (true)
    {
        // this step assigns an integer weight to each song,
        // corresponding to how likely it is to be played next.
        // in a better implementation, this would look at the total number of
        // songs as well, and provide a smoother ramp up/down.
        var weights = allSongs.Select(x => playOrder.LastIndexOf(x) > playOrder.Length - 10 ? 50 : 1);

        int position = random.Next(weights.Sum());
        foreach (int i in Enumerable.Range(allSongs.Length))
        {
            position -= weights[i];
            if (position < 0)
            {
                var song = allSongs[i];
                playOrder.Add(song);
                yield return song;
                break;
            }
        }

        // trim playOrder to prevent infinite memory here as well.
        if (playOrder.Length > allSongs.Length * 10)
            playOrder = playOrder.Skip(allSongs.Length * 8).ToList();
    }    
}
IEnumerable GetSongOrder(列出所有歌曲)
{
var playOrder=新列表();
while(true)
{
//此步骤为每首歌曲分配整数权重,
//对应于下一次播放的可能性。
//在更好的实现中,这将查看
//歌曲,并提供更平滑的上升/下降。
var-weights=allSongs.Select(x=>playOrder.LastIndexOf(x)>playOrder.Length-10?50:1);
int position=random.Next(weights.Sum());
foreach(可枚举范围(allSongs.Length)中的int i)
{
位置-=重量[i];
如果(位置<0)
{
var song=所有歌曲[i];
播放顺序。添加(歌曲);
回归歌曲;
打破
}
}
//修剪播放顺序,以防止此处出现无限内存。
如果(playOrder.Length>allSongs.Length*10)
playOrder=playOrder.Skip(allSongs.Length*8.ToList();
}    
}

这将使歌曲按顺序挑选,只要它们最近没有播放过。这提供了从一次洗牌结束到下一次洗牌结束的“更平滑”过渡,因为下一次洗牌的第一首歌曲可能与上一次洗牌的歌曲相同,概率为1/(总歌曲),而此算法的概率较低(且可配置)再次听到最后一首x歌的机会。

我认为您应该坚持当前的解决方案(o
0: {1, 2, 3}
1: {1, 3, 2}
2: {2, 1, 3}
3: {2, 3, 1}
4: {3, 1, 2}
5: {3, 2, 1}
public class MaximalLFSR
{
    private int GetFeedbackSize(uint v)
    {
        uint r = 0;

        while ((v >>= 1) != 0)
        {
          r++;
        }
        if (r < 4)
            r = 4;
        return (int)r;
    }

    static uint[] _feedback = new uint[] {
        0x9, 0x17, 0x30, 0x44, 0x8e,
        0x108, 0x20d, 0x402, 0x829, 0x1013, 0x203d, 0x4001, 0x801f,
        0x1002a, 0x2018b, 0x400e3, 0x801e1, 0x10011e, 0x2002cc, 0x400079, 0x80035e,
        0x1000160, 0x20001e4, 0x4000203, 0x8000100, 0x10000235, 0x2000027d, 0x4000016f, 0x80000478
    };

    private uint GetFeedbackTerm(int bits)
    {
        if (bits < 4 || bits >= 28)
            throw new ArgumentOutOfRangeException("bits");
        return _feedback[bits];
    }

    public IEnumerable<int> RandomIndexes(int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException("count");

        int bitsForFeedback = GetFeedbackSize((uint)count);

        Random r = new Random();
        uint i = (uint)(r.Next(1, count - 1));

        uint feedback = GetFeedbackTerm(bitsForFeedback);
        int valuesReturned = 0;
        while (valuesReturned < count)
        {
            if ((i & 1) != 0)
            {
                i = (i >> 1) ^ feedback;
            }
            else {
                i = (i >> 1);
            }
            if (i <= count)
            {
                valuesReturned++;
                yield return (int)(i-1);
            }
        }
    }
}
    static void Main(string[] args)
    {
        while (true)
        {
            Console.Write("Enter a count: ");
            string s = Console.ReadLine();
            int count;
            if (Int32.TryParse(s, out count))
            {
                MaximalLFSR lfsr = new MaximalLFSR();
                foreach (int i in lfsr.RandomIndexes(count))
                {
                    Console.Write(i + ", ");
                }
            }
            Console.WriteLine("Done.");
        }
    }
    public static IEnumerable<int> RandomIndexes(int count) {
        Random rand = new Random();
        bool[] used = new bool[count];

        int i;
        for (int counter = 0; counter < count; counter++) {
            while (used[i = rand.Next(count)]); //i = some random unused value
            used[i] = true;
            yield return i;
        }
    }
using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
    class Program
    {
        static void Main(string[] a)
        {
            Random random = new Random();
            List<int> list1 = new List<int>(); //source list
            List<int> list2 = new List<int>();
            list2 = random.SequenceWhile((i) =>
                 {
                     if (list2.Contains(i))
                     {
                         return false;
                     }
                     list2.Add(i);
                     return true;
                 },
                 () => list2.Count == list1.Count,
                 list1.Count).ToList();

        }
    }
    public static class RandomExtensions
    {
        public static IEnumerable<int> SequenceWhile(
            this Random random, 
            Func<int, bool> shouldSkip, 
            Func<bool> continuationCondition,
            int maxValue)
        {
            int current = random.Next(maxValue);
            while (continuationCondition())
            {
                if (!shouldSkip(current))
                {
                    yield return current;
                }
                current = random.Next(maxValue);
            }
        }
    }
}
const int MaxItemsToShuffle = 20;
public static IEnumerable<int> RandomIndexes(int count)
{
    Random random = new Random();

    int indexCount = Math.Min(count, MaxItemsToShuffle);
    int[] indexes = new int[indexCount];

    if (count > MaxItemsToShuffle)
    {
        int cur = 0, subsetCount = MaxItemsToShuffle;
        for (int i = 0; i < count; i += 1)
        {
            if (random.NextDouble() <= ((float)subsetCount / (float)(count - i + 1)))
            {
                indexes[cur] = i;
                cur += 1;
                subsetCount -= 1;
            }
        }
    }
    else
    {
        for (int i = 0; i < count; i += 1)
        {
            indexes[i] = i;
        }
    }

    for (int i = indexCount; i > 0; i -= 1)
    {
        int curIndex = random.Next(0, i);
        yield return indexes[curIndex];

        indexes[curIndex] = indexes[i - 1];
    }
}