游戏开发中常用的算法1(20道题一篇文章)

世界杯足彩 3683

一、快速排序算法

步骤1:选取一串数字中的中心轴

步骤2:将大于中心轴的数字放在右边

步骤3:将小于中心轴的数字放在左边

步骤4:分别对左右两个序列重复前三步操作

public class QuickSort : MonoBehaviour

{

private void Start()

{

int[] Nums = { 4, 3, 6, 1, 8, 0, 3, 2, 5, 7};

Sort(Nums, 0, 9);

for (int i = 0; i < 10; i++)

{

Debug.Log(Nums[i]);

}

}

void Sort(int[] nums,int left,int right)

{

//退出条件

if (left >= right)

return;

int i = left;

int j = right;

//中心元素取为第一个元素

int temp = nums[left];

while(i != j)

{

//从最右边的元素开始比较中心元素

while(i < j && nums[j] >= temp)

{

j--;

}

if(i < j )

{

nums[i] = nums[j];

}

while(i < j && nums[i] <= temp)

{

i++;

}

if(i < j)

{

nums[j] = nums[i];

}

}

nums[i] = temp;

Sort(nums, left, i - 1);

Sort(nums, i+1, right);

}

}

二、冒泡排序算法

步骤一、从数组的最左侧两个元素进行比较

步骤二、将较大的数向右移动,再进行比较

步骤三、直到将最大的数字放在最右边

步骤四、重复上述操作,不过这次比较数组的数量-1

public class BubbleSort : MonoBehaviour

{

private void Start()

{

int[] array = { 6, 5, 8, 7, 1, 2, 3, 5 };

Sort(array);

for (int i = 0; i < array.Length; i++)

{

Debug.Log(array[i]);

}

}

private void Sort(int[] array)

{

//进行i次排序,对数组内所有元素都进行比较

for (int i = 0; i < array.Length - 1; i++)

{

//对某一元素进行的相邻元素的比较,比较次数差i次

for(int j = 0; j < array.Length-1-i; j++)

{

if(array[j] > array[j+1])

{

int temp = array[j];

//如果左边的数字比右边的大,就把大的数字向右平移一位

array[j] = array[j + 1];

array[j + 1] = temp;

}

}

}

}

}

三、二分查找(要求数组顺序排列)

一、初始化三个序号,分别代表第一个,最后一个和中间序号

二、用中间序号的值和目标值进行对比,如果相等就返回

三、如果中间序号的值大于目标值,就向左缩小范围

四、如果中间序号的值小于目标值,就向右缩小范围

第一种实现:常规实现

public class BinarySearch : MonoBehaviour

{

private void Start()

{

int[] array = { 8, 11, 21, 28, 32, 43, 48, 56, 69, 72, 80, 94 };

Debug.Log(Search(array, 80));

}

private int Search(int[] array,int key)

{

var min = 0;

var max = array.Length - 1;

var mid = 0;

while(min <= max)

{

mid = (min + max) / 2;

if(array[mid] > key)

{

max = mid - 1;

}

else if(array[mid] < key)

{

min = mid + 1;

}

else if(array[mid] == key)

{

return mid;

}

}

return 0;

}

}

第二种实现:递归实现

Debug.Log(SearchTwo(array, 80,0,12));

private int SearchTwo(int[] array,int key,int low,int high)

{

if (low > high)

return -1;

var mid = (low + high) >> 1;

if (array[mid] > key)

{

return SearchTwo(array, key, low, mid - 1);

}

else if (array[mid] < key)

{

return SearchTwo(array, key, mid + 1, high);

}

else

return mid;

}

}

四、基于四叉树/八叉树的碰撞检测

五、随机寻路算法、跟踪算法、闪避算法(与跟踪算法相反)

DFS(Deep First Search)、BFS(Breadth Fitst Search)

六:A*寻路算法

A*主要是利用三个数值来计算最佳路径,分别是G代价、H代价、F代价

G:从某节点到开始节点的移动距离

H:从某节点到目标节点的估计移动距离,从任何节点迭代实际所需的距离大于或者等于H代价。

F:F代价等于G+H,F值越低,作为寻径选择就越有吸引力

我们的目标是简单的选择最低的F代价,不断的重复,直到我们的目标节点

代码部分可以见:

(1条消息) Unity A星(A Star/A*)寻路算法_unity寻路算法_九本才的博客-CSDN博客

现在有A*的寻路插件

七:B*寻路算法

理解B*可以把它想象成一个朝着目标前进的贪吃蛇,如果遇到障碍就会分裂成两条蛇,一左一右绕开障碍,只要有一条蛇碰到目标就结束寻路

优点:目标点在封闭空间内时,BStar效率优势明显

缺点:喜欢贴着墙走

八、Nav Mesh导航系统

NacigationMesh是一种数据结构,用于描述游戏世界的可行走表面

Navigation是Unity自带的导航,具备基本的Bake,NavMesh和NavMeshAgent等基本导航功能

新版中有NavMeshComponent,能够实现动态烘焙

步骤:

打开Navgation面板、

设置烘焙参数(Bake Agent)、

设置行走区域(设置为Navigation Static)、烘焙

角色添加寻路控制器(Nav Mesh Agent)、

挂在一个脚本到Player身上,告诉目标点即可

using UnityEngine;

using UnityEngine.AI;

public class Player : MonoBehaviour

{

private NavMeshAgent agent;

public Transform target;

void Start()

{

agent = GetComponent();

agent.destination = target.position;

}

}

九、数组中仅出现过一次的元素

方法一:使用位异或运算

仅针对数组中只出现一次的情况

使用位运算,最后只剩下没有重复的元素

using UnityEngine;

///

/// 某个只出现一次的数字

/// 思路:采用异或操作,相同为0,不同为1

/// a^a = 0; a^0 = a;

///

public class SingleNumber : MonoBehaviour

{

public int[] nums = { 1, 2, 3, 2, 1 };

private void Start()

{

SingleNumber1(nums);

}

public void SingleNumber1(int[] nums )

{

int result = 0;

for(int i = 0; i < nums.Length; i++)

{

//第一次异或操作完了就是第一个元素,然后第一个元素和第二个元素对比

//如果两个相同,返回就是0,如果不相同,

result ^= nums[i];

}

Debug.Log(result);

}

}

方法二:使用Set集合

HashSet具有去重性

使用!Add即可

///

/// 使用HashSet来解决,HashSet具有去重特性!

///

///

public void SingleNumber2(int[] nums)

{

HashSet hash = new HashSet();

for (int i = 0; i< nums.Length;i++)

{

if(!hash.Add(nums[i]))

{

hash.Remove(nums[i]);

}

}

foreach (var item in hash)

Debug.Log(item);

}

}

十、多数元素

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

方法一、排序后输出中间元素即可

public class Majority : MonoBehaviour

{

int[] nums = { 1, 2, 3, 4, 5, 6, 7, 2, 2, 2, 2, 2 };

private void Start()

{

Major1(nums);

Major2(nums);

}

///

/// 方法1:先排序,再输出一半中的元素

///

///

public void Major1(int [] nums)

{

Array.Sort(nums);

Debug.Log(nums[nums.Length/2]);

}

方法二、摩尔投票法

把第一个元素作为开始元素,如果紧接的两个元素不相同,count就减,如果相同,count就加,到最后还剩下的count就是最多的元素

///

/// 方法2:摩尔投票法

///

public void Major2(int[] nums)

{

int major = nums[0];

int count = 1;

for (int i = 1; i < nums.Length; i++)

{

//消除完了,就进行下一个

if(count == 0)

{

count++;

major = nums[i];

}

//跟后面的元素相同的话,这个元素数目就继续增加

else if(major == nums[i])

{

count++;

}

else

{

count--;

}

}

Debug.Log(major);

}

}

十一、合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

方法1:使用三目运算符

即:

x?y:z 表示如果表达式x为true,则返回y; 如果x为false,则返回z

是省略if{}else{}的简单形式。

using UnityEngine;

///

/// 合并两个有序数组

///

public class Merge : MonoBehaviour

{

int[] nums1 = { 1, 2, 3,0,0,0 };

int[] nums2 = { 2, 5, 6 };

private void Start()

{

MergeNums(nums1, 3, nums2, 3);

foreach (var item in nums1)

{

Debug.Log(item);

}

}

///

/// 合并有序数组方法1

///

///

///

///

///

public int[] MergeNums(int[] nums1,int m,int[] nums2,int n)

{

int i = m - 1;

int j = n - 1;

int end = m + n - 1;

while(j>=0)

{

nums1[end--] = (i >= 0 && nums1[i] > nums2[j]) ? nums1[i--] : nums2[j--];

}

return nums1;

}

}

方法二:使用官方API

Array.Copy:合并两个数组

Array.Sort:排序方法,由小及大

public void MegerNums2(int[] num1, int m ,int[] nums2, int n )

{

Array.Copy(nums2, 0, nums1, m, n);

Array.Sort(nums1);

}

十二、鸡蛋掉落

给你 k 枚相同的鸡蛋,并可以使用一栋从第 1 层到第 n 层共有 n 层楼的建筑。

已知存在楼层 f ,满足 0 <= f <= n ,任何从 高于 f 的楼层落下的鸡蛋都会碎,从 f 楼层或比它低的楼层落下的鸡蛋都不会破。

每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层 x 扔下(满足 1 <= x <= n)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中 重复使用 这枚鸡蛋。

请你计算并返回如果要确定 f 确切的值 的话,我们的 最小操作次数 是多少?