The task of implementing a doubly linked list in c#
To the essence of the question: I implemented a doubly linked list, do not ask why, I know that there is such a list already in the generics. And everything seems to work) BUT, I send it to the test, where does the NullReferenceException error appear in the testing system? Where that is not exactly specified. The tri-kach blocks covered everything - nothing helped. Look who's interested in what's wrong? The class of the list item, although it is not important:
//элемент связанного списка
public class ListItem : IListItem
{
public ListItem prev { get; set; }
public ListItem next { get; set; }
private object _val;
public ListItem(object obj, IListItem prev = null)
{
if (obj!=null)
{
this._val = obj;
}
}
//предыдущий связанный элемент списка
public IListItem Prev()
{
try
{
return prev;
}
catch (Exception)
{
return new ListItem(999);
}
}
public void invalidate()
{
prev = null;
next = null;
_val = null;
}
//следующий связанный элемент списка
public IListItem Next()
{
try
{
return next;
}
catch (Exception)
{
return new ListItem(999);
}
}
//хранимое значение
public object Value { get {
if (_val != null)
{
return this._val;
}
else return null;
} }
}
Сам класс:
//прямой связанный список
public class LinkedList : ILinkedList
{
private ListItem head;
public int count;
public LinkedList()
{
count = 0;
}
//добавить элемент в начало
public void AddFirst(IListItem item)
{
if (item == null)
{
return;
}
if (head==null)
{
AddToEmtyist(item);
return;
}
ListItem newItem = (ListItem)item;
newItem.next = head;
newItem.prev = head.prev;
head.prev.next = newItem;
head.prev = newItem;
head = newItem;
count++;
}
//добавить элемент в конец
public void AddLast(IListItem item)
{
if (item == null)
{
return;
}
if (head == null)
{
AddToEmtyist(item);
return;
}
ListItem newItem = (ListItem)item;
newItem.next = head;
newItem.prev = head.prev;
head.prev.next = newItem;
head.prev = newItem;
count++;
}
private void AddToEmtyist(IListItem item)
{
try
{
ListItem newItem = (ListItem)item;
newItem.next = newItem;
newItem.prev = newItem;
head = newItem;
count++;
}
catch (Exception err)
{
throw;
}
}
//вставить элемент перед элементом с указанным индексом
//если элемента нет - вставить в конец
public void Insert(IListItem item, int index)
{
try
{
if (item==null)
{
return;
}
int i = 0;
ListItem replaceItem = head;
if (index > (count-1))
{
AddLast(item);
return;
}
if (index==0)
{
AddFirst(item);
}
while (index != i)
{
replaceItem = replaceItem.next;
i++;
}
ListItem newItem = (ListItem)item;
newItem.next = replaceItem;
newItem.prev = replaceItem.prev;
replaceItem.prev.next = newItem;
replaceItem.prev = newItem;
count++;
}
catch (Exception err)
{
}
}
//проверка есть ли эелементы в списке
public bool IsEmpty()
{
if (count > 0)
{
return false;
}
else return true;
}
//вернуть первый эелемент в списке
public IListItem GetFirstItem()
{
if (head != null)
{
return head;
}
else return null;
}
//вернуть все элементы списка, кроме первого
public IEnumerable<IListItem> GetAll()
{
if (count==0)
{
return null;
}
List<IListItem> rez = new List<IListItem>();
int cnt = 0;
ListItem currItem = head;
while (cnt != (count))
{
if (currItem!=head)
{
rez.Add(currItem);
}
currItem = currItem.next;
cnt++;
}
return rez;
}
//очистить список
public void Clear()
{
ListItem current =(ListItem)head;
while (current != null)
{
ListItem temp = current;
current = (ListItem)current.Next();
temp.invalidate();
}
head = null;
count = 0;
}
//сортировка списка в обратном порядке
public void Reverse()
{
ListItem node = head;
do
{
ListItem temp = node.next;
node.next = node.prev;
node.prev = temp;
node = node.prev;
if (temp == head)
{
break;
}
}
while (true);
head = head.next;
}
}
1 answers
It is easy to reproduce the problem
var l = new LinkedList();
foreach (var i in l.GetAll()) // l.GetAll() вернет null
{
}
Threw comments on the code
// Что не так:
public class ListItem : IListItem
{
public ListItem prev { get; set; }
public ListItem next { get; set; }
private object _val;
Prev not used
public ListItem(object obj, IListItem prev = null)
{
if (obj != null)
{
this._val = obj;
}
}
//предыдущий связанный элемент списка
public IListItem Prev()
{
try
{
Here, with this code, there will never be an exception
return prev;
}
catch (Exception)
{
return new ListItem(999);
}
}
public void invalidate()
{
prev = null;
next = null;
_val = null;
}
//следующий связанный элемент списка
public IListItem Next()
{
try
{
There can be no exception here, it's just a return of the link
return next;
}
catch (Exception)
{
return new ListItem(999);
}
}
//хранимое значение
public object Value
{
get
{
The entire construction is replaced with return this._val
if (_val != null)
{
return this._val;
}
else return null;
}
}
}
//прямой связанный список
public class LinkedList : ILinkedList
{
private ListItem head;
public int count;
public LinkedList()
{
count = 0;
}
//добавить элемент в начало
public void AddFirst(IListItem item)
{
if (item == null)
{
return;
}
if (head == null)
{
AddToEmtyist(item);
return;
}
ListItem newItem = (ListItem)item;
newItem.next = head;
Head.prev is always null by logic
newItem.prev = head.prev;
If head.prev == null, there will be an exception
head.prev.next = newItem;
head.prev = newItem;
head = newItem;
count++;
}
//добавить элемент в конец
public void AddLast(IListItem item)
{
if (item == null)
{
return;
}
if (head == null)
{
AddToEmtyist(item);
return;
}
ListItem newItem = (ListItem)item;
newItem.next = head;
Head.prev by logic always null
newItem.prev = head.prev;
If head.prev == null, there will be an exception
head.prev.next = newItem;
head.prev = newItem;
count++;
}
private void AddToEmtyist(IListItem item)
{
try
{
ListItem newItem = (ListItem)item;
Why do the next one and the previous one point to the same thing, and to themselves?
newItem.next = newItem;
newItem.prev = newItem;
head = newItem;
count++;
}
catch (Exception err)
{
If there is an exception, it will not stop here - you run it further yourself
throw;
}
}
//вставить элемент перед элементом с указанным индексом
//если элемента нет - вставить в конец
public void Insert(IListItem item, int index)
{
try
{
if (item == null)
{
return;
}
int i = 0;
ListItem replaceItem = head;
if (index > (count - 1))
{
AddLast(item);
return;
}
if (index == 0)
{
AddFirst(item);
}
while (index != i)
{
replaceItem = replaceItem.next;
i++;
}
ListItem newItem = (ListItem)item;
newItem.next = replaceItem;
newItem.prev = replaceItem.prev;
replaceItem.prev.next = newItem;
replaceItem.prev = newItem;
count++;
}
catch (Exception err)
{
}
}
//проверка есть ли эелементы в списке
public bool IsEmpty()
{
if (count > 0)
{
return false;
}
else return true;
}
//вернуть первый эелемент в списке
public IListItem GetFirstItem()
{
// просто return head;
if (head != null)
{
return head;
}
else return null;
}
//вернуть все элементы списка, кроме первого
public IEnumerable<IListItem> GetAll()
{
if (count == 0)
{
If you return null as a result , you get nullreferenceexceprion in the calling code.
Return Enumerable.Empty<IListItem>();
return null;
}
List<IListItem> rez = new List<IListItem>();
int cnt = 0;
ListItem currItem = head;
Why are there counters at all? Just go through the list until you run out.
while (cnt != (count))
{
if (currItem != head)
{
rez.Add(currItem);
}
currItem = currItem.next;
cnt++;
}
return rez;
}
//очистить список
public void Clear()
{
ListItem current = (ListItem)head;
while (current != null)
{
ListItem temp = current;
current = (ListItem)current.Next();
temp.invalidate();
}
head = null;
count = 0;
}
//сортировка списка в обратном порядке
public void Reverse()
{
ListItem node = head;
do
{
ListItem temp = node.next;
node.next = node.prev;
node.prev = temp;
node = node.prev;
if (temp == head)
{
break;
}
}
while (true);
head = head.next;
}
}