当前位置:   article > 正文

算法在游戏领域的应用:Unity3D中使用快速排序对排行榜,背包等集合进行排序以及优缺点分析_unity快速排序

unity快速排序

文章目录

文章目录

前言

相关资料

一、什么是快速排序?

快速排序的定义

快速排序的缺点

二、快速排序的实现以及优化

1.基本快排代码

2.优化后的排序算法

为什么继承IComparable?

如何减少快排的最差情况

总结


Hello大家好我是开罗小8,今天我来给大家带来如何使用快速排序对背包,排行榜等游戏中常见集合排序,并将其与其他算法进行比较,以及如何对其进行优化。

前言

在游戏领域中,经常会需要使用到排序的功能,例如玩家整理背包后对道具按稀有度,获得日期,ID等进行排序,或者在排行榜中对玩家的得分进行排序。不同的排序算法有不同的适用环境,有的排序在特定情况下排序的速度会更快,但却在另一种情况下不如其他的排序算法。因此我们需要根据不同的情况选择不同的算法。

本篇文章中,使用C#代码,让我们看一下如何将快速排序应用到游戏中。


相关资料

快速排序算法_哔哩哔哩_bilibili

C# List<>.Sort() 排序的底层实现原理_c#list的底层原理-CSDN博客

快速排序 Vs. 归并排序 Vs. 堆排序——谁才是最强的排序算法_堆排序为什么快-CSDN博客

快速排序的4种优化_快速排序优化-CSDN博客

扒一扒Arrays.sort()方法底层排序原理,奇怪的知识又增加了_arraysort底层用的什么排序-CSDN博客

一、什么是快速排序?

快速排序的定义

快速排序是一种常用的排序算法,时间复杂度为O(nlog n),空间复杂度为O(log n),它是一种不稳定的排序算法,在处理大规模数据时,快速排序的效率是最高的,因此使用最广泛。

快速排序的缺点

不稳定:快速排序是一种不稳定的排序算法,不稳定体现在排序过后,相同值元素在排序前的相对位置可能发生改变,举个例子,比如给一个班的学生按成绩进行排序,小明和小红的分数相同,在排序前,小明在小红的前面,而排序后,小红变到了小明的前面。

特定情况下时间复杂度退化到O(n^2):在待排序集合基本处于有序的情况下,快速排序时间复杂度退化到O(n^2),变成选择排序。

二、快速排序的实现以及优化

我们以对班级学生按成绩进行排序举例

1.基本快排代码

  1. public class Stu
  2. {
  3. public string Name;
  4. public int Score;
  5. public Stu(string name, int score)
  6. {
  7. Name = name;
  8. Score = score;
  9. }
  10. }
  11. class Program
  12. {
  13. static void Main()
  14. {
  15. List<Stu> list = new List<Stu>() {
  16. new Stu("小明", 100), new Stu("小红", 99), new Stu("小刚", 98),
  17. new Stu("小伟", 99), new Stu("小强", 100),
  18. };
  19. QuickSort(list, 0, list.Count - 1);
  20. }
  21. public static void QuickSort(List<Stu> list, int left, int right)
  22. {
  23. if (left >= right) return;
  24. Stu pivot = list[left];
  25. int i = left + 1, j = right;
  26. while (i < j)
  27. {
  28. while (i < j && list[i].Score >= pivot.Score) ++i;
  29. while (i < j && list[j].Score < pivot.Score) --j;
  30. if (i < j)
  31. {
  32. (list[i], list[j]) = (list[j], list[i]);
  33. }
  34. }
  35. if (list[i].Score < pivot.Score) --i;
  36. (list[i], list[left]) = (list[left], list[i]);
  37. QuickSort(list, left, i - 1);
  38. QuickSort(list, i + 1, right);
  39. }
  40. }
快排后的结果

 (list[i], list[j]) = (list[j], list[i]);为交换i和j的值

上面的排序算法正确的对每一个学生的成绩进行了排序,但是,成绩相同的两位同学的相对位置发生了变化,在排序前,小明排在小强的前面,但是排序后小强排到了小明的前面,有时这并不是我们想要的

2.优化后的排序算法

  1. public class Stu : IComparable<Stu>
  2. {
  3. public string Name;
  4. public int Score;
  5. int ID;
  6. public Stu(string name, int score, int id)
  7. {
  8. Name = name;
  9. Score = score;
  10. ID = id;
  11. }
  12. public int CompareTo(Stu other)
  13. {
  14. if (other.Score != Score) return other.Score - Score;
  15. return ID - other.ID;
  16. }
  17. }
  18. class Program
  19. {
  20. static void Main()
  21. {
  22. List<Stu> list = new List<Stu>() {
  23. new Stu("小明", 100, 1), new Stu("小红", 99, 2), new Stu("小刚", 98, 3),
  24. new Stu("小伟", 99, 4), new Stu("小强", 100, 5),
  25. };
  26. //list.Sort();因为Stu实现了IComparable接口,因此可以直接利用自带的排序方法
  27. QuickSort2(list, 0, list.Count - 1);
  28. }
  29. public static void QuickSort2(List<Stu> list, int left, int right)
  30. {
  31. if (left >= right) return;
  32. Stu pivot = list[left];
  33. int i = left + 1, j = right;
  34. while (i < j)
  35. {
  36. while (i < j && list[i].CompareTo(pivot) <= 0) ++i;
  37. while (i < j && list[j].CompareTo(pivot) > 0) --j;
  38. if (i < j)
  39. {
  40. (list[i], list[j]) = (list[j], list[i]);
  41. }
  42. }
  43. if (list[i].CompareTo(pivot) > 0) --i;
  44. (list[i], list[left]) = (list[left], list[i]);
  45. QuickSort2(list, left, i - 1);
  46. QuickSort2(list, i + 1, right);
  47. }
  48. }

 为了保证排序后相对顺序不变,我加入了一个新的字段ID,ID不会重复,排序的规则变成了以分数优先,其次再按ID进行排序,ID大的排在后面

整体的排序思路变为小于等于pivot的元素放在pivot的左边,大于pivot的元素放在右边,CompareTo用于比较两个元素的大小

为什么继承IComparable接口?

继承这个接口后,可以直接利用.net自带的排序方法进行排序,.net自带的方法在排序方面做了更多的优化,效率更高,可以省去自己再写排序的代码的时间。

CompareTo的返回值用于判断大小,如果返回正数,说明比传入的对象大,负数说明小于传入的对象

.net对排序做的优化:

  1. 在排序的元素较少的情况下,使用插入排序
  2. 在元素较多时使用内省排序,原理为快速排序+堆排序,这个排序算法首先从快速排序开始,当递归深度超过一定深度(深度为排序元素数量的对数值)后转为堆排序

如何减少快排的最差情况

当数组基本有序时,快排会退化成选择排序,时间复杂度变为O(n^2),因此使用插入排序更合适,插入排序在数组基本有序的情况下的时间复杂度为O(n)

冒泡排序做一下优化也可以在数组基本有序的情况下复杂度为O(n),做法为在每一趟排序结束后做一次判断,如果这一趟排序没有元素发生交换,说明数组已经有序,直接终止排序

如果一定要用快排,可以从以下两方面入手

  1. 避免数组有序
  2. 随机选择pivot点

避免数组有序可以使用洗牌算法在排序前先打乱数组,来减少最差情况

随机选取pivot点的实现可以参考文章顶部的相关资料

  1. public static void Shuffle(int[] nums)
  2. {
  3. Random rand = new Random();
  4. int n = nums.Length;
  5. for(int i=0;i<n; ++i)
  6. {
  7. int index=rand.Next(i, n);
  8. (nums[i], nums[index]) = (nums[index], nums[i]);
  9. }
  10. }

总结

本文介绍了快速排序在游戏领域的应用,展示了快速排序不稳定的特点会导致的问题,并提供解决方案,以及最大程度上减少快排退化成O(n^2)的可能性

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/369442
推荐阅读
相关标签
  

闽ICP备14008679号