0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用迭代器如何实现指针前移或后移

UtFs_Zlgmcu7890 来源:互联网 作者:佚名 2017-09-27 14:06 次阅读

近日周立功教授公开了数年的心血之作《程序设计与数据结构》,电子版已无偿性分享到电子工程师与高校群体下载,经周立功教授授权,特对本书内容进行连载。

>>>>1.1.1 算法接口

由于使用迭代器可以轻松地实现指针的前移或后移因此可以使用迭代器接口实现冒泡排序算法。其函数原型为

void iter_sort(iterator_if_t *p_if, iterator_t begin, iterator_t end, compare_t compare, swap_t swap) ;

其中,p_if表示算法使用的迭代器接口。begin与end是一对迭代器,表示算法的操作范围,但不一定是容器的首尾迭代器,因此算法可以处理任何范围的数据。为了判定范围的有效性,习惯采用前闭后开范围表示法,即使用begin和end表示的范围为[begin,end),表示范围涵盖bigen到end(不含end)之间的所有元素。当begin==end时,上述所表现的便是一个空范围。

compare同样也是比较函数,但比较的类型发生了变化,用于比较两个迭代器所对应的值。其类型compare_t定义如下:

typedef int (*compare_t)(iterator_t it1, iterator_t it2);

swap函数用于交换两个迭代器所对应的数据,其类型swap_t定义如下:

typedef void (*swap_t)(iterator_t it1, iterator_t it2);

由此可见,接口中只有迭代器,根本没有容器的踪影,从而做到了容器与冒泡排序算法彻底分离,基于迭代器的冒泡排序算法详见程序清单3.56

程序清单3.56冒泡排序算法函数

1 void iter_sort(iterator_if_t *p_if, iterator_t begin, iterator_t end, compare_t compare, swap_t swap)

2 {

3 int flag = 1; // flag = 1,表示指针的内容未交换

4 iterator_t it1 = begin; // it1指向数组变量的首元素

5 iterator_t it2 = end;

6

7 iterator_t it_next; // pNext指向p1所指向的元素的下一个元素

8 if (begin == end) { //没有需要算法处理的迭代器

9 return;

10 }

11 iterator_prev(p_if, &it2); // it2指向需要排序的最后一个元素

12 while (it2 != begin){

13 it1 = begin;

14 flag = 1;

15 while(it1 != it2){

16 it_next = it1; //暂存

17 iterator_next(p_if, &it_next); // it_next为 it1 的下一个元素

18 if(compare(it1, it_next) > 0){

19 swap(it1, it_next); //交换内容

20 flag = 0; // flag = 0,表示指针的内容已交换

21 }

22 it1 = it_next; // it1的下一个元素

23 }

24 if(flag) return; //没有交换,表示已经有序,则直接返回

25 iterator_prev(p_if, &it2); // it2向前移

26 }

27 }

下面以一个简单的例子来测试验证基于迭代器的冒泡排序算法,详见程序清单3.57。将整数存放到双向链表中,首先将5、4、3、2、1分别加在链表的尾部,接着调用dlist_foreach()遍历链表,看是否符合预期,然后再调用算法库的iter_sort()排序。当排序完毕后链表的元素应该是从小到大排列的,再次调用算法库的dilst_foreach()遍历链表,看是否符合预期。

程序清单3.57使用双向链表、算法和迭代器

1 #include

2 #include "iterator.h"

3

4 typedef struct _dlist_int{

5 dlist_node_t node; //包含链表结点

6 int data; // int类型数据

7 }dlist_int_t;

8

9 int list_node_process(void *p_arg, dlist_node_t *p_node)

10 {

11 printf("%d ", ((dlist_int_t *)p_node) -> data);

12 return 0;

13 }

14

15 static int __compare(iterator_t it1, iterator_t it2)

16 {

17 return ((dlist_int_t *)it1) -> data - ((dlist_int_t *)it2) -> data;

18 }

19

20 static void __swap(iterator_t it1, iterator_t it2)

21 {

22 int data = ((dlist_int_t *)it2) -> data;

23 ((dlist_int_t *)it2) -> data = ((dlist_int_t *)it1) -> data;

24 ((dlist_int_t *)it1) -> data = data;

25 }

26

27 int main(int argc, char *argv[])

28 {

29 iterator_if_t iterator_if;

30 dlist_head_t head; //定义链表头结点

31 dlist_int_t node[5]; //定义5个结点空间

32 int i;

33

34 dlist_init(&head);

35

36 for (i = 0; i < 5; i++) {                           // 将5个结点添加至链表尾部

37 node[i].data = 5 - i; //使值的顺序为 5 ~ 1

38 dlist_add_tail(&head, &(node[i].node));

39 }

40 dlist_iterator_if_get(&iterator_if);

41

42 printf("\nBefore bubble sort:\n");

43 dlist_foreach (&head, list_node_process, NULL); //打印排序前的情况

44

45 iter_sort(&iterator_if, dlist_begin_get(&head), dlist_end_get(&head),__compare, __swap);

46

47 printf("\nAfter bubble sort:\n");

48 dlist_foreach (&head, list_node_process, NULL); //打印排序后的情况

49 return 0;

50 }

在这里,使用了dlist_foreach()遍历函数,既然通过迭代器能够实现冒泡排序,那么也能通过迭代器实现简单的遍历算法,此时遍历算法与具体容器无关。遍历函数的原型如下

void iter_foreach(iterator_if_t *p_if, iterator_t begin, iterator_t end, visit_t visit, void *p_arg);

其中,p_if表示算法使用的迭代器接口,begin与end表示算法需要处理的迭代器范围,visit是用户自定义的遍历迭代器的函数。其类型visit_t定义如下:

typedef int (*visit_t)(void *p_arg, iterator_t it);

visit_t参数p_arg指针和it迭代器其返回值为int类型的函数指针。每遍历一个结点均会调用visit指向的函数,传递给p_arg的值即为用户参数,其值为iter_foreach()函数的p_arg参数,p_arg的值完全是由用户决定的,传递给it迭代器的值即为指向当前遍历的迭代器iter_foreach()函数的实现详见程序清单3.58

程序清单3.58遍历算法函数

1 void iter_foreach(iterator_if_t *p_if, iterator_t begin, iterator_t end, visit_t visit, void *p_arg)

2 {

3 iterator_t it = begin;

4 while(it != end){

5 if (visit(p_arg, it) < 0) {                        // 若返回值为负值表明用户终止了遍历

6 return;

7 }

8 iterator_next(p_if, &it); //让迭代器向后移动

9 }

10 }

现在可以将程序清单3.57的第43行和第48行中的dlist_foreach()函数修改为使用iter_foreach()函数看能否得到相同的效果

如果将数据保存在数组变量中,那么将如何使用已有的冒泡排序算法呢?由于数组也是容器,因此只要实现基于数组的迭代器即可,详见程序清单3.59

程序清单3.59使用数组实现迭代器接口

1 typedef int element_type_t;

2

3 static void __array_iterator_next(iterator_t *p_iter)

4 {

5 (*(element_type_t **)(p_iter))++; //让迭代器指向下一个数据

6 }

7

8 static void __array_iterator_prev(iterator_t *p_iter)

9 {

10 (*(element_type_t **)(p_iter))--; //让迭代器指向前一个数据

11 }

12

13 void array_iterator_if_get(iterator_if_t *p_if)

14 {

15 iterator_if_init(p_if, __array_iterator_next, __array_iterator_prev);

16 }

基于新的迭代器同样可以直接使用冒泡排序算法实现排序,详见程序清单3.60

程序清单3.60使用数组、算法和迭代器

1 #include

2 #include "iterator.h"

3

4 static int __visit(void *p_arg, iterator_t it)

5 {

6 printf("%d ", *(int *)it);

7 return 0;

8 }

9

10 static int __compare(iterator_t it1, iterator_t it2)

11 {

12 return *(int *)it1 - *(int *)it2;

13 }

14

15 static void __swap(iterator_t it1, iterator_t it2)

16 {

17 int data = *(int *)it2;

18 *(int *)it2 = *(int *)it1;

19 *(int *)it1 = data;

20 }

21

22 int main(int argc, char *argv[])

23 {

24 iterator_if_t iterator_if;

25 int a[] = {5, 3, 2, 4, 1};

26 array_iterator_if_get(&iterator_if);

27

28 printf("\nBefore bubble sort:\n");

29 iter_foreach(&iterator_if, a, a + 5, __visit, NULL);

30

31 iter_sort(&iterator_if, a, a + 5, __compare, __swap);

32

33 printf("\nAfter bubble sort:\n");

34 iter_foreach(&iterator_if, a, a + 5, __visit, NULL);

35 return 0;

36 }

由此可见,通过迭代器冒泡排序算法也得到了复用。如果算法库里有几百个函数,那么只要实现迭代器接口的2个函数即可,从而达到复用代码的目的。显然,迭代器是一种更灵活的遍历行为,它可以按任意顺序访问容器中的元素,而且不会暴露容器的内部结构。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4599

    浏览量

    92618
  • 指针
    +关注

    关注

    1

    文章

    479

    浏览量

    70506
  • 周立功
    +关注

    关注

    38

    文章

    130

    浏览量

    37578
  • 迭代器
    +关注

    关注

    0

    文章

    43

    浏览量

    4302

原文标题:周立功:迭代器——算法的接口

文章出处:【微信号:Zlgmcu7890,微信公众号:周立功单片机】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Python高级特性:迭代切片的应用

    在前两篇关于 Python 切片的文章中,我们学习了切片的基础用法、高级用法、使用误区,以及自定义对象如何实现切片用法(相关链接见文末)。本文是切片系列的第三篇,主要内容是迭代切片。 迭代
    发表于 11-29 10:11 655次阅读

    labview迭代实现方法

    请问一下,那位高手知道labview怎样实现迭代!!?
    发表于 03-27 14:00

    请问迭代实现原理是什么?

    什么是集合框架?LIST接口的实际应用?迭代实现原理是什么?
    发表于 11-04 09:45

    阻容相桥触发电路是如何实现相的

    阻容相桥触发电路是如何实现相的?单稳态电路的输出脉冲宽度取决于什么?什么是电阻测量法?直接耦合放大电路的特点是什么?
    发表于 08-19 07:54

    什么是void指针?void指针有何功能

    一般被称为通用指针叫泛指针。它是C语言关于纯粹地址的一种约定。当某个指针是void型指针时,所指向的对象不属于任何类型。 因为void
    发表于 02-21 06:01

    python迭代

    确的方法,还是应该使用 for 循环。3. 可迭代协议可迭代对象内部是如何实现在你对其进行 for 循环时,可以一个一个元素的返回出来呢?这就要谈到迭代
    发表于 02-24 15:42

    OpenHarmony中的HDF单链表及其迭代

    of it. */struct HdfSListNode *HdfSListIteratorNext(struct HdfSListIterator *iterator);迭代实现考虑对于本文所描述的单链表
    发表于 08-30 10:31

    OpenHarmony中的HDF单链表及其迭代

    */structHdfSListNode*HdfSListIteratorNext(structHdfSListIterator*iterator);迭代实现考虑对于本文所描述的单链表迭代
    发表于 09-05 11:38

    人工智能抗疫 AI技术实现了筛查的时间窗口

    人工智能(AI)在本次新冠肺炎疫情的防控中得到了实际应用,涵盖了辅助诊断、影像分析、药物研发、体温检测、医疗机器人等多个AI+医疗领域。尤其是在主战场AI医学影像方面,AI技术实现了筛查的时间窗口
    发表于 02-27 10:42 735次阅读

    理解函数指针、函数指针数组、函数指针数组的指针

    理解函数指针、函数指针数组、函数指针数组的指针
    的头像 发表于 06-29 15:38 1.5w次阅读
    理解函数<b class='flag-5'>指针</b>、函数<b class='flag-5'>指针</b>数组、函数<b class='flag-5'>指针</b>数组的<b class='flag-5'>指针</b>

    【C和指针指针

    指针的概念:说的实用一点,指针就是地址。包括对指针的各种操作,就是对地址和变量之间的互相转换等操作(个人理解);地址的概念:计算机的内存都是由0和1组成的。由于0和1只能表示两种情况。所以在使用时
    发表于 01-13 15:51 1次下载
    【C和<b class='flag-5'>指针</b>】<b class='flag-5'>指针</b>

    什么是迭代

    对于int型数组除了用下标访问,还可以通过指针访问,实际上迭代就是对指针进行了封装。
    的头像 发表于 02-27 15:55 1786次阅读
    什么是<b class='flag-5'>迭代</b><b class='flag-5'>器</b>?

    Python中的迭代介绍 迭代在scoreboard中的应用有哪些?

    Iterator Design Pattern: 对容器 (聚合类,集合数据等) 的遍历操作从容器中拆分出来,放到迭代中,实现迭代操作的解耦。
    的头像 发表于 08-08 09:41 577次阅读
    Python中的<b class='flag-5'>迭代</b><b class='flag-5'>器</b>介绍 <b class='flag-5'>迭代</b><b class='flag-5'>器</b>在scoreboard中的应用有哪些?

    C++智能指针的底层实现原理

    C++智能指针的头文件: #include 1. shared_ptr: 智能指针从本质上来说是一个模板类,用类实现指针对象的管理。 template class shared_pt
    的头像 发表于 11-09 14:32 703次阅读
    C++智能<b class='flag-5'>指针</b>的底层<b class='flag-5'>实现</b>原理

    从概念到应用 终于有人把式无人叉车讲明白了 赶紧收藏

    ,又称无人驾驶式叉车式叉车AGV,是一种能够自主导航、装卸、堆垛和短距离运输成件托盘货物的智能设备。其特点主要包括:  货叉
    的头像 发表于 08-22 11:13 284次阅读
    从概念到应用 终于有人把<b class='flag-5'>前</b><b class='flag-5'>移</b>式无人叉车讲明白了 赶紧收藏