Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.64/25: Рейтинг темы: голосов - 25, средняя оценка - 4.64
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22

Односвязный кольцевой список [code review]

23.07.2018, 13:17. Показов 5178. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
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
/*
    Операции:
    - Поиск элемента по индексу
    - Вставка в начало/конец
    - Вставка перед/после элемента x
    - Удаление первого/последнего элемента
    - Удаление элемента перед/после x
    - Удаление целевого элемента
*/
 
using System;
 
namespace Examples.Collections.Generic
{
    //Односвязный кольцевой список.
    public class CycledLinkedList<T> : IPrintable
    {
        #region PrivateSection
        private void TryThrowInvalidOperationException()
        {
            if (Count == 0)
            {
                throw new InvalidOperationException("Односвязный кольцевой список пуст");
            }
        }
 
        private void TryThrowArgumentException(Node<T> target)
        {
            if (target == Head)
            {
                throw new ArgumentException(Helper.InvalidTarget);
            }
        }
 
        private bool FindHelper(int count, Node<T> node, T value)
        {
            return ((count < 2) && !node.Value.Equals(value));
        }
 
        private Node<T> Find(T value)
        {
            int count = 0;
            Node<T> current = Head;
            while (FindHelper(count, current, value))
            {
                if (current == Head)
                {
                    count++;
                }
                current = current.Next;
            }
            if (count == 2)
            {
                TryThrowArgumentException(Head);
            }
            return current;
        }
 
        private void Move(ref Node<T> first, ref Node<T> second)
        {
            first = second;
            second = second.Next;
        }
 
        private Node<T> FindPrevious(T value)
        {
            int count = 0;
            Node<T> previous = Tail;
            Node<T> current = Head;
            while (FindHelper(count, current, value))
            {
                if (current == Head)
                {
                    count++;
                }
                Move(ref previous, ref current);
            }
            if (count == 2)
            {
                TryThrowArgumentException(Head);
            }
            return previous;
        }
 
        private void AddAfter(Node<T> target, T value)
        {
            Node<T> node = new Node<T>(value, target.Next);
            target.Next = node;
        }
        #endregion PrivateSection
 
        #region PublicSection
        #region PublicSection.Properties.Owner
        public Node<T> Head { get; private set; }
        public Node<T> Tail { get; private set; }
        public int Count { get; private set; }
        #endregion PublicSection.Properties.Owner
 
        #region PublicSection.Methods
        #region PublicSection.Methods.InterfaceImplementations.IPrintable
        public void Print() => Console.Write(ToString());
 
        public void Println() => Console.WriteLine(ToString());
        #endregion PublicSection.Methods.InterfaceImplementations.IPrintable
 
        #region PublicSection.Methods.UserOperations
        public void AddFirst(T value)
        {
            Node<T> node = new Node<T>(value, Head);
            if (Count == 0)
            {
                Tail = node;
            }
            Head = node;
            Tail.Next = node;
            Count++;
        }
 
        public void AddLast(T value)
        {
            Node<T> node = new Node<T>(value, Head);
            if (Count == 0)
            {
                Head = node;
                Head.Next = node;
            }
            else
            {
                Tail.Next = node;
            }
            Tail = node;
            Count++;
        }
 
        public void AddBefore(T target, T value)
        {
            Node<T> previous = FindPrevious(target);
            AddAfter(previous, value);
            if (previous.Next.Next == Head)
            {
                Head = previous.Next;
            }
            Count++;
        }
 
        public void AddAfter(T target, T value)
        {
            Node<T> current = Find(target);
            AddAfter(current, value);
            if (current == Tail)
            {
                Tail = current.Next;
            }
            Count++;
        }
 
        public void RemoveFirst()
        {
            TryThrowInvalidOperationException();
            if (Count == 1)
            {
                Clear();
            }
            else
            {
                Head = Head.Next;
                Tail.Next = Head;
                Count--;
            }
        }
 
        public void RemoveLast()
        {
            TryThrowInvalidOperationException();
            if (Count == 1)
            {
                Clear();
            }
            else
            {
                Node<T> previous = Head.Next;
                while (previous.Next != Tail)
                {
                    previous = previous.Next;
                }
                previous.Next = Head;
                Tail = previous;
                Count--;
            }
        }
 
        public void RemoveBefore(T value)
        {
            TryThrowInvalidOperationException();
            if (Count < 2)
            {
                TryThrowArgumentException(Head);
            }
            Node<T> previous = Tail;
            while ((previous.Next.Next != Head) && !previous.Next.Next.Value.Equals(value))
            {
                previous = previous.Next;
            }
            TryThrowArgumentException(previous.Next.Next);
            if (previous.Next == Head)
            {
                Head = previous.Next.Next;
            }
            previous.Next = previous.Next.Next;
            Count--;
        }
 
        public void RemoveAt(T value)
        {
            TryThrowInvalidOperationException();
            if ((Count == 1) && Head.Value.Equals(value))
            {
                Clear();
            }
            else
            {
                Node<T> previous = FindPrevious(value);
                if (previous.Next == Head)
                {
                    Head = previous.Next.Next;
                }
                else if (previous.Next == Tail)
                {
                    Tail = previous;
                }
                previous.Next = previous.Next.Next;
                Count--;
            }
        }
 
        public void RemoveAfter(T value)
        {
            TryThrowInvalidOperationException();
            Node<T> previous = Find(value);
            TryThrowArgumentException(previous.Next);
            if (previous.Next == Tail)
            {
                Tail = previous;
            }
            previous.Next = previous.Next.Next;
            Count--;
        }
 
        public void Clear()
        {
            Head = null;
            Tail = null;
            Count = 0;
        }
 
        public override string ToString()
        {
            Node<T> current = Head;
            string result = $"CycledLinkedList[{typeof(CycledLinkedList<T>).GetGenericArguments()[0]}]: [";
            do
            {
                result += current + (current.Next != Head ? Helper.Delimiter : "");
                current = current.Next;
            }
            while (current != Head);
            result += ']';
            return result;
        }
        #endregion PublicSection.Methods.UserOperations
        #endregion PublicSection.Methods
        #endregion PublicSection
    }
}
, где IPrintable:
C#
1
2
3
4
5
6
7
8
namespace Examples
{
    public interface IPrintable
    {
        void Print();
        void Println();
    }
}
, где Helper:
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
using Examples.Collections.Generic;
 
namespace Examples
{
    //Вспомогательный класс.
    public static class Helper
    {
        #region PublicSection.Constants.Owner
        public const string Delimiter = ", ";
        public const int MaxSize = 32;
        public const string InvalidTarget = "Опорный узел, требуемый для выполнения данной операции не найден";
        #endregion PublicSection.Constants.Owner
 
        #region PublicSection.Methods.UserOperations
        public static void Swap<T>(ref T x, ref T y)
        {
            var z = x;
            x = y;
            y = z;
        }
 
        public static string ToString<T>(T[] target, int count)
        {
            string result = "[";
            for(var i = 0; i < count; i++)
            {
                result += target[i] + (i + 1 < count ? Delimiter : "");
            }
            result += ']';
            return result;
        }
 
        public static string ToString<T>(Node<T> head)
        {
            Node<T> current = head;
            string result = "[";
            while (current != null)
            {
                result += current + (current.Next != null ? Delimiter : "");
                current = current.Next;
            }
            result += ']';
            return result;
        }
 
        public static string ToString<T>(Node2<T> head)
        {
            Node2<T> current = head;
            string result = "[";
            while (current != null)
            {
                result += current + (current.Next != null ? Delimiter : "");
                current = current.Next;
            }
            result += ']';
            return result;
        }
        #endregion PublicSection.Methods.UserOperations
    }
}
Насколько адекватная реализация данной структуры данных с точки зрения оформления кода, его структуризации и подхода к реализации?

Добавлено через 7 минут
И вот еще ICloneableAs<T>:
C#
1
2
3
4
5
6
7
8
9
using System;
 
namespace Examples
{
    public interface ICloneableAs<T> : ICloneable
    {
        T CloneAs();
    }
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
23.07.2018, 13:17
Ответы с готовыми решениями:

Двусвязный линейный список [code review]
/* Операции: - Поиск элемента по индексу - Вставка в начало/конец - Вставка перед/после элемента x - Удаление...

[Code review] ООП ошибки
Здравствуйте! Есть программа и она рабочая. И мне для дальнейшего программирования необходимо знать насколько она правильно, оптимально и...

[Code review] Алгоритм Брезенхема для линии
/* * Created by SharpDevelop. * User: 26-60-911 * Date: 13.08.2017 * Time: 20:58 * * To change this template use Tools |...

16
 Аватар для Wolflind
127 / 107 / 31
Регистрация: 17.03.2016
Сообщений: 445
Записей в блоге: 1
23.07.2018, 13:19
Скобок_много()
{
;
}
0
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 13:25  [ТС]
Wolflind, где-то читал, что рекомендуется использовать {} даже если после if идет один оператор. Это уже скорее стиль. Вот, нашёл, например:
C#
1
2
3
4
5
6
7
8
if ((divisor != 0) && (dividend / divisor > 0))
{
    Console.WriteLine("Quotient: {0}", dividend / divisor);
}
else
{
    Console.WriteLine("Attempted division by 0 ends up here.");
}
0
 Аватар для Wolflind
127 / 107 / 31
Регистрация: 17.03.2016
Сообщений: 445
Записей в блоге: 1
23.07.2018, 13:29
Volobuev Ilya, я не чего против скобок не имею кому как удобней
Цитата Сообщение от Volobuev Ilya Посмотреть сообщение
где-то читал, что рекомендуется использовать {} даже если после if идет один оператор.
если вспомните напишите интересно почитать
0
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 13:30  [ТС]
Wolflind, ссылочка вверху в посте 3. Явно не вижу, чтобы говорилось (может невнимательно смотрел), но думаю примера кода и так достаточно, он же от Microsoft, а не с левого сайта.
0
 Аватар для Wolflind
127 / 107 / 31
Регистрация: 17.03.2016
Сообщений: 445
Записей в блоге: 1
23.07.2018, 13:35
там для читабельности только как я понял
да и ниже сами же опускают скобки
C#
1
2
3
4
5
6
7
8
foreach (var ch in laugh)
{
    if (ch == 'h')
        Console.Write("H");
    else
        Console.Write(ch);
}
Console.WriteLine();
0
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 13:36  [ТС]
Wolflind, тогда вопрос остается спорным (использовать их или нет). Хотя, я привык использовать.
0
 Аватар для Wolflind
127 / 107 / 31
Регистрация: 17.03.2016
Сообщений: 445
Записей в блоге: 1
23.07.2018, 13:36
писал на питоне одно время поэтому от лишних скобок только в глазах рябит
0
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 13:38  [ТС]
Wolflind, отходя от темы, можно сказать, что и я этим страдал недавно.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
23.07.2018, 14:32
Лучший ответ Сообщение было отмечено Volobuev Ilya как решение

Решение

  • Есть несколько подозрительных мест — возможно, там присутствуют баги
  • Класс Node<T> не обязательно делать обобщенным, достаточно объявить его вложенным в дерево
  • Неплохо было бы на коллекции реализовать соответствующие интерфейсы (как минимум IEnumerable<T>)
  • Непонятно, почему методы ToString с параметром Node находятся в классе Helper, а не переопределены в классе Node
  • Непонятно, почему модификатор доступа у класса Helper — public, а не internal или private (вложенный)
  • Выражение CycledLinkedList[{typeof(CycledLinkedList<T>).GetGenericArguments()[0]}] несколько странно. Почему бы не использовать typeof(T)?
1
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 14:38  [ТС]
kolorotur, Node<T> используется в нескольких структурах данных, поэтому его вынес. А так, спасибо за информативный ответ.
0
 Аватар для Wolflind
127 / 107 / 31
Регистрация: 17.03.2016
Сообщений: 445
Записей в блоге: 1
23.07.2018, 14:43
Volobuev Ilya, а скобки все таки лишние
0
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 14:47  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Есть несколько подозрительных мест — возможно, там присутствуют баги
А можно поподробней?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
23.07.2018, 15:52
Лучший ответ Сообщение было отмечено Volobuev Ilya как решение

Решение

Цитата Сообщение от Volobuev Ilya Посмотреть сообщение
А можно поподробней?
Подробностей, скорее всего, не будет — при более детальном рассмотрении вроде все в порядке.
Просто местами код читать тяжеловато, через это некоторые вещи выглядят странно.

После более детального просмотра в копилку прибыло.
Что происходит с именами методов?!
  • TryThrowInvalidOperationException бросает исключение, если список пуст. Почему он называется не ThrowIfEmpty?
  • TryThrowArgumentException бросает исключение, если в него передали ссылку на Head. Почему он называется не ThrowIfHead?
  • Метод RemoveAt удаляет элемент с определенным значением. Почему он называется не просто Remove? RemoveAt обычно используется для удаления элемента с определенным порядковым номером.
  • Метод FindHelper — это исчадие ада. Дайте угадаю: вы его так назвали потому, что сами не смогли придумать ему осмысленное название?
    Его наличие объясняется только несколько странным алгоритмом поиска элемента, где вы пытаетесь определить момент полного обхода через счетчик количеств "натыкания" на головной элемент. Там это ни к чему: как только current.Next ссылается на Head — вы сделали полный обход.

    Как вам такой вариант Find?
    C#
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    private Node<T> Find(T value)
    {
        TryThrowInvalidOperationException();
     
        var curr = Head;
        do
        {
            if (curr.Value.Equals(value))
                return curr;
            curr = curr.Next;
        } while (curr != Head);
     
        throw new InvalidOperationException(Helper.InvalidTarget);
    }
    Метод FindPrevious будет выглядеть примерно так же, с незначительными дополнениями.
2
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 16:03  [ТС]
Метод FindHelper — это исчадие ада. Дайте угадаю: вы его так назвали потому, что сами не смогли придумать ему осмысленное название?
Вы определенно обладаете телепатией.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
23.07.2018, 16:11
Цитата Сообщение от Volobuev Ilya Посмотреть сообщение
Вы определенно обладаете телепатией.
Да бросьте — мы все через это прошли.
0
Alvin Seville
 Аватар для Соколиный глаз
343 / 273 / 134
Регистрация: 25.07.2014
Сообщений: 4,537
Записей в блоге: 22
23.07.2018, 16:21  [ТС]
Как вам такой вариант Find?
Отлично!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
23.07.2018, 16:21
Помогаю со студенческими работами здесь

[Code review] Сумма нечётных от первого числа до 2
Здравствуйте, подскажите пожалуйста данный код является корректным с точки зрения проф. программистов. using System; using...

Реализация списка на базе динамического массива [code review]
using System; namespace MyCollections.Generic { public class List&lt;T&gt; : IPrintable, ICloneableAs&lt;List&lt;T&gt;&gt; { private T content;...

[Code review] Даны два числа. Заменить большее число тройным произведением, меньшее - полусуммой
Вести два числа а и b. Число, которое больше заменить тройным произведением, число которое меньше заменить полусуммой. double a, b, a1,...

[Code review] Текстовый процессор, реализующий автодополнение слов по требованию пользователя
Всем привет. Недавно выполнял тестовое задание, по результату прислали: К сожалению, уровень владения языком C#, продемонстрированный...

[Code review] Дано натуральное число n, можно его представить в виде суммы трех квадратов натуральных чисел
Дано натуральное число n, можно его представить в виде суммы трех квадратов натуральных чисел. ЕСли можно,то указать тройку x^2+y^2+z^2=n....


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
1С: Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию группы. . .
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
1С: Программный отбор элементов справочника по значению перечисления
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит значение перечислений. / / Событие "НачалоВыбора" реквизита на форме. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru