以下列代码为例
- //终于给我搞清楚指针的指向究竟是怎么看的了
-
- // 按编号对职工记录进行递增排序
- void sortById(List* list) {
- Employee* p, * q, * tail = NULL;
- // tail 变量则是一个边界指针,初始值为 NULL。
-
- while (list->head->next != tail) // tail 变量则是一个边界指针,等于tail时,即终止循环
-
- //tail只会不断向前靠,一旦tail为初始数据指针即排序完毕
- {
- p = list->head;//记录头结点,也就是链表位置的指针
- q = p->next;//记录初始起始数据指针,便于后面交换数据
- while (q->next != tail) {
- if (q->id > q->next->id) {
- p->next = q->next;
- //意思是p的头结点的下一个位置改为q->next,也就是直接连接了下一个最小的节点
-
- q->next = q->next->next;
- //同理,q的下一个节点,即下一个位置的连接为q的下一个的下一个节点的位置
- //也就是直接跳过了中间的q->next
- // 这里的意思是直接q节点直接跳过q->next,链接q->next->next的意思
-
- //你记住,在左边,最后一个next永远都是指它的下一个位置是什么的意思
- // 也就是与哪个节点连接的意思
- //而如果前面有多的next,才是看作一个整体,
- // 如q->next->next,
- //可看成(q->next)->next,即q的下一个节点的下一个位置,即链接的位置是哪?
-
-
- //而如果在右边,那么next的意思那就全都是看作一起,也就是一个整体
- //直接把右边的指针看作成一整块,而不是分开来。
- /* 很简单,代码从来都是左边操作,右边赋值的*/
-
-
- p->next->next = q;
- /* 这个就很经典了,意思是
- (p->next)->next*/
- //即p->next这个整体的下一个位置,链接何处
-
-
-
- q = p->next;
- /* q重新指向为p->next这个位置*/
- //更新p的指针位置,即更新交换后的起始数据指针
- }
- p = p->next;
- q = q->next;
- //第一次循环的时候,已经将头指针和最小的节点给确认了
- //所以前两个点可以不用管了,直接往下与新的节点比较就好
- }
- tail = q;
- //当内循环退出时,表示当前轮次的排序已完成。将 tail 设为最后一次交换的节点 q,相当于缩小了待排序的范围。
-
- //就是冒泡排序的道理一样的,最后的数据一定是最大的,每一次排序完后,最后的位置是不用动的,
- //而前面的数据很可能还要反复地交换,tail就是每一次标记每次循环中最大的数据,一旦遇见直接跳出排序即可
-
- }
- printf("按编号排序已完成。\n");
- }
- //理解误区
-
- //指针的next本质上不是替换,而是位置的确认!
- //你记住,next无论如何都是指当前的值的下一个位置指向哪里
- //是指向哪里 ,也就是包含了链接的意思,同时又确认了当前指针的下一个位置是什么
- //而不是替换值的大小!
- //你记住,链表指向的意思是,当前指针的前一个节点,或者下一个节点是什么,是连接也是存储不同的值
- //不要把指针和next等同于一个单位看,它还包括了链表之间的连接关系!
-
- //你该关注的是什么,不是next和pre,而是最原始的指针如p,q
- //你要关注的是目前p,q这样的指针的具体动向在哪,有没有改变,如果改变了他们的指向也会变得不同
- //如果没变,那么p,q永远都是在同一个位置!
- //关注原始指针!
-
- //同时还有很重要的一点,就是你一定要考虑清楚,指针究竟有没有改动,以及下一个位置究竟是哪
- //都是前后文,自己要注意和看清楚位置究竟是哪,然后,前面自己有改动的地方也要知道
- //总的来说就是你一定要清楚自己指针指向的最新位置是哪,前面的可以不考虑
- //但当前指向的最新位置一定要清楚!
-
- // 按部门号对职工记录进行递增排序,若部门号相同,则按职工编号递增排序