C# :: Aufgabe #129

4 Lösungen Lösungen öffentlich

Programmierung eines SleepSorter

Fortgeschrittener - C# von hollst - 09.06.2016 um 15:33 Uhr
Zum Sortieren irgendwelcher Objekte existieren unzählige Algorithmen, immer mit dem Ziel, das Sortieren möglichst schnell hinzubekommen, denn bei großen Datenmengen kann das Sortieren etliche Zeit beanspruchen. Eine recht originelle Art eines Sortierers stellt der sogenannte SleepSorter dar, allerdings ist er in der Regel kaum praxistauglich. Sein Vorteil besteht jedoch darin, dass man von vornherein fast genau weiß, wie lange der Sortiervorgang dauern wird, egal, wie vielen Objekte zu sortieren sind.

So funktioniert der SleepSorter: Jedem zu sortierenden Element wird ein eigener Thread zugeordnet. Nachdem das geschehen ist, werden alle Threads gleichzeitig gestartet. Die Threads haben keine großartige Rechenleistung zu erbringen, im Gegenteil, sie sind sofort in den Schlaf zu versetzen. Wie lange sie zu schlafen haben, muss ihnen bei der Initialisierung mitgegeben werden, und zwar genau so lange, wie es dem Wert des zu sortierenden Elemets entspricht, d. h. eine Zeitdauer dazu proportional. Das ist alles. Die Threads werden nach dem gemeinsamen Schlafengehen in aufsteigender Folge wieder erwachen und man muss dieses Erwachen lediglich sofort abfangen und den dem Thread jeweils zugeordneten Sortierwert z. B. in einer Liste hinterlegen. In dieser Liste sind die Elemente dann in sortierter Folge gespeichert.

Die Programmieraufgabe lautet so: Gegeben sei ein int-Array mit zufällig belegten Feldern, Wertebereich sei 0 ... 99. Die Länge des Arrays sei N (z. B. N = 1000). Das int-Array ist mit einem SleepSorter zu sortieren. Zusätzlich ist nach der Sortierung zu prüfen, ob auch tatsächlich richtig sortiert worden ist. Die Richtigkeit ist beim SleepSorter nämlich nicht garantiert, bspw. wenn zwei Sortierwerte eng beieinander liegen und der SleepSorter nicht von außen völlig abgeschottet ist.

Lösungen:

vote_ok
von J_U_B (650 Punkte) - 11.06.2016 um 08:12 Uhr
Ich habe ein bisschen getestet und habe für 1000 verschiedene Zahlen eine Laufzeit des SleepSort von ~ 9,9 Minuten (also 99*6000ms), dadurch ist zumindest in den meisten fällen ein Positives Ergebnis garantiert. Mit weniger Zeit war schon sehr früh zu erkennen, das der Sortiervorgang fehlerhaft veräuft.

Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Threading;

namespace TrainYourProgrammer
{
    static class Program
    {
        /// <summary>
        /// Die Länge des Array, dass mit Zahlen gefüllt wird.
        /// </summary>
        const int ArrayLength = 1000;

        /// <summary>
        /// Die Grund-Zeit mit der Gewartet werden soll.
        /// </summary>
        const int time = 6000;

        /// <summary>
        /// Die Liste für den SleepSort.
        /// </summary>
        static List<int> sortedList = new List<int>();

        /// <summary>
        /// Der Thread wartet "Zeit*Item", speichert die Zahl in einer neuen Liste ab und gibt sie aus.
        /// </summary>
        /// <param name="item">Die Zahl die Sortiert werden soll.</param>
        static void SleepSortThread(object item)
        {
            Thread.Sleep(time * (int)item);
            sortedList.Add((int)item);
            Console.WriteLine(item);
        }

        /// <summary>
        /// Der Sleepsorter öffnet fast Gleichzeitig so viele Threads, wie Zahlen im Array vorhanden. Dannach wartet er, bis alle Threads beendet sind.
        /// </summary>
        /// <param name="liste">Das Array der zu Sortierenden Zahlen.</param>
        static void SleepSorter(IEnumerable<int> liste)
        {
            List<Thread> threadList = new List<Thread>();
            foreach (var item in liste)
            {
                threadList.Add(new Thread(SleepSortThread));
                threadList[threadList.Count - 1].Start(item);
            }
            foreach (var item in threadList) item.Join();
        }

        /// <summary>
        /// Überprüft die Gleichheit zweier Listen Index für Index.
        /// </summary>
        /// <param name="iList1">Die erste Liste</param>
        /// <param name="iList2">Die zweite Liste</param>
        /// <returns>Gibt zurück ob die Listen gleich sind oder nicht.</returns>
        static bool CheckEquality(List<int> iList1, List<int> iList2)
        {
            if (iList1.Count != iList2.Count) return false;

            for (int i = 0; i < iList1.Count; i++)
                if (iList1[i] != iList2[i]) return false;

            return true;
        }

        static void Main()
        {
            Console.WriteLine("Ein Array mit {0} zufälligen Zahlen im Wertebereich von 0 bis 99 wird angelegt.", ArrayLength);
            // Es wird zuerst die Liste mit [ArrayLength] Zahlen im Wertebereich von 0 bis 99 angelegt
            Random r = new Random();
            List<int> iList = new List<int>();
            for (int i = 0; i < ArrayLength; i++)
                iList.Add(r.Next(0, 100));
            // Eine kurze Pause vor dem Sortieren um die Anzeige für den User zu verschönern
            Thread.Sleep(800);
            Console.WriteLine("Nun beginnt das Sortieren:");
            Thread.Sleep(400);
            // Sortiervorgang
            SleepSorter(iList);
            // Ein schnellerer Sortiervorgang schon von List<T> bereitgestellt wird benutzt. Um die zwei Listen zu vergleichen.
            iList.Sort();
            if (CheckEquality(iList, sortedList)) Console.WriteLine("Das Sortieren war erfolgreich!");
            else Console.WriteLine("Das Sortieren war nicht erfolgreich!");

            Console.WriteLine("Drücken Sie eine beliebige Taste zum Beenden...");
            Console.ReadLine();
        }
    }
}
vote_ok
von daniel59 (4260 Punkte) - 17.06.2016 um 07:40 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Diagnostics;

namespace ConsoleSleepSorter
{
    class Program
    {
        static List<int> sleepSortedList;
        static Random rnd = new Random();
        static List<Thread> threads;
        static int accuracy;
        static void Main(string[] args)
        {
            Console.Write("Größe der Liste: ");
            int length = Convert.ToInt32(Console.ReadLine());
            Console.Write("Wertebereich untere Grenze: ");
            int from = Convert.ToInt32(Console.ReadLine());
            Console.Write("Wertebereich obere Grenze: ");
            int to = Convert.ToInt32(Console.ReadLine());
            Console.Write("Genauigkeit: ");
            accuracy = Convert.ToInt32(Console.ReadLine());

            List<int> randomList = new List<int>();
            for (int i = 0; i < length; i++)
            {
                randomList.Add(rnd.Next(from, to));
            }

            List<int> sortedList = randomList.OrderBy(x => x).ToList();

            int expectedTime = sortedList.Max() * accuracy;//in ms
            Console.WriteLine("Geschätzte Zeit: " + expectedTime + " ms\n");

            Stopwatch sw = new Stopwatch();
            sw.Start();
            Sort(randomList);
            while (!threads.TrueForAll(a => !a.IsAlive))//Warte solange bis alle Threads abgeschlossen sind
            { }
            int count = 0;
            for (int i = 0; i < sortedList.Count; i++)
            {
                if (sortedList[i] == sleepSortedList[i])
                {
                    Console.ForegroundColor = ConsoleColor.DarkGreen;
                    count++;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.DarkRed;
                }
                Console.WriteLine("{0}\t\t---\t\t{1}", sortedList[i], sleepSortedList[i]);
            }
            sw.Stop();
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("\nGeschätzte Zeit: " + expectedTime + " ms");
            Console.WriteLine("Benötigte Zeit: " + sw.ElapsedMilliseconds + " ms");
            Console.WriteLine("Übereinstimmungen: {0}/{1}", count, sortedList.Count);

            Console.ReadLine();
        }

        static void Sort(IEnumerable<int> source)
        {
            sleepSortedList = new List<int>();
            threads = new List<Thread>();
            foreach (int i in source)
            {
                Thread sortingThread = new Thread(() => Sleep(i * accuracy));
                sortingThread.Start();
                threads.Add(sortingThread);
            }
        }

        static void Sleep(int duration)
        {
            Thread.Sleep(duration);
            lock (sleepSortedList)
            { sleepSortedList.Add(duration / accuracy); }
        }
    }
}
vote_ok
von Mexx (2370 Punkte) - 31.07.2016 um 23:30 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Threading;

namespace SleepSorter
{
    class Program
    {
        static int[] testarray = new int[] { 4, 1, 5, 8, 2, 34, 52, 1, 11, 17, 7 , 13, 1, 22, 31, 21, 1};
        static List<int> sortiert = new List<int>();

        static void Main(string[] args)
        {
            //Zu sortierende Einträge anlegen
            List<Sortieren> objects = new List<Sortieren>(testarray.Length);
            foreach (int entry in testarray)
            {
                objects.Add(new Sortieren(entry));
            }

            //Sortierung für jedes objekt starten
            foreach (Sortieren sort in objects)
            {
                sort.Start();
            }

            //Prüfen ob alle Threads ageschlossen sind
            bool running = true;
            while (running)
            {
                int count = 0;
                foreach (Sortieren sort in objects)
                {
                    if (!sort.thr.IsAlive)
                        count++;
                    if (count == testarray.Length)
                        running = false;
                }
            }

            foreach (int i in sortiert)
                Console.Write(i.ToString() + " ");
            Console.ReadKey();
        }

        public static void SaveValue(int value)
        {
            sortiert.Add(value);
        }
    }

    
    class Sortieren
    {
        public Thread thr { get; }
        delegate void GetValue(int value);
        event GetValue getValue;
        int value;

        public Sortieren(int value)
        {
            this.value = value;
            this.getValue += Program.SaveValue;
            this.thr = new Thread(Warten);
        }

        /// <summary>
        /// Thread starten
        /// </summary>
        public void Start()
        {
            this.thr.Start();
        }

        /// <summary>
        /// Entsprechend des Werts den Thread schlafen legen und beim erwachen den Wert per
        /// Delegat zurückgeben
        /// </summary>
        private void Warten()
        {
            Thread.Sleep(value * 50);
            if (getValue != null)
            {
                getValue(value);
            }
        }
    }
}
vote_ok
von hollst (13980 Punkte) - 08.09.2016 um 09:24 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Threading;

namespace sleep_sorting
{
    class Program
    {
        static StringBuilder sb = new StringBuilder();
        static Int32 counter = 0;
        static Int32 max = 100;
        static Random r = new Random();

        static void ThreadStart(object item)
        {            
            Thread.Sleep(500 * (int)item);
            counter++;
            sb.Append(item.ToString() + " ");
            Console.WriteLine(item + " " + counter.ToString());
            if(counter == max)
                Console.WriteLine("fertig");
        }

        static void SleepSort(IEnumerable<int> items)
        {
            foreach (var item in items)
            {
                new Thread(ThreadStart).Start(item);
            }
        }

        private static readonly object syncLock = new object();

        static void Main()
        {
            
            String[] s = new String[max];
            for (var i = 0; i < max; i++)
                s[i] = ((Int32)r.Next(100)).ToString();

            lock (syncLock)
            {
                SleepSort(s.Select(int.Parse));
            }
                                                          
            Console.ReadKey();
            Console.WriteLine(sb.ToString());
            Console.ReadKey();
        }
    }
}
2121064

Du scheinst einen AdBlocker zu nutzen. Ich würde mich freuen, wenn du ihn auf dieser Seite deaktivierst und dich davon überzeugst, dass die Werbung hier nicht störend ist.