357 lines
10 KiB
C#
357 lines
10 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Xml;
|
|
using System.Xml.Linq;
|
|
|
|
namespace StgSharp.Data
|
|
{
|
|
public class HuffmanTree<T> where T : struct
|
|
{
|
|
HuffmanNodeList<T> leaves;
|
|
|
|
public TreeNode<T> Root
|
|
{
|
|
get => leaves.Last;
|
|
}
|
|
|
|
public HuffmanNodeList<T> LeafList
|
|
{
|
|
get => leaves;
|
|
}
|
|
|
|
internal HuffmanTree(HuffmanNodeList<T> nodeList)
|
|
{
|
|
leaves = nodeList;
|
|
}
|
|
|
|
public static HuffmanTree<T> BuildHuffmanTree(List<(T, ulong)> metaData)
|
|
{
|
|
if (metaData.Count<=3)
|
|
{
|
|
throw new Exception("Data is too little, no need to compress");
|
|
}
|
|
HuffmanNodeList<T> leaves = new HuffmanNodeList<T>();
|
|
HuffmanNodeList<T> all = new HuffmanNodeList<T>();
|
|
|
|
foreach (var item in metaData)
|
|
{
|
|
leaves.Add(new TreeNode<T>(item));
|
|
}
|
|
|
|
int count = 0;
|
|
|
|
while (leaves.Count >2)
|
|
{
|
|
TreeNode<T> node, toMove;
|
|
if (leaves.Last._frequency < leaves.BeforeLast._frequency)
|
|
{
|
|
if (leaves.BeforeLast._frequency < leaves.OverLast._frequency)
|
|
{
|
|
//第三节点最大
|
|
node = new TreeNode<T>(leaves.BeforeLast, leaves.Last);
|
|
toMove = leaves.RemoveAndGetLast; all.Add(toMove);
|
|
toMove = leaves.RemoveAndGetLast; all.Add(toMove);
|
|
leaves.Add(node);
|
|
}
|
|
else
|
|
{
|
|
//第二节点最大
|
|
node = leaves.Last._frequency < leaves.OverLast._frequency ?
|
|
new TreeNode<T>(leaves.OverLast, leaves.Last) :
|
|
new TreeNode<T>(leaves.Last, leaves.OverLast);
|
|
toMove = leaves.RemoveAndGetLast; all.Add(toMove);
|
|
toMove = leaves.RemoveAndGetBeforeLast; all.Add(toMove);
|
|
leaves.Add(node);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if (leaves.Last._frequency < leaves.OverLast._frequency)
|
|
{
|
|
//第三节点最大
|
|
node = new TreeNode<T>(leaves.Last, leaves.BeforeLast);
|
|
toMove = leaves.RemoveAndGetLast; all.Add(toMove);
|
|
toMove = leaves.RemoveAndGetLast; all.Add(toMove);
|
|
leaves.Add(node);
|
|
}
|
|
else
|
|
{
|
|
//第一节点最大
|
|
node = leaves.BeforeLast._frequency < leaves.OverLast._frequency?
|
|
new TreeNode<T>(leaves.OverLast, leaves.BeforeLast):
|
|
new TreeNode<T>(leaves.BeforeLast, leaves.OverLast);
|
|
toMove = leaves.RemoveAndGetBeforeLast; all.Add(toMove);
|
|
toMove = leaves.RemoveAndGetBeforeLast; all.Add(toMove);
|
|
leaves.Add(node);
|
|
}
|
|
}
|
|
|
|
leaves = new HuffmanNodeList<T>( leaves.OrderByDescending(pair => pair.frequency)
|
|
.Select(pair => pair).ToList());
|
|
}
|
|
|
|
TreeNode<T> lastOne = leaves[0];
|
|
TreeNode<T> lastTwo = leaves[1];
|
|
TreeNode<T> root = lastOne.frequency>lastTwo.frequency?
|
|
new TreeNode<T>(lastOne,lastTwo):
|
|
new TreeNode<T>(lastTwo, lastOne);
|
|
|
|
all.Add(lastOne);
|
|
all.Add(lastTwo);
|
|
all.Add(root);
|
|
|
|
leaves = all;
|
|
return new HuffmanTree<T>(all);
|
|
}
|
|
|
|
public Dictionary<T, HuffmanKey<T>> BuildHuffmanDictionary()
|
|
{
|
|
Dictionary<T, HuffmanKey<T>> ret = new Dictionary<T, HuffmanKey<T>>();
|
|
TreeNode<T> root = Root;
|
|
HuffmanKey<T> key = new HuffmanKey<T>();
|
|
key = key.SetSide(KeySide.Right);
|
|
InternalBuildDictionary(ret, root, key);
|
|
return ret;
|
|
}
|
|
|
|
public void InternalBuildDictionary(
|
|
Dictionary<T, HuffmanKey<T>> dict,
|
|
TreeNode<T> node,
|
|
HuffmanKey<T> valueTemp
|
|
)
|
|
{
|
|
valueTemp.AddIndexLevel();
|
|
//检查左节点
|
|
if (node._left.Value==null)
|
|
{
|
|
//左节点不是叶子节点,继续搜索
|
|
InternalBuildDictionary(
|
|
dict,
|
|
node._left,
|
|
valueTemp.SetSide(KeySide.Left));
|
|
}
|
|
else
|
|
{
|
|
//左节点是叶子节点,添加值
|
|
dict.Add(node._left.Value.Value,valueTemp.SetSide(KeySide.Left));
|
|
}
|
|
//检查右节点
|
|
if (node._right.Value == null)
|
|
{
|
|
//右节点不是叶子节点,继续搜索
|
|
InternalBuildDictionary(
|
|
dict,
|
|
node._right,
|
|
valueTemp.SetSide(KeySide.Left));
|
|
}
|
|
else
|
|
{
|
|
//右节点是叶子节点,添加值
|
|
dict.TryAdd(node._right.Value.Value, valueTemp.SetSide(KeySide.Right));
|
|
}
|
|
//这里检查自己是不是叶子节点
|
|
//但是上面已经检查过了,不需要被检查
|
|
}
|
|
}
|
|
|
|
public struct HuffmanKey<T>where T : struct
|
|
{
|
|
internal T value;
|
|
|
|
public T Value
|
|
{
|
|
get { return value; }
|
|
}
|
|
|
|
internal HuffmanKey(T value)
|
|
{
|
|
this.value= value;
|
|
}
|
|
|
|
public unsafe HuffmanKey<T> SetSide(KeySide side)
|
|
{
|
|
HuffmanKey<T> ret = new HuffmanKey<T>(value);
|
|
T* p = &ret.value;
|
|
switch (side)
|
|
{
|
|
case KeySide.Left:
|
|
byte* ptrLeft = (byte*)p;
|
|
*ptrLeft &= 0xfe;
|
|
break;
|
|
case KeySide.Right:
|
|
byte* ptrRight = (byte*)p;
|
|
*ptrRight |= 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
Console.WriteLine(*(byte*)p);
|
|
return ret;
|
|
}
|
|
|
|
public unsafe void AddIndexLevel()
|
|
{
|
|
fixed (T* p = &value)
|
|
{
|
|
switch (Marshal.SizeOf<T>())
|
|
{
|
|
case 1:
|
|
*(byte*)p <<= 1;
|
|
break;
|
|
case 2:
|
|
*(ushort*)p <<= 1;
|
|
break;
|
|
case 4:
|
|
*(uint*)p <<= 1;
|
|
break;
|
|
case 8:
|
|
*(ulong*)p <<= 1;
|
|
break;
|
|
case 16:
|
|
#if NET7_0_OR_GREATER
|
|
*(UInt128*)p <<= 1;
|
|
#else
|
|
ulong* hp = (ulong*)p;
|
|
if (*hp != 0)
|
|
{
|
|
*hp <<= 1;
|
|
}
|
|
*hp += ((*(ulong*)p) & 0x80_00_00_00_00_00_00_00) == 0 ? (ulong)0 : 1;
|
|
*(ulong*)p <<= 1;
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsSupported
|
|
{
|
|
get
|
|
{
|
|
return
|
|
typeof(T) == typeof(byte) ||
|
|
typeof(T) == typeof(uint) ||
|
|
typeof(T) == typeof(ushort) ||
|
|
typeof(T) == typeof(ulong) ||
|
|
#if NET7_0_OR_GREATER
|
|
typeof(T) == typeof(UInt128) ||
|
|
#endif
|
|
typeof(T) == typeof(M128);
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum KeySide
|
|
{
|
|
Left,
|
|
Right
|
|
}
|
|
|
|
public class HuffmanNodeList<T> : List<TreeNode<T>> where T : struct
|
|
{
|
|
public HuffmanNodeList():base()
|
|
{
|
|
|
|
}
|
|
|
|
public HuffmanNodeList(IEnumerable<TreeNode<T>> values):base(values)
|
|
{}
|
|
|
|
public void Add(T element, ulong f)
|
|
{
|
|
base.Add(new TreeNode<T>(element,f));
|
|
}
|
|
|
|
public TreeNode<T> Last
|
|
{
|
|
get => this[Count-1 ];
|
|
}
|
|
|
|
public TreeNode<T> RemoveAndGetLast
|
|
{
|
|
get
|
|
{
|
|
TreeNode<T> ret = this[Count-1];
|
|
RemoveAt(Count-1);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
public TreeNode<T> BeforeLast
|
|
{
|
|
get => this[Count - 2];
|
|
}
|
|
|
|
public TreeNode<T> RemoveAndGetBeforeLast
|
|
{
|
|
get
|
|
{
|
|
TreeNode<T> ret = this[Count - 2];
|
|
RemoveAt(Count - 2);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
public TreeNode<T> OverLast
|
|
{
|
|
get => this[Count - 3];
|
|
}
|
|
|
|
public TreeNode<T> RemoveAndGetOverLast
|
|
{
|
|
get
|
|
{
|
|
TreeNode<T> ret = this[Count - 3];
|
|
RemoveAt(Count - 3);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public class TreeNode<T> where T: struct
|
|
{
|
|
internal TreeNode<T> _left;
|
|
internal TreeNode<T> _right;
|
|
internal T? _value;
|
|
internal ulong _frequency;
|
|
|
|
public ulong frequency => _frequency;
|
|
|
|
public T? Value => _value;
|
|
|
|
public TreeNode<T> Left => _left;
|
|
public TreeNode<T> Right => _right;
|
|
|
|
public TreeNode( T? value, ulong frequncy)
|
|
{
|
|
_value = value;
|
|
_frequency = frequncy;
|
|
|
|
}
|
|
|
|
internal TreeNode(TreeNode<T> left, TreeNode<T> right)
|
|
{
|
|
_left = left;
|
|
_right = right;
|
|
_value = null;
|
|
_frequency = left._frequency + right._frequency;
|
|
}
|
|
|
|
public TreeNode((T, ulong) data)
|
|
{
|
|
_value = data.Item1;
|
|
_frequency = data.Item2;
|
|
|
|
}
|
|
}
|
|
}
|