Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/11: Рейтинг темы: голосов - 11, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 25.06.2019
Сообщений: 5

Проблема с архитектурным решением

25.06.2019, 11:56. Показов 2135. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем доброго дня.
Одолел меня проектный кретинизм. Не могу сообразить как лучше спроектировать приложение.
Может есть тут светлые головы, которые подскажут как лучше реализовать.
И так к сути. Дано:
Есть очередь заданий с приоритетами.
Задания 3 видов: Полное обновление (full), частичное обновление(part), и обновление сущности (incr).
incr - основная работа, выполняется многопоточно, по мере поступления заданий (fulltime)
full - должно выполняться в однопоточном режиме, при этом должно остановить запуск остальных заданий (incr и part). задание поступает раз в неделю.
part - должно выполняться в однопоточном режиме, при этом должно остановить запуск остальных заданий (incr и full ). задание поступает раз в сутки.


Обработку incr реализовал через Dataflow.ActionBlock.
Как прикрутить грамотно full и part без костылей мне пока не понятно.

Если подскажите в строну какого паттерна смотреть с вероятной реализацией, буду безмерно благодарен.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
25.06.2019, 11:56
Ответы с готовыми решениями:

Проблема с решением системы уравнений
Маткад не хочет решать систему, если поставить все известные данные в виде обозначений. Если подставить их в качестве чисел, то всё...

Проблема с решением системы дифференциальных уравнений первого порядка методом Адамса
Здравствуйте, уважаемые форумчане. Прошу вашей помощи в решении задачи. Имеется такая система. Необходимо найти функцию z1 методом...

c++ c решением
Given an integer number N THAT IS NOT LESS THAN 2. OUTPUT THE SMALLEST NATURAL DIVISOR OF THE N (NOT INCLUDING 1) input 15 output 3 ...

8
 Аватар для Cupko
658 / 595 / 171
Регистрация: 17.07.2012
Сообщений: 1,682
Записей в блоге: 1
25.06.2019, 12:36
Сергей Аноним, в сторону готовых планировщиков уже глядели? Типа Hangfire.
1
0 / 0 / 0
Регистрация: 25.06.2019
Сообщений: 5
25.06.2019, 12:48  [ТС]
Нет, сейчас ознакомлюсь. Благодарю
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
25.06.2019, 14:20
Сергей Аноним, не полностью понятно по поводу приоритетов.
Допустим, в данный момент максимальное количество потоков одновременно обрабатывают несколько incr, при этом в очереди висит еще несколько incr, ожидая своей очереди на обработку, т.к. все рабочие потоки заняты.
В этот момент прилетает full или part. Что происходит дальше?
Сначала обрабатываются висящие в начале очереди incr или full/part прыгает в начало очереди?
Если второе, то что делается с теми incr, которые уже были в очереди на момент поступления full/part? Они выбрасываются или обрабатываются потом, по окончании обработки full/part?
Если выбрасываются, то какой приоритет у full и part относительно друг друга?
0
0 / 0 / 0
Регистрация: 25.06.2019
Сообщений: 5
25.06.2019, 14:33  [ТС]
Обработка заданий идет по приоритету (от большего к меньшему), в порядке поступления в очередь.
Т.е. incr может иметь больший приоритет чем full, и должен отработать раньше.
Full и part должны дождаться обработки текущих incr.
После обработки задания full или part запрашивается следующее задание.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
25.06.2019, 15:13
Цитата Сообщение от Сергей Аноним Посмотреть сообщение
Full и part должны дождаться обработки текущих incr.
Если во время ожидания окончания обработки текущих incr в очередь прилетает новый incr с более высоким приоритетом, чем у full или part, которые ожидают окончания, то взятое из очереди и ждущее full/part возвращается в очередь или ожидание завершения текущих incr можно считать частью обработки full/part?
0
0 / 0 / 0
Регистрация: 25.06.2019
Сообщений: 5
25.06.2019, 15:32  [ТС]
Приоритет учитывается только при выборке из очереди.
Далее задание запускается в работу. С incr все просто, просто добавить в Dataflow.ActionBlock.
А вот с full и part сложнее, нужно дождаться и отработки ActionBlock и не запустить новые
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
25.06.2019, 16:29
Лучший ответ Сообщение было отмечено Сергей Аноним как решение

Решение

Сергей Аноним, если я правильно понимаю, то у вас где-то крутится поток, который вытягивает элементы из приоритетной очереди и добавляет их в ActionBlock.
Если это так, то вам надо при вытягивании full или part уведомить блок о завершении, дождаться этого завершения и выполнить работу в том же потоке. После чего тянуть следующий элемент и если он окажется incr, то создать заново блок.

Как-то так, если предположить что метод ProcessQueue у вас обрабатывает очередь и очередь представлена классом BlockingCollection с приоритетной очередью как деталью реализации:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private static void ProcessQueue(object arg)
{
    var (queue, token) = (ValueTuple<BlockingCollection<KeyValuePair<int, WorkItem>>, CancellationToken>)arg;
 
    var executorOptions = new ExecutionDataflowBlockOptions
    {
        BoundedCapacity = Environment.ProcessorCount,
        MaxDegreeOfParallelism = Environment.ProcessorCount,
        CancellationToken = token,
        SingleProducerConstrained = true
    };
    ActionBlock<WorkItem> executor = null;
 
    try { Consume(); }
    catch (OperationCanceledException)
    when (token.IsCancellationRequested) { return; }
 
    void Consume()
    {
        foreach (var item in queue.GetConsumingEnumerable(token))
        {
            switch (item.Value)
            {
                case IncrementalWorkItem incr:
                    if (executor == null)
                        executor = new ActionBlock<WorkItem>(workItem => workItem.DoWork(), executorOptions);
                    executor.SendAsync(incr).Wait();
                    break;
 
                case PartialWorkItem part:
                case FullWorkItem full:
                    if (executor != null)
                    {
                        executor.Complete();
                        executor.Completion.Wait();
                        executor = null;
                    }
 
                    item.Value.DoWork();
                    break;
            }
        }
    }
}
Полный пример:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks.Dataflow;
 
internal class Program
{
    private static void Main(string[] args)
    {
        var queue = new BlockingCollection<KeyValuePair<int, WorkItem>>(new ConcurrentPriorityQueue<int, WorkItem>());
        var cancellationSource = new CancellationTokenSource();
        var workerThread = new Thread(ProcessQueue);
        workerThread.Start((queue, cancellationSource.Token));
 
        var key = ConsoleKey.NoName;
        int i = 0, p = 0, f = 0;
        var rand = new Random();
        while (key != ConsoleKey.Escape)
        {
            switch (key = Console.ReadKey(true).Key)
            {
                case ConsoleKey.I:
                    queue.Add(rand.Next(2, 10), new IncrementalWorkItem($"incr {++i}"));
                    break;
 
                case ConsoleKey.P:
                    queue.Add(1, new PartialWorkItem($"part {++p}"));
                    break;
 
                case ConsoleKey.F:
                    queue.Add(0, new FullWorkItem($"full {++f}"));
                    break;
            }
        }
 
        cancellationSource.Cancel();
        workerThread.Join();
    }
 
    private static void ProcessQueue(object arg)
    {
        var (queue, token) = (ValueTuple<BlockingCollection<KeyValuePair<int, WorkItem>>, CancellationToken>)arg;
 
        var executorOptions = new ExecutionDataflowBlockOptions
        {
            BoundedCapacity = Environment.ProcessorCount,
            MaxDegreeOfParallelism = Environment.ProcessorCount,
            CancellationToken = token,
            SingleProducerConstrained = true
        };
        ActionBlock<WorkItem> executor = null;
 
        try { Consume(); }
        catch (OperationCanceledException)
        when (token.IsCancellationRequested) { return; }
 
        void Consume()
        {
            foreach (var item in queue.GetConsumingEnumerable(token))
            {
                switch (item.Value)
                {
                    case IncrementalWorkItem incr:
                        if (executor == null)
                            executor = new ActionBlock<WorkItem>(workItem => workItem.DoWork(), executorOptions);
                        executor.SendAsync(incr).Wait();
                        break;
 
                    case PartialWorkItem part:
                    case FullWorkItem full:
                        if (executor != null)
                        {
                            executor.Complete();
                            executor.Completion.Wait();
                            executor = null;
                        }
 
                        item.Value.DoWork();
                        break;
                }
            }
        }
    }
}
 
internal abstract class WorkItem
{
    public string Name { get; }
 
    public WorkItem(string name) => Name = name;
 
    public void DoWork()
    {
        Console.WriteLine($"Starting work on {Name}");
        Thread.Sleep(Delay);
        Console.WriteLine($"Finished work on {Name}");
    }
 
    protected abstract TimeSpan Delay { get; }
}
 
internal sealed class IncrementalWorkItem : WorkItem
{
    public IncrementalWorkItem(string name) : base(name)
    {
    }
 
    protected override TimeSpan Delay => TimeSpan.FromSeconds(3);
}
 
internal sealed class PartialWorkItem : WorkItem
{
    public PartialWorkItem(string name) : base(name)
    {
    }
 
    protected override TimeSpan Delay => TimeSpan.FromSeconds(5);
}
 
internal sealed class FullWorkItem : WorkItem
{
    public FullWorkItem(string name) : base(name)
    {
 
    }
 
    protected override TimeSpan Delay => TimeSpan.FromSeconds(10);
}
 
internal static class CollectionExtensions
{
    public static void Add<TKey, TValue>(this BlockingCollection<KeyValuePair<TKey, TValue>> queue, TKey key, TValue value)
    => queue.Add(new KeyValuePair<TKey, TValue>(key, value));
}


Клавишами I, P, F добавляются соответствующие элементы в очередь.

Реализация потокобезопасной приоритетной очереди взята из пакета ParallelExtensionsExtra
ConcurrentPriorityQueue
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
//--------------------------------------------------------------------------
// 
//  Copyright (c) Microsoft Corporation.  All rights reserved. 
// 
//  File: ConcurrentPriorityQueue.cs
//
//--------------------------------------------------------------------------
 
using System.Collections.Generic;
using System.Diagnostics;
 
namespace System.Collections.Concurrent
{
    /// <summary>Provides a thread-safe priority queue data structure.</summary>
    /// <typeparam name="TKey">Specifies the type of keys used to prioritize values.</typeparam>
    /// <typeparam name="TValue">Specifies the type of elements in the queue.</typeparam>
    [DebuggerDisplay("Count={Count}")]
    public class ConcurrentPriorityQueue<TKey, TValue> :
        IProducerConsumerCollection<KeyValuePair<TKey, TValue>>
        where TKey : IComparable<TKey>
    {
        private readonly object _syncLock = new object();
        private readonly MinBinaryHeap _minHeap = new MinBinaryHeap();
 
        /// <summary>Initializes a new instance of the ConcurrentPriorityQueue class.</summary>
        public ConcurrentPriorityQueue() { }
 
        /// <summary>Initializes a new instance of the ConcurrentPriorityQueue class that contains elements copied from the specified collection.</summary>
        /// <param name="collection">The collection whose elements are copied to the new ConcurrentPriorityQueue.</param>
        public ConcurrentPriorityQueue(IEnumerable<KeyValuePair<TKey, TValue>> collection)
        {
            if (collection == null) throw new ArgumentNullException("collection");
            foreach (var item in collection) _minHeap.Insert(item);
        }
 
        /// <summary>Adds the key/value pair to the priority queue.</summary>
        /// <param name="priority">The priority of the item to be added.</param>
        /// <param name="value">The item to be added.</param>
        public void Enqueue(TKey priority, TValue value)
        {
            Enqueue(new KeyValuePair<TKey, TValue>(priority, value));
        }
 
        /// <summary>Adds the key/value pair to the priority queue.</summary>
        /// <param name="item">The key/value pair to be added to the queue.</param>
        public void Enqueue(KeyValuePair<TKey, TValue> item)
        {
            lock (_syncLock) _minHeap.Insert(item);
        }
 
        /// <summary>Attempts to remove and return the next prioritized item in the queue.</summary>
        /// <param name="result">
        /// When this method returns, if the operation was successful, result contains the object removed. If
        /// no object was available to be removed, the value is unspecified.
        /// </param>
        /// <returns>
        /// true if an element was removed and returned from the queue succesfully; otherwise, false.
        /// </returns>
        public bool TryDequeue(out KeyValuePair<TKey, TValue> result)
        {
            result = default(KeyValuePair<TKey, TValue>);
            lock (_syncLock)
            {
                if (_minHeap.Count > 0)
                {
                    result = _minHeap.Remove();
                    return true;
                }
            }
            return false;
        }
 
        /// <summary>Attempts to return the next prioritized item in the queue.</summary>
        /// <param name="result">
        /// When this method returns, if the operation was successful, result contains the object.
        /// The queue was not modified by the operation.
        /// </param>
        /// <returns>
        /// true if an element was returned from the queue succesfully; otherwise, false.
        /// </returns>
        public bool TryPeek(out KeyValuePair<TKey, TValue> result)
        {
            result = default(KeyValuePair<TKey, TValue>);
            lock (_syncLock)
            {
                if (_minHeap.Count > 0)
                {
                    result = _minHeap.Peek();
                    return true;
                }
            }
            return false;
        }
 
        /// <summary>Empties the queue.</summary>
        public void Clear() { lock (_syncLock) _minHeap.Clear(); }
 
        /// <summary>Gets whether the queue is empty.</summary>
        public bool IsEmpty { get { return Count == 0; } }
 
        /// <summary>Gets the number of elements contained in the queue.</summary>
        public int Count
        {
            get { lock (_syncLock) return _minHeap.Count; }
        }
 
        /// <summary>Copies the elements of the collection to an array, starting at a particular array index.</summary>
        /// <param name="array">
        /// The one-dimensional array that is the destination of the elements copied from the queue.
        /// </param>
        /// <param name="index">
        /// The zero-based index in array at which copying begins.
        /// </param>
        /// <remarks>The elements will not be copied to the array in any guaranteed order.</remarks>
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
        {
            lock (_syncLock) _minHeap.Items.CopyTo(array, index);
        }
 
        /// <summary>Copies the elements stored in the queue to a new array.</summary>
        /// <returns>A new array containing a snapshot of elements copied from the queue.</returns>
        public KeyValuePair<TKey, TValue>[] ToArray()
        {
            lock (_syncLock)
            {
                var clonedHeap = new MinBinaryHeap(_minHeap);
                var result = new KeyValuePair<TKey, TValue>[_minHeap.Count];
                for (int i = 0; i < result.Length; i++)
                {
                    result[i] = clonedHeap.Remove();
                }
                return result;
            }
        }
 
        /// <summary>Attempts to add an item in the queue.</summary>
        /// <param name="item">The key/value pair to be added.</param>
        /// <returns>
        /// true if the pair was added; otherwise, false.
        /// </returns>
        bool IProducerConsumerCollection<KeyValuePair<TKey, TValue>>.TryAdd(KeyValuePair<TKey, TValue> item)
        {
            Enqueue(item);
            return true;
        }
 
        /// <summary>Attempts to remove and return the next prioritized item in the queue.</summary>
        /// <param name="item">
        /// When this method returns, if the operation was successful, result contains the object removed. If
        /// no object was available to be removed, the value is unspecified.
        /// </param>
        /// <returns>
        /// true if an element was removed and returned from the queue succesfully; otherwise, false.
        /// </returns>
        bool IProducerConsumerCollection<KeyValuePair<TKey, TValue>>.TryTake(out KeyValuePair<TKey, TValue> item)
        {
            return TryDequeue(out item);
        }
 
        /// <summary>Returns an enumerator that iterates through the collection.</summary>
        /// <returns>An enumerator for the contents of the queue.</returns>
        /// <remarks>
        /// The enumeration represents a moment-in-time snapshot of the contents of the queue. It does not
        /// reflect any updates to the collection after GetEnumerator was called. The enumerator is safe to
        /// use concurrently with reads from and writes to the queue.
        /// </remarks>
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            var arr = ToArray();
            return ((IEnumerable<KeyValuePair<TKey, TValue>>)arr).GetEnumerator();
        }
 
        /// <summary>Returns an enumerator that iterates through a collection.</summary>
        /// <returns>An IEnumerator that can be used to iterate through the collection.</returns>
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
 
        /// <summary>Copies the elements of the collection to an array, starting at a particular array index.</summary>
        /// <param name="array">
        /// The one-dimensional array that is the destination of the elements copied from the queue.
        /// </param>
        /// <param name="index">
        /// The zero-based index in array at which copying begins.
        /// </param>
        void ICollection.CopyTo(Array array, int index)
        {
            lock (_syncLock) ((ICollection)_minHeap.Items).CopyTo(array, index);
        }
 
        /// <summary>
        /// Gets a value indicating whether access to the ICollection is synchronized with the SyncRoot.
        /// </summary>
        bool ICollection.IsSynchronized { get { return true; } }
 
        /// <summary>
        /// Gets an object that can be used to synchronize access to the collection.
        /// </summary>
        object ICollection.SyncRoot { get { return _syncLock; } }
 
        /// <summary>Implements a binary heap that prioritizes smaller values.</summary>
        private sealed class MinBinaryHeap
        {
            private readonly List<KeyValuePair<TKey, TValue>> _items;
 
            /// <summary>Initializes an empty heap.</summary>
            public MinBinaryHeap()
            {
                _items = new List<KeyValuePair<TKey, TValue>>();
            }
 
            /// <summary>Initializes a heap as a copy of another heap instance.</summary>
            /// <param name="heapToCopy">The heap to copy.</param>
            /// <remarks>Key/Value values are not deep cloned.</remarks>
            public MinBinaryHeap(MinBinaryHeap heapToCopy)
            {
                _items = new List<KeyValuePair<TKey, TValue>>(heapToCopy.Items);
            }
 
            /// <summary>Empties the heap.</summary>
            public void Clear() { _items.Clear(); }
 
            /// <summary>Adds an item to the heap.</summary>
            public void Insert(TKey key, TValue value)
            {
                // Create the entry based on the provided key and value
                Insert(new KeyValuePair<TKey, TValue>(key, value));
            }
 
            /// <summary>Adds an item to the heap.</summary>
            public void Insert(KeyValuePair<TKey, TValue> entry)
            {
                // Add the item to the list, making sure to keep track of where it was added.
                _items.Add(entry);
                int pos = _items.Count - 1;
 
                // If the new item is the only item, we're done.
                if (pos == 0) return;
 
                // Otherwise, perform log(n) operations, walking up the tree, swapping
                // where necessary based on key values
                while (pos > 0)
                {
                    // Get the next position to check
                    int nextPos = (pos - 1) / 2;
 
                    // Extract the entry at the next position
                    var toCheck = _items[nextPos];
 
                    // Compare that entry to our new one.  If our entry has a smaller key, move it up.
                    // Otherwise, we're done.
                    if (entry.Key.CompareTo(toCheck.Key) < 0)
                    {
                        _items[pos] = toCheck;
                        pos = nextPos;
                    }
                    else break;
                }
 
                // Make sure we put this entry back in, just in case
                _items[pos] = entry;
            }
 
            /// <summary>Returns the entry at the top of the heap.</summary>
            public KeyValuePair<TKey, TValue> Peek()
            {
                // Returns the first item
                if (_items.Count == 0) throw new InvalidOperationException("The heap is empty.");
                return _items[0];
            }
 
            /// <summary>Removes the entry at the top of the heap.</summary>
            public KeyValuePair<TKey, TValue> Remove()
            {
                // Get the first item and save it for later (this is what will be returned).
                if (_items.Count == 0) throw new InvalidOperationException("The heap is empty.");
                KeyValuePair<TKey, TValue> toReturn = _items[0];
 
                // Remove the first item if there will only be 0 or 1 items left after doing so.  
                if (_items.Count <= 2) _items.RemoveAt(0);
                // A reheapify will be required for the removal
                else
                {
                    // Remove the first item and move the last item to the front.
                    _items[0] = _items[_items.Count - 1];
                    _items.RemoveAt(_items.Count - 1);
 
                    // Start reheapify
                    int current = 0, possibleSwap = 0;
 
                    // Keep going until the tree is a heap
                    while (true)
                    {
                        // Get the positions of the node's children
                        int leftChildPos = 2 * current + 1;
                        int rightChildPos = leftChildPos + 1;
 
                        // Should we swap with the left child?
                        if (leftChildPos < _items.Count)
                        {
                            // Get the two entries to compare (node and its left child)
                            var entry1 = _items[current];
                            var entry2 = _items[leftChildPos];
 
                            // If the child has a lower key than the parent, set that as a possible swap
                            if (entry2.Key.CompareTo(entry1.Key) < 0) possibleSwap = leftChildPos;
                        }
                        else break; // if can't swap this, we're done
 
                        // Should we swap with the right child?  Note that now we check with the possible swap
                        // position (which might be current and might be left child).
                        if (rightChildPos < _items.Count)
                        {
                            // Get the two entries to compare (node and its left child)
                            var entry1 = _items[possibleSwap];
                            var entry2 = _items[rightChildPos];
 
                            // If the child has a lower key than the parent, set that as a possible swap
                            if (entry2.Key.CompareTo(entry1.Key) < 0) possibleSwap = rightChildPos;
                        }
 
                        // Now swap current and possible swap if necessary
                        if (current != possibleSwap)
                        {
                            var temp = _items[current];
                            _items[current] = _items[possibleSwap];
                            _items[possibleSwap] = temp;
                        }
                        else break; // if nothing to swap, we're done
 
                        // Update current to the location of the swap
                        current = possibleSwap;
                    }
                }
 
                // Return the item from the heap
                return toReturn;
            }
 
            /// <summary>Gets the number of objects stored in the heap.</summary>
            public int Count { get { return _items.Count; } }
 
            internal List<KeyValuePair<TKey, TValue>> Items { get { return _items; } }
        }
    }
}
1
0 / 0 / 0
Регистрация: 25.06.2019
Сообщений: 5
25.06.2019, 17:45  [ТС]
Огромнейшее спасибо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
25.06.2019, 17:45
Помогаю со студенческими работами здесь

Подскажите с решением
Многие знают, что ответ на главный вопрос жизни, вселенной и всего такого — 42. Но Вася хочет большего! Он желает знать квадрат этого...

помогите с решением
написать программу составления пятиугольника с вершинами вершинами (100,100), (150,100), (170,120), (150,140), (100,100). Закрасить поле с...

Подскажите с решением.
Задача на Паскаль. Дана непустая последовательность из строчных букв, между соседними словами запятая, за последним словом - точка....

Загвоздка с решением.
Сформировать массив, содержащий сведения о количестве изделий категорий A, B, C, собранных рабочим за месяц. Комбинированный тип содержит...

помгите с решением
помогите пожалусто решить написать программу которая генерирует три последовотельности из 5 случайных чисел в диопозоне от 5 до 10...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru