Files
stgsharp/编码器/StgSharpDataEncoder/StgSharpData/HuffmanTree.cs
T

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;
}
}
}