c++ set 遍历_47. Set 是如何工作的(3) 遍历顺序是如何确定的?
Set 是无序容器,它的插入顺序与迭代(或者 print)输出的顺序不保证与插入顺序一致,与 Dict 类似的问题,Set 的输出顺序是如何决定的呢?
首先我们从 Set 的输出开始寻找蛛丝马迹,在 Dict 的研究中,我们知道对象的输出由 *_repr 函数实现,对于 SetObject 这个函数是 set_repr:
// Objects/setobject.c:579set_repr(PySetObject *so)
{// ··· ···// Set 转换为 Listkeys = PySequence_List((PyObject *)so);// ··· ···// 获得 List 的字符串listrepr = PyObject_Repr(keys);// 截掉 List 输出左右两端的 "[" 和 "]"tmp = PyUnicode_Substring(listrepr, 1, PyUnicode_GET_LENGTH(listrepr)-1);// ··· ···// 拼接输出// ··· ···return result;
}
Set 的输出经历了以下步骤:
- Set 转换为 List;
- List 转换为 String;
- 舍弃 List 输出左右两端的方括号,替换为小括号 ();
我们又一次见到了熟悉的面孔 PySequence_List,该函数的作用是将可迭代对象转换为 List 对象。Set 也是可迭代对象,具体的迭代操作由:
// Objects/setobject.c:867static PyObject *setiter_iternext(setiterobject *si){// ··· ···
}
该函数的代码表明 Set 对象的遍历,实际上是对 Set->table 的遍历,但是会忽略 NULL 和 dummy 元素。Set 的遍历顺序由其 table 中 entry 的实际排布决定。Set 元素的插入方式,可以参看上一节的介绍,其中包含了 Set 的 lookup 逻辑。
验证
下面以一个简单的例子验证我们的理解。首先创建一个空的 Set,命名为 a。为了方便,依然使用整数作为 Key,原因是整数的 hash 就是它们自身。
a = set()
此时 a 的 table 长度为初始值 8。依次插入 1~4,会分别插入 table[1~4]。当插入 5 的时候,5/8 > 3/5,table 会伸缩到 4 倍有效元素数量 5 * 4 = 20,在实际分配的时候,内存尺寸会对 2^n 向上取整, 实际伸缩 table 长度到 32。
a.update([1,2,3,4])
此时 table 的样子:
下面插入 5:
# resize the table firstly, then insert.
a.add(5)
经过 resize 的 table 看起来如此:
如果将 a 打印出来,输出的顺序应该就是 1~5,#0 处的 NULL 会被忽略掉。
print(a)
输出:
{1, 2, 3, 4, 5}
注意,此时 table 的长度已经是 32 了,下面插入一个较大的 Key = 32,对 32 求模刚好为 0,那么它会被插入到 #0:
a.add(32)
print(a)
上面的输出也可以印证这一点,输出:
{32, 1, 2, 3, 4, 5}
新插入的 32 打破了插入顺序和 Key 的大小顺序。 同理:
- 如果继续插入 Key = 39,它会出现在 #7 的位置;
- 再插入 Key = 70,则会出现在 #6 的位置;
我们通过代码来验证
a.add(39)
a.add(70)
print(a)
输出:
{32, 1, 2, 3, 4, 5, 70, 39}
哈! 与预期完全一致!
关注我,了解程序员的烧脑日常,还有开源 Python 教程。
c++ set 遍历_47. Set 是如何工作的(3) 遍历顺序是如何确定的?相关推荐
- 后序遍历的非递归算法python_二叉树后序遍历(递归与非递归)算法C语言实现...
二叉树后序遍历的实现思想是:从根节点出发,依次遍历各节点的左右子树,直到当前节点左右子树遍历完成后,才访问该节点元素. 图 1 二叉树 如图 1 中,对此二叉树进行后序遍历的操作过程为: 从根节点 1 ...
- 窗体内元素遍历-通用方法(DevExpress 中BarManager的遍历)
窗体内元素遍历-通用方法(DevExpress 中BarManager的遍历) 需求:WinForm窗体中对于各个元素进行遍历设置. 本身因为程序绝大部分功能已经开发完毕,但是权限控制没有追加,在后续 ...
- 遍历二叉树的各种操作(非递归遍历)
先使用先序的方法建立一棵二叉树,然后分别使用递归与非递归的方法实现前序.中序.后序遍历二叉树,并使用了两种方法来进行层次遍历二叉树,一种方法就是使用STL中的queue,另外一种方法就是定义了一个数组 ...
- 树形结构:迭代方式遍历树,宽度优先,先序遍历,中序遍历,后序遍历
迭代的方式处理树,就必须清楚你将要访问的顺序,对应的就是指针怎么走,你必须很清楚 树的宽度优先搜索,他是一层一层的访问,就搞不清楚怎么划分子问题了,但是你访问的顺序 你很清楚,那么就使用迭代的方式实现 ...
- 二叉树的层序遍历,前序遍历(递归,非递归),中序遍历(递归,非递归),后续遍历(递归,非递归)
文章目录 二叉树的层序遍历 前序遍历 递归版本 非递归版本 中序遍历 递归版本 非递归版本 后序遍历 递归版本 非递归版本 二叉树的层序遍历 void printTree(BinaryTree* ar ...
- 无向图的深度优先遍历非递归_LeetCode0429: N叉树的层序遍历
题目介绍 描述: 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右,逐层遍历). 例如,给定一个 3叉树 : 返回其层序遍历:[[1],[3,2,4],[5,6] ]说明:树的深度不会超过 ...
- python遍历树结构_python 数据结构与算法——树的遍历
1.广度优先遍历 2.深度优先遍历 先序遍历:把根放在最前面 中序遍历:把根放在中间 后序遍历:把根放在后面 # -*- coding: utf-8 -*- """ Cr ...
- 二叉树的遍历实验报告C语言,数据结构-二叉树的遍历(类C语言描写叙述)
遍历概念 所谓遍历(Traversal)是指沿着某条搜索路线.依次对树中每一个结点均做一次且仅做一次訪问.訪问结点所做的操作依赖于详细的应用问题. 遍历是二叉树上最重要的运算之中的一个,是二叉树上进行 ...
- 按照前序遍历创建二叉树及树的四种遍历方式
一.二叉树的介绍 二叉树的特点是二叉树的每个结点的度都不大于2,可以视为每个结点都有左孩子和右孩子.故二叉树结点的数据结构为 二.二叉树的特点 1.设根结点所在的层数为第1层,则第i层最多有个结点. ...
最新文章
- ajax基础学习笔记
- LeetCode 98验证二叉搜素树(中序遍历)99恢复二叉搜索树
- J2SE:Java环境搭建探究环境变量
- ORA-02290:违反检查约束条件(sys_c0011321)什么原因
- POJ 1915 经典马步 双向bfs
- 浅谈Borg/YARN/Mesos/Torca/Corona一类系统
- 数据结构:实验四 图的遍历
- linux mysql 开发_Linux64下mysql安装和开发
- 衣带渐宽终不悔,为伊消得人憔悴。
- Groupon新变种 LevelUp:折价券
- 工业革命4.0是光和算的革命,时代呼唤硬科技!
- C语言求1到100的和
- Spring 注解@Value详解
- 对Java的展望_优秀技能经验及对java学习展望
- 【电脑配置知识】显卡 GPU
- 智能车图像处理-阳光算法
- DS18B20测量温度液晶1602显示
- Apache Kafka - ConsumerInterceptor 实战 (1)
- 毕业四年后一次同学聚会-性格决定命运
- 偏微分方程简明教程第六章部分答案
热门文章
- TCP握手/挥手的过程分析
- Android之Fragment 真正的完全解析(上)
- java中hasnext的作用_java中Scanner的hasNext()的疑问
- php json error,PHP 7.3 中的 JSON 错误处理
- 我要3万取款机怎么取_7万的新宝骏RS-3怎么样?用车三个月后,车主说出了实话...
- 理科生浪漫起来,谁都顶不住!
- 快速入门深度学习,其实并不难!
- 5道谷歌面试题:即使是天才也要怀疑自己能力了(附答案)
- mysql 堆叠查询_SQL 注入方法 - 盲注、报错注入、UNION查询注入与堆叠注入
- java输入数据插入if_java编程,从键盘录入10个整数数据,将每次录入的数据按从小到大的顺序插入到数组中。...