GameMaker8.0 :新手教程 Part 25 -数据结构-

分类栏目:gamemaker教程

387

GameMaker8.0 :新手教程 Part 25 -数据结构-

1、数据结构

数据结构(data structure)是计算机中存储、组织数据的方式,描述“数据”及其之间的“关系”。参考维基百科的定义,数组是一种最简单的数据结构。
数据结构内部会对数据之间的关系进行整理,排序,计算,因此选择正确合适的数据结构有助于提高程序效率。
数据结构种类繁多,GM8所提供的数据结构(不包含数组)一共有六种:堆栈(stack)、队列(queue)、列表(list)、配对(map)、优先队列 (priority queue)、栅格(grid)。

2、通用函数

下列函数适用于除栅格(grid)外的数据类型,请将函数中的xxx改为stack/queue/list/map/priority使用。
ds_xxx_create() 创建一个数据结构,返回它的索引。
ds_xxx_destroy(id) 销毁索引为id的数据结构。一旦你使用完,一定要销毁数据结构释放内存。(gird适用)
ds_xxx_clear(id) 清空索引为id的数据结构内所有数据。
ds_xxx_size(id) 返回索引为id的数据结构储存了多少个数据。
ds_xxx_empty(id) 返回索引为id的数据结构是否为空。
ds_xxx_copy(dest, src) 将索引为src的数据结构的数据拷贝到索引为dest的数据结构中,注意必须是同种数据结构。(grid适用)
ds_xxx_write(id) 将索引为id的数据结构转换为字符串,返回这个字符串。通常用于储存到文件中。(grid适用)
ds_xxx_read(id, str) 从字符串str中读取数据结构。与上面这个函数配对,用于从文件中读取数据结构。(grid适用)

3、堆栈

堆栈(stack)是一种“先入后出,后入先出”的数据结构。想象你要搬家了,你把自己的上百本书装进一个箱子里带走,当你到新家的时候,你要把书拿出来,你拿出来的第一本书,是不是你之前装入的最后一本书?而你拿出来的最后一本书,是不是你之前装入的第一本书?堆栈就是这么一种性质,当你向堆栈中加入数据时,数据会被放在顶层,当你要获取数据时,也只能获取顶层的数据。你必须要先移除顶层的数据,才能去访问下一个顶层的数据,并且数据一旦移除就会永久消失。
ds_stack_push(id, val) 向索引为id的堆栈顶层加入数据val。
ds_stack_pop(id) 获取索引为id的堆栈的顶层数据,并移除该顶层数据。顶层数据被移除后,次层数据会自动提升为顶层。
ds_stack_top(id) 获取索引为id的堆栈的顶层数据,但是不移除该顶层数据。当然,下次获取数据时,你会得到同一个数据。
去除通用函数后,堆栈就只有上述三个操作函数了。通常,堆栈并不适合开发者去使用,他更多地用在程序本身的优化上,比如函数的递归。所谓递归,就是函数的自我调用,在函数内部的代码中调用自己本身,并且使用了函数的返回值,或者两个函数之间互相调用。当然,这个调用必须要有一个if来控制结束,否则会无限调用。通常程序在处理递归时就会使用堆栈,每一次的函数调用都会占据一层堆栈,直到最后一层函数处理完毕,被移除,返回值交给倒数第二层函数,以此类推。

4、队列

队列(queue)与堆栈相反,是“先入先出,后入后出”的数据结构,向队列添加数据,会被置于队列底层,但是读取数据依然是从顶层开始的。因此,先被加入队列的数据就会被先处理,而后被加入队列的数据就后被处理。队列比堆栈更具有通用性,例如消息处理,通信等。
   ds_queue_enqueue(id, val) 向索引为id的队列底层加入数据val。
ds_queue_dequeue(id) 返回索引为id的队列顶层的数据,并且移除这个数据。
ds_queue_head(id) 返回索引为id的队列顶层的数据,但是不移除该数据。
ds_queue_tail(id) 返回索引为id的队列底层的数据,不移除且不能移除。
关于函数ds_queue_dequeue(id),GM8汉化文档翻译的是“返回叫作这个标识符的队列中最长的数值并移除它”,我找了一下原文,也写的是"Returns the value that is longest in the queue and removes it from the queue",之后又看了一下ds_queue_head(id)的原文描述,"Returns the value at the head of the queue, that is, the value that has been the longest in the queue (It does not remove it from the queue.)",可见,GM8中的"longest value"就是指的顶层数据,“最长的数值”纯属字面翻译,但是因为文化差异导致二者表达的意思完全不相同。

5、列表

列表(list)可以看做堆栈,队列和数组的功能结合体,列表允许在任意位置插入数据,允许读取任意位置的数据,同样也允许移除任意位置的数据。但是作为代价,列表所占用的内存比堆栈和队列要高出一大截。
ds_list_add(id, val) 向索引为id的列表的尾部加入数据val。
ds_list_insert(id, pos, val) 向索引为id的列表的指定位置加入数据val。注意,位置pos是从0开始的,下同。
ds_list_replace(id, pos, val) 将索引为id的列表的指定位置的数据替换为val。
ds_list_delete(id, pos) 删除索引为id的列表中指定位置的数据。
ds_list_find_index(id, val) 在索引为id的列表中搜索数据val,如果存在,则返回val的位置,如果不存在,则返回-1。
ds_list_find_value(id, pos) 返回索引为id的列表中位置pos的数据。
ds_list_sort(id, ascend) 将索引为id的列表排序,ascend为是否升序排序(false为降序排序)
ds_list_shuffle(id) 打乱索引为id的列表的数据顺序。
相比于其他数据结构,列表可以说是使用程度最高,灵活性最好的一种数据结构了。

6、配对

配对(map)可以看做对列表的功能扩充,在保留列表功能的情况下,允许用户自定义索引(可以是实数也可以是字符串)。通常在配对中,将自定义的索引称为键(key),配对数据结构通常也被叫做键值(key-value)数据结构。与列表面向小数据不同,配对通常都是面向大数据的管理。比如windows的注册表,就是十分典型的配对。
ds_map_add(id, key, val) 向索引为id的配对中添加数据val,这个数据的键是key。
ds_map_replace(id, key, val) 将索引为id的配对中键为key的数据替换为val。
ds_map_delete(id, key) 删除索引为id的配对中键为key的数据。如果一个键对应多个数据,只有一个会被移除。话虽这么说,但是一般不建议也不应该给不同的数据分配相同的索引。
ds_map_exists(id, key) 返回索引为id的配对中是否存在key这个键。
ds_map_find_value(id, key) 返回索引为id的配对中键为key的数据。
ds_map_find_previous(id, key) 返回在索引为id的配对中比key小的最大键,注意返回的是键不是值。如果你的一个配对中既有实数键,又有字符串键,那么在排序时,字母按A-Z从小到大,不区分大小写,并且字符串键比实数键大。
ds_map_find_next(id, key) 返回索引为id的配对中比key大的最小键。
ds_map_find_first(id) 返回索引为id的配对中最小的键。
ds_map_find_last(id) 返回索引为id的配对中最大的键。

7、优先队列

优先队列(priority list)与队列不同,不是以加入的时间顺序作为索引,而是以优先级作为索引。这种数据结构可以帮助你根据数据的重要程度来决定数据的处理顺序。
   ds_priority_add(id, val, prio) 向索引为id的优先队列中添加数据val,这个数据的优先级是prio。
ds_priority_change_priority(id, val, prio) 将索引为id的优先队列中数据val的优先级更改为prio。
ds_priority_find_priority(id, val) 返回索引为id的优先队列中数据val的优先级。
ds_priority_delete_value(id,val) 删除索引为id的优先队列中的数据val。
ds_priority_delete_min(id) 返回索引为id的优先队列中优先级最小的数值并移除它。
ds_priority_delete_max(id) 返回索引为id的优先队列中优先级最大的数值并移除它。
ds_priority_find_min(id)  返回索引为id的优先队列中优先级最小的数值但是不移除它。
ds_priority_find_max(id)  返回索引为id的优先队列中优先级最大的数值但是不移除它。
总的来说,优先队列的出场机会也并不多。

8、栅格

栅格(grid)可以看做列表与二维数组的组合体,它使用两个值来作为数据的索引,正因如此,栅格不能随随便便地改变其大小。
ds_grid_create(w, h) 创建一个宽为w,高为h的栅格。返回创建的栅格的索引。
ds_grid_resize(id, w, h) 改变索引为id的栅格的宽与高,保留栅格内对应位置的数据。
ds_grid_width(id) 返回索引为id的栅格的宽。
ds_grid_height(id) 返回索引为id的栅格的高。
ds_grid_clear(id, val) 清除索引为id的栅格的指定数值val。
ds_grid_set(id, x, y, val) 设置索引为id的栅格中(x, y)位置的数据。可以视作二维数组arr[x, y] = val,同样的,栅格的位置从0开始计数。
ds_grid_get(id, x, y) 返回索引为id的栅格中(x, y)位置的数据。
ds_grid_add(id, x, y, val) 将索引为id的栅格中(x, y)位置的数据与val相加并取代原本的数据。如果是字符串,则接在原字符串的后面。
ds_grid_multiply(id, x, y, val) 将索引为id的栅格中的(x, y)位置的数据与val相乘并取代原数据,仅当数据为实数时有效。
ds_grid_shuffle(id) 打乱索引为id的配对的数据顺序。
除此之外,栅格还有一个优点是可以提供范围操作。
ds_grid_set_region(id, x1, y1, x2, y2, val) 将索引为id的栅格中,左上角为(x1, y1)右下角为(x2, y2)的矩形范围内的数据全部设置为val。
ds_grid_add_region(id, x1, y1, x2, y2, val) 同上,只不过这个函数将其相加。
ds_grid_multiply_region(id, x1, y1, x2, y2, val) 同上,只不过这个函数将其相乘。
ds_grid_set_disk(id, xm, ym, r, val) 将索引为id的栅格中,以(xm, ym)为中心、r为半径的圆的所有数据设置为val。
ds_grid_add_disk(id, xm, ym, r, val) 同上,只不过这个函数将其相加。
ds_grid_multiply_disk(id, xm, ym,r, val) 同上,只不过这个函数将其相乘。
ds_grid_get_sum(id, x1, y1, x2, y2) 返回索引为id的栅格中,左上角为(x1, y1)右下角为(x2, y2)的矩形范围内数据的总和,仅当数据为数字才有效。
ds_grid_get_max(id, x1, y1, x2, y2) 同上,只不过这个函数返回最大的数据。
ds_grid_get_min(id, x1, y1, x2, y2) 同上,只不过这个函数返回最小的数据。
ds_grid_get_mean(id, x1, y1, x2, y2) 同上,只不过这个函数返回范围内数据的平均值。
ds_grid_get_disk_sum(id, xm, ym, r) 返回索引为id的栅格中,以(xm, ym)为中心、r为半径的圆的所有数据的总和。
ds_grid_get_disk_min(id, xm, ym, r) 同上,只不过这个函数返回最大的数据。
ds_grid_get_disk_max(id, xm, ym, r) 同上,只不过这个函数返回最小的数据。
ds_grid_get_disk_mean(id, xm, ym, r) 同上,只不过这个函数返回范围内数据的平均值。
ds_grid_value_exists(id, x1, y1, x2, y2, val) 返回索引为id的栅格中,左上角为(x1, y1)右下角为(x2, y2)的矩形范围内是否存在数据val。
ds_grid_value_x(id, x1, y1, x2, y2, val) 返回索引为id的栅格中,左上角为(x1, y1)右下角为(x2, y2)的矩形范围内数据val的x索引。
ds_grid_value_y(id, x1, y1, x2, y2, val) 返回索引为id的栅格中,左上角为(x1, y1)右下角为(x2, y2)的矩形范围内数据val的y索引。
ds_grid_value_disk_exists(id, xm, ym, r, val) 返回索引为id的栅格中,以(xm, ym)为中心、r为半径的圆内是否存在数据val。
ds_grid_value_disk_x(id, xm, ym, r, val) 返回索引为id的栅格中,以(xm, ym)为中心、r为半径的圆内数据val的x索引。
ds_grid_value_disk_y(id, xm, ym, r, val) 返回索引为id的栅格中,以(xm, ym)为中心、r为半径的圆内数据val的y索引。