Skip to content

Commit 341c48d

Browse files
committed
重写2.2.18
1 parent ae5b398 commit 341c48d

File tree

4 files changed

+169
-61
lines changed

4 files changed

+169
-61
lines changed

2 Sorting/2.2/2.2.18/2.2.18.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,19 @@
4343
</ItemGroup>
4444
<ItemGroup>
4545
<Compile Include="LinkedList.cs" />
46+
<Compile Include="MergeSuffle.cs" />
4647
<Compile Include="Node.cs" />
4748
<Compile Include="Program.cs" />
4849
<Compile Include="Properties\AssemblyInfo.cs" />
4950
</ItemGroup>
5051
<ItemGroup>
5152
<None Include="App.config" />
5253
</ItemGroup>
54+
<ItemGroup>
55+
<ProjectReference Include="..\Merge\Merge.csproj">
56+
<Project>{86319415-44d5-4beb-9bd9-87d7e1efa36e}</Project>
57+
<Name>Merge</Name>
58+
</ProjectReference>
59+
</ItemGroup>
5360
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
5461
</Project>

2 Sorting/2.2/2.2.18/LinkedList.cs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -120,27 +120,18 @@ public Item Delete(int index)
120120
}
121121

122122
/// <summary>
123-
/// 将链表对半拆分
123+
/// 获得链表的中间元素
124124
/// </summary>
125-
/// <param name="A">左半部分。</param>
126-
/// <param name="B">右半部分。</param>
127-
public void SplitInHalf(out LinkedList<Item> A, out LinkedList<Item> B)
125+
/// <returns>链表的中间元素。</returns>
126+
public Node<Item> GetMiddle()
128127
{
128+
Node<Item> middle = this.first;
129129
int mid = this.count / 2;
130-
A = new LinkedList<Item>();
131-
B = new LinkedList<Item>();
132-
A.first = this.first;
133-
A.count = mid;
134-
B.first = this.first;
135-
B.count = this.count - mid;
136-
137130
for (int i = 0; i < mid - 1; i++)
138131
{
139-
B.first = B.first.next;
132+
middle = middle.next;
140133
}
141-
Node<Item> temp = B.first;
142-
B.first = B.first.next;
143-
temp.next = null;
134+
return middle;
144135
}
145136

146137
/// <summary>
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
using System;
2+
3+
namespace _2._2._18
4+
{
5+
/// <summary>
6+
/// 归并排序类。
7+
/// </summary>
8+
public class MergeShuffle
9+
{
10+
/// <summary>
11+
/// 默认构造函数。
12+
/// </summary>
13+
public MergeShuffle() { }
14+
15+
/// <summary>
16+
/// 利用分治法打乱链表。
17+
/// </summary>
18+
/// <typeparam name="T">链表元素类型。</typeparam>
19+
/// <param name="a">等待打乱的链表。</param>
20+
public void Shuffle<T>(LinkedList<T> a)
21+
{
22+
int blockLen = 1;
23+
Random random = new Random();
24+
while (blockLen <= a.Size())
25+
{
26+
// 找到第一个块
27+
Node<T> lo = a.GetFirst();
28+
Node<T> mid = FindBlock(lo, blockLen);
29+
30+
if (mid.next == null)
31+
break;
32+
33+
while (mid.next != null)
34+
{
35+
Node<T> hi = FindBlock(mid.next, blockLen);
36+
Node<T>[] result;
37+
if (lo == a.GetFirst())
38+
{
39+
result = Merge(lo, mid, hi, random);
40+
a.SetFirst(result[0]);
41+
}
42+
else
43+
{
44+
result = Merge(lo.next, mid, hi, random);
45+
lo.next = result[0];
46+
}
47+
48+
49+
// 跳到表尾
50+
lo = result[1];
51+
52+
if (lo.next != null)
53+
mid = FindBlock(lo.next, blockLen);
54+
else
55+
mid = lo;
56+
}
57+
blockLen *= 2;
58+
}
59+
}
60+
61+
/// <summary>
62+
/// 将两个有序链表块随机归并,返回新的表头。
63+
/// </summary>
64+
/// <typeparam name="T">链表元素类型。</typeparam>
65+
/// <param name="lo">第一个块起点。</param>
66+
/// <param name="mid">第一个块终点(第二个块起点的前驱)。</param>
67+
/// <param name="hi">第二个块的终点。</param>
68+
/// <returns>新的表头。</returns>
69+
private Node<T>[] Merge<T>(Node<T> lo, Node<T> mid, Node<T> hi, Random random)
70+
{
71+
Node<T> after = hi.next; // 要合并的两个块之后的元素
72+
Node<T> first = null;
73+
Node<T>[] result = new Node<T>[2];
74+
Node<T> i = lo; // 链表1
75+
Node<T> j = mid.next; // 链表2
76+
77+
// 切割链表
78+
mid.next = null;
79+
hi.next = null;
80+
81+
Node<T> current = null;
82+
// 决定新的表头
83+
if (random.NextDouble() >= 0.5)
84+
{
85+
current = i;
86+
i = i.next;
87+
}
88+
else
89+
{
90+
current = j;
91+
j = j.next;
92+
}
93+
94+
first = current;
95+
96+
// 归并表
97+
while (i != null && j != null)
98+
{
99+
if (random.NextDouble() >= 0.5)
100+
{
101+
current.next = i;
102+
i = i.next;
103+
current = current.next;
104+
}
105+
else
106+
{
107+
current.next = j;
108+
j = j.next;
109+
current = current.next;
110+
}
111+
}
112+
113+
if (i == null)
114+
current.next = j;
115+
else
116+
current.next = i;
117+
118+
// 连接表尾(链表 1 的尾部或者链表 2 的尾部)
119+
if (mid.next == null)
120+
{
121+
mid.next = after;
122+
result[1] = mid;
123+
}
124+
else
125+
{
126+
hi.next = after;
127+
result[1] = hi;
128+
}
129+
result[0] = first;
130+
131+
return result;
132+
}
133+
134+
/// <summary>
135+
/// 获取从指定位置开始定长的链表。
136+
/// </summary>
137+
/// <typeparam name="T">链表的元素类型。</typeparam>
138+
/// <param name="lo">链表的起始结点。</param>
139+
/// <param name="length">需要获取的链表长度。</param>
140+
/// <returns>结果链表的最后一个元素结点。</returns>
141+
private Node<T> FindBlock<T>(Node<T> lo, int length)
142+
{
143+
Node<T> hi = lo;
144+
for (int i = 0; i < length - 1 && hi.next != null; i++)
145+
{
146+
hi = hi.next;
147+
}
148+
149+
return hi;
150+
}
151+
}
152+
}

2 Sorting/2.2/2.2.18/Program.cs

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,60 +14,18 @@ class Program
1414
{
1515
static void Main(string[] args)
1616
{
17-
// 对于两个只有一个元素的链表,打乱操作等于50%可能交换+50%可能不交换。
18-
// 将链表不断对半切分,再随机决定是否交换
1917
LinkedList<int> a = new LinkedList<int>();
20-
Random random = new Random();
18+
MergeShuffle shuffle = new MergeShuffle();
2119
a.Insert(1);
2220
a.Insert(2);
2321
a.Insert(3);
2422
a.Insert(4);
2523
a.Insert(5);
2624
a.Insert(6);
27-
28-
a = Shuffle(a, random);
29-
foreach (int i in a)
30-
{
31-
Console.Write(i + " ");
32-
}
33-
Console.WriteLine();
34-
}
35-
36-
/// <summary>
37-
/// 随机打乱链表。
38-
/// </summary>
39-
/// <typeparam name="T">链表中的元素类型。</typeparam>
40-
/// <param name="a">需要打乱的链表。</param>
41-
static LinkedList<T> Shuffle<T>(LinkedList<T> a, Random random)
42-
{
43-
if (a.Size() == 1)
44-
return a;
45-
46-
a.SplitInHalf(out LinkedList<T> A, out LinkedList<T> B);
47-
48-
A = Shuffle(A, random);
49-
B = Shuffle(B, random);
50-
return RandomMerge(A, B, random);
51-
}
52-
53-
/// <summary>
54-
/// 随机合并两个链表,返回合并后的链表。
55-
/// </summary>
56-
/// <typeparam name="T">链表中的元素类型。</typeparam>
57-
/// <param name="a">需要合并的链表。</param>
58-
/// <param name="b">需要合并的链表。</param>
59-
/// <returns>合并后的链表。</returns>
60-
static LinkedList<T> RandomMerge<T> (LinkedList<T> a, LinkedList<T> b, Random random)
61-
{
62-
if (random.Next(10) > 4)
63-
{
64-
LinkedList<T>.Merge(a, b);
65-
return a;
66-
}
67-
else
25+
for (int i = 0; i < 200; i++)
6826
{
69-
LinkedList<T>.Merge(b, a);
70-
return b;
27+
shuffle.Shuffle(a);
28+
Console.WriteLine(a.ToString());
7129
}
7230
}
7331
}

0 commit comments

Comments
 (0)