重构项目结构,实现链表LRU缓存和链表反转等几个常规操作

This commit is contained in:
robin 2019-01-11 16:48:26 +08:00
parent 1e4b89cfc2
commit 53a4d69bc8
23 changed files with 1210 additions and 848 deletions

View File

@ -1,223 +0,0 @@
using System;
using Xunit;
using Xunit.Abstractions;
public class ArrayTests
{
private readonly Array<int> _sqList;
private readonly ITestOutputHelper _output;
public ArrayTests (ITestOutputHelper output)
{
_sqList = new Array<int> (10);
_output = output;
}
private void PrintList ()
{
for (int idx = 0; idx < _sqList.Length; idx++)
{
var elem = _sqList.Find (idx + 1);
_output.WriteLine (elem.ToString ());
}
}
[Fact]
public void Length_Equal_0_When_List_Is_Empty ()
{
Assert.True (_sqList.Length == 0);
}
[Fact]
public void Length_Equal_1_After_InsertOneElement ()
{
_sqList.Insert (1, 1);
Assert.True (_sqList.Length == 1);
}
[Fact]
public void Insert_ThrowIndexOutOfRangeException_When_PositionGreaterThanLength ()
{
_sqList.Insert (1, 1);
Exception ex = Assert.Throws<IndexOutOfRangeException> (() => _sqList.Insert (3, 1));
Assert.IsType<IndexOutOfRangeException> (ex);
}
[Fact]
public void Insert_ThrowIndexOutOfRangeException_When_PositionLessThanOne ()
{
Exception ex = Assert.Throws<IndexOutOfRangeException> (() => _sqList.Insert (0, 1));
Assert.IsType<IndexOutOfRangeException> (ex);
}
[Fact]
public void Insert_ThrowIndexOutOfRangeException_When_List_Is_Full ()
{
_sqList.Insert (1, 10);
_sqList.Insert (2, 9);
_sqList.Insert (3, 8);
_sqList.Insert (4, 7);
_sqList.Insert (5, 6);
_sqList.Insert (6, 5);
_sqList.Insert (7, 4);
_sqList.Insert (8, 3);
_sqList.Insert (9, 2);
_sqList.Insert (10, 1);
PrintList ();
Exception ex = Assert.Throws<OutOfMemoryException> (() => _sqList.Insert (11, 101));
Assert.IsType<OutOfMemoryException> (ex);
}
[Fact]
public void Delete_ThrowIndexOutOfRangeException_When_PositionLessThanOne ()
{
Exception ex = Assert.Throws<IndexOutOfRangeException> (() => _sqList.Delete (0));
Assert.IsType<IndexOutOfRangeException> (ex);
}
[Fact]
public void Delete_ThrowIndexOutOfRangeException_When_PositionGreaterThanLength ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
Exception ex = Assert.Throws<IndexOutOfRangeException> (() => _sqList.Delete (3));
Assert.IsType<IndexOutOfRangeException> (ex);
}
[Fact]
public void Delete_First_Element ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
var elem = _sqList.Delete (1);
Assert.Equal (11, elem);
}
[Fact]
public void Delete_Last_Element ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
var elem = _sqList.Delete (3);
Assert.Equal (33, elem);
}
[Fact]
public void Delete_Middle_Element ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
var elem = _sqList.Delete (2);
Assert.Equal (22, elem);
}
[Fact]
public void GetElem_ThrowsIndexOutOfRangeException_When_PositionLessThanZero ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
Exception ex = Assert.Throws<IndexOutOfRangeException> (() => _sqList.Find (0));
Assert.IsType<IndexOutOfRangeException> (ex);
}
[Fact]
public void GetElem_ThrowsIndexOutOfRangeException_When_PositionGreaterThanLength ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
Exception ex = Assert.Throws<IndexOutOfRangeException> (() => _sqList.Find (4));
Assert.IsType<IndexOutOfRangeException> (ex);
}
[Fact]
public void GetElem_Last_Position_Return_33 ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
var elem = _sqList.Find (3);
Assert.Equal (33, elem);
}
[Fact]
public void GetElem_First_Position_Return_11 ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
var elem = _sqList.Find (1);
Assert.Equal (11, elem);
}
[Fact]
public void IndexOf_Return_Netagive1_When_Element_Not_Exist ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
var elem = _sqList.IndexOf (55);
Assert.Equal (-1, elem);
}
[Fact]
public void IndexOf_Return_First_Index ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
var elem = _sqList.IndexOf (11);
Assert.Equal (0, elem);
}
[Fact]
public void IndexOf_Return_Last_Index ()
{
_sqList.Insert (1, 11);
_sqList.Insert (2, 22);
_sqList.Insert (3, 33);
var elem = _sqList.IndexOf (33);
Assert.Equal (2, elem);
}
[Fact]
public void Clear_Length_Equal_Zero_If_Empty ()
{
_sqList.Insert (1, 10);
_sqList.Insert (2, 9);
_sqList.Insert (3, 8);
_sqList.Insert (4, 7);
_sqList.Insert (5, 6);
_sqList.Insert (6, 5);
_sqList.Insert (7, 4);
_sqList.Insert (8, 3);
_sqList.Insert (9, 2);
_sqList.Insert (10, 1);
Assert.Equal (10, _sqList.Length);
_sqList.Clear ();
Assert.Equal (0, _sqList.Length);
}
}

View File

@ -1,12 +1,14 @@
using System; using System;
public sealed class Array<T> namespace _05_array
{ {
public sealed class Array<T> where T : IComparable<T>
{
private T[] _data; private T[] _data;
private int _capacity; private readonly int _capacity;
private int _length; private int _length;
public Array (int capacity) public Array(int capacity)
{ {
_data = new T[capacity]; _data = new T[capacity];
_capacity = capacity; _capacity = capacity;
@ -16,84 +18,99 @@ public sealed class Array<T>
// length of list // length of list
public int Length => _length; public int Length => _length;
// insert a new element at specified position (position start from 1) // insert a new element at specified index (index start from 0)
public void Insert (int position, T newElem) public void Insert(int index, T newElem)
{ {
if (_length == _capacity) if (_length == _capacity)
{ {
throw new OutOfMemoryException ("List has no more space"); throw new OutOfMemoryException("List has no more space");
} }
if (position < 1 || position > _length + 1) if (index < 0 || index > _length)
{ {
throw new IndexOutOfRangeException ("Position was outside the bounds of the list"); throw new IndexOutOfRangeException("Index was outside the bounds of the list");
} }
// to loop array from last position until finding the target position // to loop array from end until finding the target index
if (position <= _length) for (int k = _length; k > index; k--)
{ {
for (int k = _length - 1; k >= position - 1; k--) _data[k] = _data[k - 1];
{ }
_data[k + 1] = _data[k];
} _data[index] = newElem;
}
_data[position - 1] = newElem;
_length++; _length++;
} }
// get an element (position start from 1) // get an element base on index
public T Find (int position) public T Find(int index)
{ {
if (position < 0 || position > _length) if (index < 0 || index > _length - 1)
{ {
throw new IndexOutOfRangeException ("Position was outside the bounds of the list"); throw new IndexOutOfRangeException("Index was outside the bounds of the list");
}
return _data[position - 1];
} }
// search the element which matches specified element and return its index (index start from 0) return _data[index];
public int IndexOf (T elem) }
// search the node which matches specified value and return its index (index start from 0)
public int IndexOf(T val)
{ {
if (_length == 0) return -1; if (_length == 0) return -1;
if (_data[0].Equals (elem)) return 0; if (_data[0].Equals(val)) return 0;
if (_data[_length - 1].Equals (elem)) return _length - 1; if (_data[_length - 1].CompareTo(val) == 0) return _length - 1;
int start = 0; int start = 1;
while (start < _length - 1) while (start < _length - 1)
{ {
if (_data[start].Equals (elem)) return start; if (_data[start].CompareTo(val) == 0) return start;
start++; start++;
continue;
} }
return -1; return -1;
} }
// delete an element which is on the specified position (position start from 1) // delete an node which is on the specified index
public T Delete (int position) public bool Delete(int index)
{ {
if (position < 1 || position > _length) if (index < 0 || index > _length - 1)
{ {
throw new IndexOutOfRangeException ("Position must be in the bound of list"); throw new IndexOutOfRangeException("Index must be in the bound of list");
} }
var elem = _data[position - 1]; T deletedElem = _data[index];
for (int k = position; k < _length; k++) if (index < _length - 1)
{ {
_data[k - 1] = _data[k]; for (int k = index; k < _length; k++)
{
_data[k] = _data[k + 1];
}
} }
_length--; _length--;
return elem; return true;
}
// delete an node
public bool Delete(T val)
{
int index;
for (index = 0; index < Length; index++)
{
if (_data[index].CompareTo(val) == 0) break;
}
if (index >= Length) return false;
return Delete(index);
} }
// clear list // clear list
public void Clear () public void Clear()
{ {
_data = new T[_capacity]; _data = new T[_capacity];
_length = 0; _length = 0;
} }
}
} }

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp2.2</TargetFramework>
@ -6,10 +6,4 @@
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,45 @@
using System.Text.RegularExpressions;
using _05_array;
namespace _06_linked_list
{
/// <summary>
/// 使用数组实现LRU缓存淘汰算法
/// </summary>
public class LRUWithArray
{
private readonly int _capacity;
public LRUWithArray(int capacity)
{
_capacity = capacity;
CachedList = new Array<int>(capacity);
}
public Array<int> CachedList { get; }
public void Set(int val)
{
// 找出该值在缓存中的索引位置
int idx = CachedList.IndexOf(val);
// 存在该缓存值
if (idx != -1)
{
CachedList.Delete(idx);
CachedList.Insert(0, val);
return;
}
// 不存在该缓存值
if (CachedList.Length == _capacity)
{
// 缓存已满,删除最后一个元素
CachedList.Delete(CachedList.Length - 1);
}
// 将新缓存插入到表头
CachedList.Insert(0, val);
}
}
}

View File

@ -0,0 +1,48 @@
namespace _06_linked_list
{
/// <summary>
/// 使用单链表实现LRU缓存淘汰算法
/// </summary>
public class LRUWithLinkedList
{
private readonly int _capacity;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="capacity">缓存容量</param>
public LRUWithLinkedList(int capacity = 10)
{
_capacity = capacity;
}
public SingleLinkedList<int> CachedList { get; } = new SingleLinkedList<int>();
/// <summary>
/// 存储缓存数据
/// </summary>
/// <param name="val"></param>
public void Set(int val)
{
// 尝试删除匹配到和给定值相等的结点,并返回
var deletedNode = CachedList.Delete(value: val);
// 数据在缓存中存在,从原位置删除,然后插入到表头
if (deletedNode != null)
{
CachedList.Insert(1, val);
return;
}
// 数据不存在
if (CachedList.Length == _capacity)
{
// 链表已满,删除尾结点,将新数据插入到头部
CachedList.Delete(CachedList.Length);
}
// 将新缓存值插入到表头
CachedList.Insert(1, val);
}
}
}

View File

@ -0,0 +1,8 @@
实现LRU缓存淘汰算法思路
维护一个有序单链表,越靠近链尾的数据是最早访问的。
当有一个新的数据被访问时,
1. 如果数据在缓存中,则将其从原位置删除,然后插入到表头;
2. 如果数据不在缓存中,有两种情况:
1) 链表未满,则将数据插入到表头;
2) 链表已满,则删除尾结点,将新数据插入到表头。

View File

@ -0,0 +1,163 @@
using System;
namespace _06_linked_list
{
/// <summary>
/// 单链表的插入、删除、清空、查找
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingleLinkedList<T> where T : IComparable<T>
{
public SingleLinkedList()
{
Head = new ListNode<T>(default(T));
}
public SingleLinkedList(params T[] list)
{
Head = new ListNode<T>(default(T));
if (list == null) return;
var p = Head;
foreach (var item in list)
{
var q = new ListNode<T>(item);
p.Next = q;
p = q;
}
Length = list.Length;
}
// Head node
public ListNode<T> First => Head.Next;
public ListNode<T> Head { get; }
public int Length { get; private set; }
public ListNode<T> Insert(int position, T newElem)
{
if (position < 1 || position > Length + 1)
{
throw new IndexOutOfRangeException("Position must be in bound of list");
}
var p = Head;
int j = 1;
while (p != null && j < position)
{
p = p.Next;
++j;
}
var newNode = new ListNode<T>(newElem);
newNode.Next = p.Next;
p.Next = newNode;
Length++;
return newNode;
}
public ListNode<T> Find(int position)
{
ListNode<T> p = First;
int j = 1;
while (p != null && j < position)
{
p = p.Next;
j++;
}
if (p == null || j > position)
{
return null;
}
return p;
}
public ListNode<T> Find(T elem)
{
ListNode<T> p = Head.Next;
while (p != null)
{
if (p.Value.CompareTo(elem) == 0) return p;
p = p.Next;
}
return null;
}
public ListNode<T> Delete(T value)
{
ListNode<T> cur = Head;
while (cur.Next != null && cur.Next.Value.CompareTo(value) != 0)
{
cur = cur.Next;
}
if (cur.Next == null) return null;
var q = cur.Next;
cur.Next = q.Next;
Length--;
return q;
}
public ListNode<T> Delete(int position)
{
if (position < 1 || position > Length)
{
return null;
}
var p = First;
int j = 1;
while (p != null && j < position - 1)
{
p = p.Next;
++j;
}
var q = p.Next;
p.Next = q.Next;
Length--;
return q;
}
public void Clear()
{
var cur = Head;
while (cur.Next != null)
{
var q = cur.Next;
cur.Next = null;
cur = q;
}
Length = 0;
}
}
public class ListNode<T>
{
public ListNode(T value)
{
Value = value;
}
public T Value { get; }
public ListNode<T> Next { get; set; }
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\05-array\_05_array.csproj" />
</ItemGroup>
</Project>

View File

@ -1,63 +0,0 @@
namespace _06_linked_list
{
/// <summary>
/// 使用单链表实现LRU缓存淘汰算法
/// </summary>
/// <remarks>
/// 思路:
/// 维护一个有序单链表,越是靠近链尾的数据是最早访问的。当有一个新的数据被访问时,
/// 1. 如果数据在缓存中,则将其从原位置删除,然后插入到表头;
/// 2. 如果数据不在缓存中,有两种情况:
/// 1) 链表未满,则将数据插入到表头;
/// 2) 链表已满,则删除尾结点,将新数据插入到表头。
/// </remarks>
public class LRULinkedList
{
private readonly SingleLinkedList<int> _cachedList = new SingleLinkedList<int>();
private readonly int _capacity;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="capacity">缓存容量</param>
public LRULinkedList(int capacity = 10)
{
_capacity = capacity;
}
/// <summary>
/// 存储缓存数据
/// </summary>
/// <param name="val"></param>
public void Set(int val)
{
var deletedNode = _cachedList.Delete(value: val);
// 数据在缓存中存在,从原位置删除,然后插入到表头
if (deletedNode != null)
{
_cachedList.Insert(1, val);
return;
}
// 数据不存在
if (_cachedList.Length != _capacity)
{
// 链表未满
_cachedList.Insert(1, val);
}
else
{
// 链表已满,删除尾结点,将新数据插入到头部
_cachedList.Delete(_cachedList.Length);
_cachedList.Insert(1, val);
}
}
public SingleLinkedList<int> GetCachedList()
{
return _cachedList;
}
}
}

View File

@ -1,320 +0,0 @@
using System;
namespace _06_linked_list
{
/// <summary>
/// 单链表的插入、删除、清空、查找
/// 1. 链表反转
/// 2. 环的检测
/// 3. 两个有序链表的合并
/// 4. 删除链表倒数第n个结点
/// 5. 求链表的中间结点
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingleLinkedList<T> where T : IComparable<T>
{
public SingleLinkedList ()
{
Head = new LinkedListNode<T> (default (T));
}
public SingleLinkedList (params T[] list)
{
Head = new LinkedListNode<T> (default (T));
if (list == null) return;
var p = Head;
foreach (var item in list)
{
var q = new LinkedListNode<T> (item);
p.Next = q;
p = q;
}
Length = list.Length;
}
// Head node
public LinkedListNode<T> First => Head.Next;
public LinkedListNode<T> Head { get; }
public int Length { get; private set; }
public LinkedListNode<T> Insert (int position, T newElem)
{
if (position < 1 || position > Length + 1)
{
throw new IndexOutOfRangeException ("Position must be in bound of list");
}
var p = Head;
int j = 1;
while (p != null && j < position)
{
p = p.Next;
++j;
}
var newNode = new LinkedListNode<T> (newElem);
newNode.Next = p.Next;
p.Next = newNode;
Length++;
return newNode;
}
public LinkedListNode<T> Find (int position)
{
LinkedListNode<T> p = First;
int j = 1;
while (p != null && j < position)
{
p = p.Next;
j++;
}
if (p == null || j > position)
{
return null;
}
return p;
}
public LinkedListNode<T> Find (T elem)
{
LinkedListNode<T> p = Head.Next;
while (p != null)
{
if (p.Value.CompareTo (elem) == 0) return p;
p = p.Next;
}
return null;
}
public LinkedListNode<T> Delete (T value)
{
LinkedListNode<T> cur = Head;
while (cur.Next != null && cur.Next.Value.CompareTo (value) != 0)
{
cur = cur.Next;
}
if (cur.Next == null) return null;
var q = cur.Next;
cur.Next = q.Next;
Length--;
return q;
}
public LinkedListNode<T> Delete (int position)
{
if (position < 1 || position > Length)
{
return null;
}
var p = First;
int j = 1;
while (p != null && j < position - 1)
{
p = p.Next;
++j;
}
var q = p.Next;
p.Next = q.Next;
Length--;
return q;
}
public void Clear ()
{
var cur = Head;
while (cur.Next != null)
{
var q = cur.Next;
cur.Next = null;
cur = q;
}
Length = 0;
}
/// <summary>
/// reverse current list
/// </summary>
public void Reverse ()
{
if (Length <= 1) return;
LinkedListNode<T> p = First;
LinkedListNode<T> q = First.Next;
LinkedListNode<T> r = null;
p.Next = null;
while (q != null)
{
r = q.Next;
q.Next = p;
p = q;
q = r;
}
Head.Next = p;
}
/// <summary>
/// 环的检测
/// </summary>
/// <remarks>
/// 用快慢两个指针快指针每次移动2个结点慢指针每次移动1个结点当两个指针相遇时说明存在环。
/// LeetCode 编号: 141
/// </remarks>
public bool HasCycle ()
{
if (Length == 0) return false;
var slow = Head.Next;
var fast = Head.Next.Next;
while (fast != null && slow != null && fast != slow)
{
fast = fast.Next?.Next;
slow = slow.Next;
}
bool ret = fast == slow;
return ret;
}
/// <summary>
/// 合并两个有序链表(从小到大)
/// </summary>
/// <remarks>LeetCode 编号: 21</remarks>
/// <param name="list"></param>
/// <returns></returns>
public SingleLinkedList<T> Merge (SingleLinkedList<T> list)
{
if (list == null) return null;
var root = new SingleLinkedList<T> ();
LinkedListNode<T> pointer = root.Head; // 总是向新链表的尾结点
var head1 = list.First;
var head2 = this.First;
while (head1 != null && head2 != null)
{
if (head1.Value.CompareTo (head2.Value) < 0)
{
pointer.Next = head1;
head1 = head1.Next;
}
else
{
pointer.Next = head2;
head2 = head2.Next;
}
pointer = pointer.Next; // 指向尾结点
}
if (head1 != null)
{
pointer.Next = head1;
}
if (head2 != null)
{
pointer.Next = head2;
}
return root;
}
/// <summary>
/// 删除倒数第n个结点
/// </summary>
/// <remarks>
/// 用快慢两个指针快指针比慢指针早n个结点然后再同步移动两个指针当快指针指向尾结点时慢指针就是将要删除的结点
/// LeetCode 编号: 19
/// </remarks>
/// <param name="n"></param>
public void RemoveNthNodeFromEnd (int n)
{
if (n < 1 || n > Length) return;
LinkedListNode<T> preNode = Head;
LinkedListNode<T> curNode = Head;
for (int i = 0; i < n; i++)
{
curNode = curNode.Next;
}
if (curNode == null) return;
while (curNode.Next != null)
{
preNode = preNode.Next;
curNode = curNode.Next;
}
preNode.Next = preNode.Next.Next;
}
/// <summary>
/// 链表的中间结点
/// </summary>
/// <remarks>
/// 思路: 利用快慢指针快指针步长2慢指针步长1当快指针到达尾结点时慢指针正好到达中间结点
/// LeetCode 编号: 876
/// </remarks>
/// <returns></returns>
public LinkedListNode<T> FindMiddleNode ()
{
if (First?.Next == null) return null;
LinkedListNode<T> slowPointer = First;
LinkedListNode<T> fastPointer = First.Next;
while (fastPointer.Next?.Next != null)
{
fastPointer = fastPointer.Next.Next;
slowPointer = slowPointer.Next;
}
slowPointer = slowPointer.Next;
return slowPointer;
}
}
public class LinkedListNode<T>
{
private T _value;
public LinkedListNode (T value)
{
_value = value;
}
public T Value => _value;
public LinkedListNode<T> Next { get; set; }
}
}

View File

@ -0,0 +1,172 @@
using System;
using _06_linked_list;
namespace _07_linkedlist
{
/// <summary>
/// 单链表常用算法操作
/// 1. 链表反转
/// 2. 环的检测
/// 3. 两个有序链表的合并
/// 4. 删除链表倒数第n个结点
/// 5. 求链表的中间结点
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingleLinkedListAlgo<T> : SingleLinkedList<T> where T : IComparable<T>
{
public SingleLinkedListAlgo(params T[] list) : base(list)
{
}
/// <summary>
/// 链表反转
/// </summary>
public void Reverse()
{
if (Length <= 1) return;
ListNode<T> p = First;
ListNode<T> q = First.Next;
ListNode<T> r = null;
p.Next = null;
while (q != null)
{
r = q.Next;
q.Next = p;
p = q;
q = r;
}
Head.Next = p;
}
/// <summary>
/// 环的检测
/// </summary>
/// <remarks>
/// 用快慢两个指针快指针每次移动2个结点慢指针每次移动1个结点当两个指针相遇时说明存在环。
/// LeetCode 编号: 141
/// </remarks>
public bool HasCycle()
{
if (Length == 0) return false;
var slow = Head.Next;
var fast = Head.Next.Next;
while (fast != null && slow != null && fast != slow)
{
fast = fast.Next?.Next;
slow = slow.Next;
}
bool ret = fast == slow;
return ret;
}
/// <summary>
/// 合并两个有序链表(从小到大)
/// </summary>
/// <remarks>LeetCode 编号: 21</remarks>
/// <param name="listAlgo"></param>
/// <returns></returns>
public SingleLinkedListAlgo<T> Merge(SingleLinkedListAlgo<T> listAlgo)
{
if (listAlgo == null) return null;
var root = new SingleLinkedListAlgo<T>();
ListNode<T> pointer = root.Head; // 总是向新链表的尾结点
var head1 = listAlgo.First;
var head2 = this.First;
while (head1 != null && head2 != null)
{
if (head1.Value.CompareTo(head2.Value) < 0)
{
pointer.Next = head1;
head1 = head1.Next;
}
else
{
pointer.Next = head2;
head2 = head2.Next;
}
pointer = pointer.Next; // 指向尾结点
}
if (head1 != null)
{
pointer.Next = head1;
}
if (head2 != null)
{
pointer.Next = head2;
}
return root;
}
/// <summary>
/// 删除倒数第n个结点
/// </summary>
/// <remarks>
/// 用快慢两个指针快指针比慢指针早n个结点然后再同步移动两个指针当快指针指向尾结点时慢指针就是将要删除的结点
/// LeetCode 编号: 19
/// </remarks>
/// <param name="n"></param>
public void RemoveNthNodeFromEnd(int n)
{
if (n < 1 || n > Length) return;
ListNode<T> preNode = Head;
ListNode<T> curNode = Head;
for (int i = 0; i < n; i++)
{
curNode = curNode.Next;
}
if (curNode == null) return;
while (curNode.Next != null)
{
preNode = preNode.Next;
curNode = curNode.Next;
}
preNode.Next = preNode.Next.Next;
}
/// <summary>
/// 链表的中间结点
/// </summary>
/// <remarks>
/// 思路: 利用快慢指针快指针步长2慢指针步长1当快指针到达尾结点时慢指针正好到达中间结点
/// LeetCode 编号: 876
/// </remarks>
/// <returns></returns>
public ListNode<T> FindMiddleNode()
{
if (First?.Next == null) return null;
ListNode<T> slowPointer = First;
ListNode<T> fastPointer = First.Next;
while (fastPointer.Next?.Next != null)
{
fastPointer = fastPointer.Next.Next;
slowPointer = slowPointer.Next;
}
slowPointer = slowPointer.Next;
return slowPointer;
}
}
}

View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\06-linkedlist\_06_linked_list.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,231 @@
using System;
using Xunit;
using Xunit.Abstractions;
using _05_array;
namespace _05_array_tests
{
public class ArrayTests
{
private readonly Array<int> _sqList;
private readonly ITestOutputHelper _output;
public ArrayTests(ITestOutputHelper output)
{
_sqList = new Array<int>(10);
_output = output;
}
private void PrintList()
{
for (int idx = 0; idx < _sqList.Length; idx++)
{
var elem = _sqList.Find(idx);
_output.WriteLine(elem.ToString());
}
}
[Fact]
public void Length_Equal_1_After_InsertOneElement()
{
_sqList.Insert(0, 1);
Assert.True(_sqList.Length == 1);
}
[Fact]
public void Insert_ThrowIndexOutOfRangeException_When_Index_GreaterThan_Length()
{
_sqList.Insert(0, 1);
Exception ex = Assert.Throws<IndexOutOfRangeException>(() => _sqList.Insert(3, 2));
Assert.IsType<IndexOutOfRangeException>(ex);
}
[Fact]
public void Insert_ThrowIndexOutOfRangeException_When_Index_LessThan_Zero()
{
Exception ex = Assert.Throws<IndexOutOfRangeException>(() => _sqList.Insert(-1, 1));
Assert.IsType<IndexOutOfRangeException>(ex);
}
[Fact]
public void Insert_ThrowIndexOutOfRangeException_When_List_Is_Full()
{
_sqList.Insert(0, 11);
_sqList.Insert(1, 10);
_sqList.Insert(2, 9);
_sqList.Insert(3, 8);
_sqList.Insert(4, 7);
_sqList.Insert(5, 6);
_sqList.Insert(6, 5);
_sqList.Insert(7, 4);
_sqList.Insert(8, 3);
_sqList.Insert(9, 2);
PrintList();
Exception ex = Assert.Throws<OutOfMemoryException>(() => _sqList.Insert(10, 101));
Assert.IsType<OutOfMemoryException>(ex);
}
[Fact]
public void Delete_ThrowIndexOutOfRangeException_When_Index_LessThan_Zero()
{
Exception ex = Assert.Throws<IndexOutOfRangeException>(() => _sqList.Delete(-1));
Assert.IsType<IndexOutOfRangeException>(ex);
}
[Fact]
public void Delete_ThrowIndexOutOfRangeException_When_Index_GreaterThan_Length()
{
_sqList.Insert(0, 11);
_sqList.Insert(1, 22);
Exception ex = Assert.Throws<IndexOutOfRangeException>(() => _sqList.Delete(3));
Assert.IsType<IndexOutOfRangeException>(ex);
}
[Fact]
public void Delete_First_Element_Success()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
bool ret = _sqList.Delete(1);
Assert.True(ret);
}
[Fact]
public void Delete_Last_Element_Success()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
bool ret = _sqList.Delete(3);
Assert.True(ret);
}
[Fact]
public void Delete_Middle_Element()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
bool ret = _sqList.Delete(2);
Assert.True(ret);
}
[Fact]
public void Find_ThrowsIndexOutOfRangeException_When_Index_LessThan_Zero()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
Exception ex = Assert.Throws<IndexOutOfRangeException>(() => _sqList.Find(-1));
Assert.IsType<IndexOutOfRangeException>(ex);
}
[Fact]
public void Find_ThrowsIndexOutOfRangeException_When_Index_GreaterThan_Length()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
Exception ex = Assert.Throws<IndexOutOfRangeException>(() => _sqList.Find(4));
Assert.IsType<IndexOutOfRangeException>(ex);
}
[Fact]
public void Find_Last_Position_Return_33()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
var elem = _sqList.Find(3);
Assert.Equal(33, elem);
}
[Fact]
public void Find_First_Element_Return_11()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
var elem = _sqList.Find(1);
Assert.Equal(11, elem);
}
[Fact]
public void IndexOf_Return_Negative_1_When_Element_Not_Exist()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
var elem = _sqList.IndexOf(55);
Assert.Equal(-1, elem);
}
[Fact]
public void IndexOf_Return_First_Index()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
var elem = _sqList.IndexOf(100);
Assert.Equal(0, elem);
}
[Fact]
public void IndexOf_Return_Last_Index()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 11);
_sqList.Insert(2, 22);
_sqList.Insert(3, 33);
var elem = _sqList.IndexOf(33);
Assert.Equal(3, elem);
}
[Fact]
public void Clear_Then_Length_Equal_Zero()
{
_sqList.Insert(0, 100);
_sqList.Insert(1, 10);
_sqList.Insert(2, 9);
_sqList.Insert(3, 8);
_sqList.Insert(4, 7);
_sqList.Insert(5, 6);
_sqList.Insert(6, 5);
_sqList.Insert(7, 4);
_sqList.Insert(8, 3);
_sqList.Insert(9, 2);
Assert.Equal(10, _sqList.Length);
_sqList.Clear();
Assert.Equal(0, _sqList.Length);
}
}
}

View File

@ -1,9 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework> <TargetFramework>netcoreapp2.2</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<AssemblyName>05_array_tests</AssemblyName>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -12,4 +14,8 @@
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\05-array\_05_array.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -1,10 +1,11 @@
using System; using System;
using _06_linked_list;
namespace _06_linked_list namespace _06_linkedlist_tests
{ {
public class BaseLinkedListTests public class BaseLinkedListTests
{ {
protected void PrintList<T> (SingleLinkedList<T> list) where T : IComparable<T> protected void PrintLinkedList<T> (SingleLinkedList<T> list) where T : IComparable<T>
{ {
if (list == null) return; if (list == null) return;

View File

@ -0,0 +1,82 @@
using Xunit;
using Xunit.Abstractions;
using _05_array;
using _06_linked_list;
namespace _06_linkedlist_tests
{
public class LRUWithArrayTests
{
private ITestOutputHelper _output;
public LRUWithArrayTests(ITestOutputHelper output)
{
_output = output;
}
private void PrintList(Array<int> list)
{
if (list == null) return;
for (int idx = 0; idx < list.Length; idx++)
{
_output.WriteLine(list.Find(idx).ToString());
}
}
[Fact]
public void LRU_Set_Value_When_Not_Existed()
{
var lru = new LRUWithArray(5);
lru.Set(1);
lru.Set(3);
lru.Set(5);
lru.Set(7);
lru.Set(9);
var list = lru.CachedList;
PrintList(list);
Assert.Equal(9, list.Find(0));
}
[Fact]
public void LRU_Set_Value_When_Existed()
{
var lru = new LRUWithArray(5);
lru.Set(1);
lru.Set(3);
lru.Set(5);
lru.Set(7);
lru.Set(3);
var list = lru.CachedList;
PrintList(list);
Assert.Equal(3, list.Find(0));
}
[Fact]
public void LRU_Set_Value_When_Full()
{
var lru = new LRUWithArray(5);
lru.Set(1);
lru.Set(3);
lru.Set(5);
lru.Set(7);
lru.Set(9);
lru.Set(8);
var list = lru.CachedList;
PrintList(list);
Assert.Equal(8, list.Find(0));
}
}
}

View File

@ -1,14 +1,15 @@
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
using _06_linked_list;
namespace _06_linked_list namespace _06_linkedlist_tests
{ {
public class LRULinkedListTests : BaseLinkedListTests public class LRUWithLinkedListTests : BaseLinkedListTests
{ {
[Fact] [Fact]
public void LRU_Set_Value_When_Not_Existed() public void LRU_Set_Value_When_Not_Existed()
{ {
var lru = new LRULinkedList(); var lru = new LRUWithLinkedList();
lru.Set(1); lru.Set(1);
lru.Set(3); lru.Set(3);
@ -16,9 +17,9 @@ namespace _06_linked_list
lru.Set(7); lru.Set(7);
lru.Set(9); lru.Set(9);
var list = lru.GetCachedList(); var list = lru.CachedList;
PrintList(list); PrintLinkedList(list);
Assert.Equal(9, list.First.Value); Assert.Equal(9, list.First.Value);
} }
@ -26,7 +27,7 @@ namespace _06_linked_list
[Fact] [Fact]
public void LRU_Set_Value_When_Existed() public void LRU_Set_Value_When_Existed()
{ {
var lru = new LRULinkedList(); var lru = new LRUWithLinkedList();
lru.Set(1); lru.Set(1);
lru.Set(3); lru.Set(3);
@ -34,9 +35,9 @@ namespace _06_linked_list
lru.Set(7); lru.Set(7);
lru.Set(3); lru.Set(3);
var list = lru.GetCachedList(); var list = lru.CachedList;
PrintList(list); PrintLinkedList(list);
Assert.Equal(3, list.First.Value); Assert.Equal(3, list.First.Value);
} }
@ -44,7 +45,7 @@ namespace _06_linked_list
[Fact] [Fact]
public void LRU_Set_Value_When_Full() public void LRU_Set_Value_When_Full()
{ {
var lru = new LRULinkedList(5); var lru = new LRUWithLinkedList(5);
lru.Set(1); lru.Set(1);
lru.Set(3); lru.Set(3);
@ -53,9 +54,9 @@ namespace _06_linked_list
lru.Set(9); lru.Set(9);
lru.Set(8); lru.Set(8);
var list = lru.GetCachedList(); var list = lru.CachedList;
PrintList(list); PrintLinkedList(list);
Assert.Equal(8, list.First.Value); Assert.Equal(8, list.First.Value);
} }

View File

@ -1,8 +1,9 @@
using System; using System;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
using _06_linked_list;
namespace _06_linked_list namespace _06_linkedlist_tests
{ {
public class SingleLinkedListTests : BaseLinkedListTests public class SingleLinkedListTests : BaseLinkedListTests
{ {
@ -11,7 +12,7 @@ namespace _06_linked_list
{ {
var list = new SingleLinkedList<string>("The", "Quick", "Brown"); var list = new SingleLinkedList<string>("The", "Quick", "Brown");
PrintList(list); PrintLinkedList(list);
Assert.Equal(3, list.Length); Assert.Equal(3, list.Length);
} }
@ -33,7 +34,7 @@ namespace _06_linked_list
} }
[Fact] [Fact]
public void Find_Return_Null_When_Postion_LessThan_1() public void Find_Return_Null_When_Position_LessThan_1()
{ {
var list = new SingleLinkedList<string>("The", "Quick", "Brown"); var list = new SingleLinkedList<string>("The", "Quick", "Brown");
@ -42,7 +43,7 @@ namespace _06_linked_list
} }
[Fact] [Fact]
public void Find_Return_Null_When_Postion_GreaterThan_Length() public void Find_Return_Null_When_Position_GreaterThan_Length()
{ {
var list = new SingleLinkedList<string>("The", "Quick", "Brown"); var list = new SingleLinkedList<string>("The", "Quick", "Brown");
@ -51,7 +52,7 @@ namespace _06_linked_list
} }
[Fact] [Fact]
public void Find_Return_Correct_When_Postion_Valid() public void Find_Return_Correct_When_Position_Valid()
{ {
var list = new SingleLinkedList<string>("The", "Quick", "Brown"); var list = new SingleLinkedList<string>("The", "Quick", "Brown");
@ -60,7 +61,7 @@ namespace _06_linked_list
} }
[Fact] [Fact]
public void Delete_Return_Null_When_Postion_LessThan_1() public void Delete_Return_Null_When_Position_LessThan_1()
{ {
var list = new SingleLinkedList<string>("The", "Quick", "Brown"); var list = new SingleLinkedList<string>("The", "Quick", "Brown");
@ -69,7 +70,7 @@ namespace _06_linked_list
} }
[Fact] [Fact]
public void Delete_Return_Null_When_Postion_GreaterThan_Length() public void Delete_Return_Null_When_Position_GreaterThan_Length()
{ {
var list = new SingleLinkedList<string>("The", "Quick", "Brown"); var list = new SingleLinkedList<string>("The", "Quick", "Brown");
@ -85,7 +86,7 @@ namespace _06_linked_list
var deletedNode = list.Delete("over"); var deletedNode = list.Delete("over");
PrintList(list); PrintLinkedList(list);
Assert.Equal("over", deletedNode.Value); Assert.Equal("over", deletedNode.Value);
Assert.Equal(8, list.Length); Assert.Equal(8, list.Length);
@ -99,7 +100,7 @@ namespace _06_linked_list
var deletedNode = list.Delete("hello"); var deletedNode = list.Delete("hello");
PrintList(list); PrintLinkedList(list);
Assert.Null(deletedNode); Assert.Null(deletedNode);
Assert.Equal(9, list.Length); Assert.Equal(9, list.Length);
@ -113,7 +114,7 @@ namespace _06_linked_list
var deletedNode = list.Delete("The"); var deletedNode = list.Delete("The");
PrintList(list); PrintLinkedList(list);
Assert.Equal("The", deletedNode.Value); Assert.Equal("The", deletedNode.Value);
Assert.Equal(8, list.Length); Assert.Equal(8, list.Length);
@ -127,7 +128,7 @@ namespace _06_linked_list
var deletedNode = list.Delete("dog"); var deletedNode = list.Delete("dog");
PrintList(list); PrintLinkedList(list);
Assert.Equal("dog", deletedNode.Value); Assert.Equal("dog", deletedNode.Value);
Assert.Equal(8, list.Length); Assert.Equal(8, list.Length);
@ -141,7 +142,7 @@ namespace _06_linked_list
var node = list.Delete(3); var node = list.Delete(3);
PrintList(list); PrintLinkedList(list);
Assert.Equal("Brown", node.Value); Assert.Equal("Brown", node.Value);
Assert.Equal(8, list.Length); Assert.Equal(8, list.Length);
@ -167,143 +168,5 @@ namespace _06_linked_list
Assert.Null(list.First); Assert.Null(list.First);
} }
[Fact]
public void Reverse_When_List_Is_Empty()
{
var list = new SingleLinkedList<string>();
list.Reverse();
PrintList(list);
Assert.Null(list.First);
}
[Fact]
public void Reverse_When_List_Has_Many_Elements()
{
var list = new SingleLinkedList<string>("The", "Quick", "Brown", "Fox", "jumps", "over", "the", "lazy",
"dog");
list.Reverse();
PrintList(list);
Assert.True(list.First.Value == "dog");
}
[Fact]
public void HasCycle_List_Empty()
{
var list = new SingleLinkedList<string>("The", "Quick", "Brown", "Fox", "jumps", "over", "the", "lazy",
"dog");
bool hasCycle = list.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_False_When_List_Length_1()
{
var list = new SingleLinkedList<string>("The");
bool hasCycle = list.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_False_When_List_Length_2()
{
var list = new SingleLinkedList<string>("The", "Quick");
bool hasCycle = list.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_True_When_List_Length_2()
{
var list = new SingleLinkedList<string>();
var firstNode = list.Insert(1, "The");
var secondNode = list.Insert(2, "Quick");
secondNode.Next = firstNode;
bool hasCycle = list.HasCycle();
Assert.True(hasCycle);
}
[Fact]
public void HasCycle_False()
{
var linkList =
new SingleLinkedList<string>("The", "Quick", "Brown", "fox", "jumps", "over", "the", "lazy", "dog");
bool hasCycle = linkList.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_True()
{
var list = new SingleLinkedList<string>();
// 初始化一个具有环的链表
list.Insert(1, "The");
list.Insert(2, "Quick");
list.Insert(3, "Brown");
var fourthNode = list.Insert(4, "fox");
list.Insert(5, "jumps");
list.Insert(6, "over");
list.Insert(7, "the");
list.Insert(8, "lazy");
var last = list.Insert(9, "dog");
last.Next = fourthNode;
bool hasCycle = list.HasCycle();
Assert.True(hasCycle);
}
[Fact]
public void Merge()
{
var list1 = new SingleLinkedList<int>(1, 2, 4);
var list2 = new SingleLinkedList<int>(1, 3, 4);
var list3 = list1.Merge(list2);
PrintList(list3);
Assert.True(list1.First.Next.Next.Value == 2);
}
[Fact]
public void Remove_2th_Node_From_End()
{
var list = new SingleLinkedList<int>(1, 2, 3, 4, 5);
list.RemoveNthNodeFromEnd(2);
PrintList(list);
Assert.True(list.First.Next.Next.Next.Value == 5);
}
[Fact]
public void FindMiddleNode()
{
var list = new SingleLinkedList<int>(1, 2, 3, 4, 5);
LinkedListNode<int> middleNode = list.FindMiddleNode();
Assert.True(middleNode.Value == 3);
}
} }
} }

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>_06_linkedlist_tests</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\05-array\_05_array.csproj" />
<ProjectReference Include="..\..\06-linkedlist\_06_linked_list.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,150 @@
using System;
using Xunit;
using _06_linkedlist_tests;
using _06_linked_list;
using _07_linkedlist;
namespace _07_linkedlist_tests
{
public class SingleLinkedListAlgoTests : BaseLinkedListTests
{
[Fact]
public void Reverse_When_List_Is_Empty()
{
var list = new SingleLinkedListAlgo<string>();
list.Reverse();
PrintLinkedList(list);
Assert.Null(list.First);
}
[Fact]
public void Reverse_When_List_Has_Many_Elements()
{
var list = new SingleLinkedListAlgo<string>("The", "Quick", "Brown", "Fox", "jumps", "over", "the", "lazy",
"dog");
list.Reverse();
PrintLinkedList(list);
Assert.True(list.First.Value == "dog");
}
[Fact]
public void HasCycle_List_Empty()
{
var list = new SingleLinkedListAlgo<string>("The", "Quick", "Brown", "Fox", "jumps", "over", "the", "lazy",
"dog");
bool hasCycle = list.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_False_When_List_Length_1()
{
var list = new SingleLinkedListAlgo<string>("The");
bool hasCycle = list.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_False_When_List_Length_2()
{
var list = new SingleLinkedListAlgo<string>("The", "Quick");
bool hasCycle = list.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_True_When_List_Length_2()
{
var list = new SingleLinkedListAlgo<string>();
var firstNode = list.Insert(1, "The");
var secondNode = list.Insert(2, "Quick");
secondNode.Next = firstNode;
bool hasCycle = list.HasCycle();
Assert.True(hasCycle);
}
[Fact]
public void HasCycle_False()
{
var linkList =
new SingleLinkedListAlgo<string>("The", "Quick", "Brown", "fox", "jumps", "over", "the", "lazy", "dog");
bool hasCycle = linkList.HasCycle();
Assert.False(hasCycle);
}
[Fact]
public void HasCycle_True()
{
var list = new SingleLinkedListAlgo<string>();
// 初始化一个具有环的链表
list.Insert(1, "The");
list.Insert(2, "Quick");
list.Insert(3, "Brown");
var fourthNode = list.Insert(4, "fox");
list.Insert(5, "jumps");
list.Insert(6, "over");
list.Insert(7, "the");
list.Insert(8, "lazy");
var last = list.Insert(9, "dog");
last.Next = fourthNode;
bool hasCycle = list.HasCycle();
Assert.True(hasCycle);
}
[Fact]
public void Merge()
{
var list1 = new SingleLinkedListAlgo<int>(1, 2, 4);
var list2 = new SingleLinkedListAlgo<int>(1, 3, 4);
var list3 = list1.Merge(list2);
PrintLinkedList(list3);
Assert.True(list1.First.Next.Next.Value == 2);
}
[Fact]
public void Remove_2th_Node_From_End()
{
var list = new SingleLinkedListAlgo<int>(1, 2, 3, 4, 5);
list.RemoveNthNodeFromEnd(2);
PrintLinkedList(list);
Assert.True(list.First.Next.Next.Next.Value == 5);
}
[Fact]
public void FindMiddleNode()
{
var list = new SingleLinkedListAlgo<int>(1, 2, 3, 4, 5);
ListNode<int> middleNode = list.FindMiddleNode();
Assert.True(middleNode.Value == 3);
}
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\06-linkedlist\_06_linked_list.csproj" />
<ProjectReference Include="..\..\07-linkedlist\_07_linkedlist\_07_linkedlist.csproj" />
<ProjectReference Include="..\_06_linkedlist_tests\_06_linkedlist_tests.csproj" />
</ItemGroup>
</Project>

111
csharp/csharp.sln Normal file
View File

@ -0,0 +1,111 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_05_array", "05-array\_05_array.csproj", "{B88033F6-FF08-434A-AED7-91F5CDB73402}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_06_linked_list", "06-linkedlist\_06_linked_list.csproj", "{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_05_array_tests", "Tests\_05_array_tests\_05_array_tests.csproj", "{14982212-49E4-4409-8BFD-2D8A2945BD83}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_06_linkedlist_tests", "Tests\_06_linkedlist_tests\_06_linkedlist_tests.csproj", "{1B93D9C6-D6C1-4619-BFB9-D84C29099223}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_07_linkedlist", "07-linkedlist\_07_linkedlist\_07_linkedlist.csproj", "{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_07_linkedlist_tests", "Tests\_07_linkedlist_tests\_07_linkedlist_tests.csproj", "{66C3BC00-C135-4279-A666-A330A86F20D5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Debug|x64.ActiveCfg = Debug|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Debug|x64.Build.0 = Debug|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Debug|x86.ActiveCfg = Debug|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Debug|x86.Build.0 = Debug|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Release|Any CPU.Build.0 = Release|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Release|x64.ActiveCfg = Release|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Release|x64.Build.0 = Release|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Release|x86.ActiveCfg = Release|Any CPU
{B88033F6-FF08-434A-AED7-91F5CDB73402}.Release|x86.Build.0 = Release|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Debug|x64.ActiveCfg = Debug|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Debug|x64.Build.0 = Debug|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Debug|x86.ActiveCfg = Debug|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Debug|x86.Build.0 = Debug|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Release|Any CPU.Build.0 = Release|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Release|x64.ActiveCfg = Release|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Release|x64.Build.0 = Release|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Release|x86.ActiveCfg = Release|Any CPU
{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}.Release|x86.Build.0 = Release|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Debug|x64.ActiveCfg = Debug|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Debug|x64.Build.0 = Debug|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Debug|x86.ActiveCfg = Debug|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Debug|x86.Build.0 = Debug|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Release|Any CPU.Build.0 = Release|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Release|x64.ActiveCfg = Release|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Release|x64.Build.0 = Release|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Release|x86.ActiveCfg = Release|Any CPU
{14982212-49E4-4409-8BFD-2D8A2945BD83}.Release|x86.Build.0 = Release|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Debug|x64.ActiveCfg = Debug|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Debug|x64.Build.0 = Debug|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Debug|x86.ActiveCfg = Debug|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Debug|x86.Build.0 = Debug|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Release|Any CPU.Build.0 = Release|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Release|x64.ActiveCfg = Release|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Release|x64.Build.0 = Release|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Release|x86.ActiveCfg = Release|Any CPU
{1B93D9C6-D6C1-4619-BFB9-D84C29099223}.Release|x86.Build.0 = Release|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Debug|x64.ActiveCfg = Debug|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Debug|x64.Build.0 = Debug|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Debug|x86.ActiveCfg = Debug|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Debug|x86.Build.0 = Debug|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Release|Any CPU.Build.0 = Release|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Release|x64.ActiveCfg = Release|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Release|x64.Build.0 = Release|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Release|x86.ActiveCfg = Release|Any CPU
{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}.Release|x86.Build.0 = Release|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Debug|x64.ActiveCfg = Debug|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Debug|x64.Build.0 = Debug|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Debug|x86.ActiveCfg = Debug|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Debug|x86.Build.0 = Debug|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|Any CPU.Build.0 = Release|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x64.ActiveCfg = Release|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x64.Build.0 = Release|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x86.ActiveCfg = Release|Any CPU
{66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{14982212-49E4-4409-8BFD-2D8A2945BD83} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}
{1B93D9C6-D6C1-4619-BFB9-D84C29099223} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}
{66C3BC00-C135-4279-A666-A330A86F20D5} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,10 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNotificationDisabled/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/AutoDetectedNamingRules/=Method/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/AutoDetectedNamingRules/=Parameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/AutoDetectedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/AutoDetectedNamingRules/=Locals/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/AutoDetectedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/AutoDetectedNamingRules/=Property/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/ApplyAutoDetectedRules/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNamingAutoDetectionCompleted/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>