C实现看起来像泛型的顺序表

文章展示了如何在不支持泛型编程的C语言中,利用void*和位操作实现顺序表的基本操作,如初始化、查找、插入、删除和销毁。代码包括了InitList、Length、LocateElem、GetElem、ListInsert、ListDelete等函数的实现,并在main函数中进行了测试。

顺序表的简单操作 ADT

C前面的版本是不支持泛型编程的,以前学习数据结构的时候采用C++来做的泛型编程,就想着能不能用C来做一次试试,C的void*可以一定程度上实现泛型,实现逻辑主要是依靠位操作,把所有数据类型转换为字符型来操作,最后获取元素的时候再按照不同的类型来解释即可。

#pragma once
typedef struct {
	int maxSize;
	int elemSize;
	void* array;
	int length;
}List;
typedef enum {
	false,true
}bool;
bool InitList(List* list, int size, int elemSize);
int Length(List);
int LocateElem(List, void*);
void* GetElem(List, int);
bool ListInsert(List*, int, void*);
bool ListDelete(List*, int, void*);
void Print(List);
bool Empty(List);
bool DestroyList(L

接口的实现,初始化,按照值查找,返回元素

bool InitList(List* list, int size,int elemSize) {
	list->maxSize = size;
	list->array = malloc(size*elemSize);
	list->length = 0;
	list->elemSize = elemSize;
}//初始化操作
int Length(List list) {
	return list.length;
}//返回数组长度
int LocateElem(List list, void* val) {
	char* bytes = (char*)list.array;
	char* target = (char*)&val;
	for (int i = 0; i < list.length; i++) {
		if (!memcmp(bytes + list.elemSize * i, target, list.elemSize)) {
			return i;
		}
	}
	return -1;
}//返回数据元素的位置
void* GetElem(List list, int index) {
	char* bytes = (char*)list.array;
	return bytes + index * list.elemSize;
}//获取返回元素,最后接收元素的时候需要强转类型

插入元素,删除元素

bool ListInsert(List*list , int index, void* val) {
	if (index<0 || index>list->length + 1)
		return false;//这是是我自定义的枚举类型,可看上方ADT
	char* bytes = (char*)list->array;
	memmove(bytes + (index + 1) * list->elemSize, bytes + index * list->elemSize,(list->length-index)*list->elemSize);//先移动元素,空出位置,由于是泛型,因此统一转为字符型来进行位操作
	memmove(bytes + index * list->elemSize, &val,list->elemSize);
	list->length++;//线性表长度递增
	return true;
}
bool ListDelete(List*list, int index, void* val) {
	if (index > list->length || index < 0) {
		return false;
	}
	char* bytes = (char*)list->array;
	memmove(val, bytes + index * list->elemSize, list->elemSize);
	memmove(bytes + index * list->elemSize, bytes + (index + 1) * list->elemSize, (list->length - index - 1) * list->elemSize);
	list->length--;
	return true;
}//与插入原理相同

判空以及销毁顺序表

bool Empty(List list) {
	if (list.length == 0) {
		return false;
	}
	else
		return true;
}
bool DestroyList(List* list) {
	memset(list->array, 0, list->length * list->elemSize);
	free(list->array);
	list->array = NULL;
	list->length = 0;
	return true;
}

测试

int main() {
	List mylist;
	InitList(&mylist, 5, sizeof(int));
	ListInsert(&mylist, 0, 5);
	ListInsert(&mylist, 1, 6);
	ListInsert(&mylist, 0, 7);
	int a=0;
	ListDelete(&mylist, 0, &a);
	int k = LocateElem(mylist, 6);
	int* m = (int*)GetElem(mylist, 1);
	printf("该位置元素为: %d\n", *m);
	printf("该元素位于: %d\n", k);
	printf("删除的元素为 : %3d\n", a);
	printf("删除后顺序表长度: %3d\n", Length(mylist));
	DestroyList(&mylist);//销毁
	printf("销毁后长度: %3d\n", Length(mylist));
	system("pause");
	return 0;
}

 

 

在 C# 中,**`Dictionary<TKey, TValue>` 的访问顺序是否按照添加顺序**,取决于你使用的具体字典类。 --- ### ❌ `Dictionary<TKey, TValue>`:**不保证顺序** ```csharp var dict = new Dictionary<string, int>(); dict.Add("one", 1); dict.Add("two", 2); dict.Add("three", 3); foreach (var kvp in dict) { Console.WriteLine(kvp.Key); } ``` 📌 **输出结果可能不是添加顺序!** - `Dictionary<TKey, TValue>` 是基于哈希表(hash table)实现的。 - 它**不保留插入顺序**,遍历顺序是不确定的(虽然在某些情况下看起来有序,但这只是巧合或内部结构导致的,不能依赖)。 - 微软官方明确说明:**枚举的顺序没有定义**。 > ⚠️ 即使目前运行时看起来是按添加顺序输出,也不能作为程序逻辑依赖! --- ### ✅ `SortedDictionary<TKey, TValue>`:按键排序 ```csharp var sortedDict = new SortedDictionary<string, int> { { "three", 3 }, { "one", 1 }, { "two", 2 } }; foreach (var kvp in sortedDict) { Console.WriteLine(kvp.Key); // 输出:one, three, two(按 key 排序) } ``` - 基于红黑树实现。 - 遍历时按键(Key)的顺序排序,**不是插入顺序**。 --- ### ✅✅ `System.Collections.Generic.SortedList<TKey, TValue>`:也按键排序 类似 `SortedDictionary`,也是按键排序,不保留插入顺序。 --- ### ✅✅✅ 正确答案:使用 `System.Collections.ObjectModel.KeyedCollection<TKey, TItem>` 或第三方库? 但最常用的是: ## ✅ 推荐方案:使用 `System.Linq.Enumerable.ToDictionary()` 不行 —— 应该用: --- ## ✅ 最佳选择:`System.Collections.Specialized.OrderedDictionary`? ❌ 不推荐:它是 `object` 类,非,主要用于 ASP.NET。 --- ## ✅✅✅ 真正的答案:使用 **`System.Collections.Generic.LinkedList<T>` + `Dictionary<TKey, LinkedListNode<T>>`** 手动维护? 太复杂了。 --- ## ✅✅✅✅ 正确且简单的方法:从 .NET 4.0 开始,有一个隐藏宝藏: ## 🎯 使用 `ImmutableSortedDictionary`?No. --- ## ✅✅✅✅✅ 最佳实践(现代 C#):使用 **`System.Collections.Generic.SortedDictionary`**?还是不对。 --- ## ✅✅✅✅✅✅ 正确答案来了! > ## 从 **.NET 6 起**,微软引入了一个新集合: > > # 🔥 `System.Collections.Generic.PriorityQueue<TElement, TPriority>` > > ❌ 不对,那是优先队列。 --- ## 🚫 悲伤的事实:C# 原生没有 `OrderedDictionary<TKey, TValue>` 类 直到今天(C# 13 / .NET 8),标准库中仍然**没有内置的 `OrderedDictionary<TKey, TValue>`**。 但是! --- ## ✅✅✅ 推荐替代方案:自己封装或使用开源库 ### 方案一:使用两个集合联合管理(手动维护顺序) ```csharp using System; using System.Collections.Generic; using System.Linq; public class OrderedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>> { private readonly Dictionary<TKey, TValue> _dictionary = new(); private readonly List<TKey> _keys = new(); public TValue this[TKey key] { get => _dictionary[key]; set { if (!_dictionary.ContainsKey(key)) { _keys.Add(key); } _dictionary[key] = value; } } public void Add(TKey key, TValue value) { if (_dictionary.ContainsKey(key)) throw new ArgumentException("An item with the same key has already been added."); _dictionary[key] = value; _keys.Add(key); } public bool Remove(TKey key) { if (_dictionary.Remove(key)) { _keys.Remove(key); return true; } return false; } public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { foreach (var key in _keys) { yield return new KeyValuePair<TKey, TValue>(key, _dictionary[key]); } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); } ``` ### 使用示例: ```csharp var orderedDict = new OrderedDictionary<string, int>(); orderedDict.Add("first", 1); orderedDict.Add("second", 2); orderedDict.Add("third", 3); foreach (var kvp in orderedDict) { Console.WriteLine(kvp.Key); // 保证输出:first → second → third } ``` --- ### 方案二:使用 NuGet 包 [**PowerCollections**](https://www.nuget.org/packages/PowerCollections/) 由 Wintellect 提供,包含 `OrderedDictionary<TKey, TValue>`: ```xml <PackageReference Include="PowerCollections" Version="1.0.0" /> ``` ```csharp using Wintellect.PowerCollections; var od = new OrderedDictionary<string, int>(); od.Add("a", 1); od.Add("b", 2); od.Add("c", 3); foreach (var kvp in od) { Console.WriteLine(kvp.Key); // 保证插入顺序! } ``` --- ### 方案三:如果你只需要“读取时保持添加顺序”,可以用 `List<KeyValuePair<TKey, TValue>>` ```csharp var list = new List<KeyValuePair<string, int>>(); list.Add(new("one", 1)); list.Add(new("two", 2)); // 查找效率低 O(n),适合小数据量 ``` --- ### 方案四:只读场景下,你可以用 LINQ 保证顺序 ```csharp var data = new[] { ("one", 1), ("two", 2), ("three", 3) } .ToDictionary(x => x.Item1, x => x.Item2); // 但依然无法保证遍历顺序! ``` 除非你在遍历时强制排序: ```csharp foreach (var kvp in data.OrderBy(kvp => someOrder[kvp.Key])) ``` 但这不是插入顺序。 --- ## ✅ 总结 | 字典类 | 是否保持插入顺序 | 是否按键排序 | 是否推荐用于有序访问 | |--------|------------------|--------------|---------------------| | `Dictionary<TKey, TValue>` | ❌ 否 | ❌ 否 | ❌ 不要依赖顺序 | | `SortedDictionary<TKey, TValue>` | ❌ 否 | ✅ 是(按 Key) | ✅ 适用于按键排序 | | `SortedList<TKey, TValue>` | ❌ 否 | ✅ 是(按 Key) | ✅ 小数据集按键排序 | | 自定义 `OrderedDictionary<TKey, TValue>` | ✅ 是 | ❌ 否 | ✅ 推荐(如上代码) | | PowerCollections.OrderedDictionary | ✅ 是 | ❌ 否 | ✅ 强烈推荐(NuGet) | --- ## 💡 小贴士 - 如果你使用的是 **Unity**,注意其默认 .NET 版本可能较低(如 4.x),不支持最新的集合类。 - 在 Unity 中推荐将上面的 `OrderedDictionary<TKey, TValue>` 类复制进项目使用。 - 对性能要求高且需要插入顺序时,考虑用 `List<T>` + 缓存映射。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值