遍历链表,代码如下:
void transverse(node *p) { int n = 0; while (p!=NULL) { printf("node%d value is %d\n", n, p->item); n++; p = p->next; } }
代码思想是从链表头开始,只要结点指针p所指向的结点不是空结点,就输出p所指向结点的内容,然后将p指针往后移一个结点。
链表升序排序,代码如下:
node* sort_link_list(node *p) { node *ndp = p; node *ndpp = p; node *head = p; int num = 0; while (ndp != NULL)//1、获得链表结点个数 { printf("node%d value is %d\n", num, ndp->item); ndp = ndp->next; num++; } for (int i = 0; i < num - 1; i++) { ndp = head; ndpp = head; for (int j = 0; j < num - 1 - i; j++) { if (ndp->item>ndp->next->item) { if (j == 0) { head = ndp->next; ndpp = ndp->next; } node* temp; temp = ndp->next->next; //2、交换两个结点在链表中的位置 ndpp->next = ndp->next; ndpp = ndpp->next; ndp->next->next = ndp; ndp->next = temp; } else { ndp = ndp->next; if (j != 0) { ndpp = ndpp->next; } } } } return head; }
这段代码用的排序算法是冒泡排序法。对链表结点进行排序,相对于数组排序要复杂得多,因为对数组可以直接访问其中的任何一个元素,而链表想要找到其中任何位置的结点都必须得从链表头开始,遍历该结点前所有链表结点一直到所要查找位置的结点。但是不管怎样,归根结底算法的思想都是冒泡排序,即每次对比相邻的两个结点的大小,大的结点往右移,小的往左移。第一次循环找到最大的结点,将其移到了链表的最右(最末尾),第二次循环找到第二大的结点,将其移到链表最右往回一个结点的位置,一直到最后一次循环,找到最小的结点,将其移到链表的最左的位置。
假设现在链表如下:
(图1)
链表有6个结点,首结点数据是2。在只有链表头的情况下,首先我得知道链表里有几个结点,所以我得遍历一遍链表。知道链表结点个数后,就可以知道需要循环几次才能完成排序。根据冒泡法,外层循环次数是num-1次,即5次;内层循环是num-1-i。进入for循环,ndp为指向当前结点的指针,ndpp为指向当前结点的前一个结点的指针,在初始时两者都初始化为指向链表头,如下所示。
(图2)
第一次外循环,i=0。进入内循环,j=0。首先对比第一个结点与第二个结点,2小于6,ndp指向下一个结点,即6,ndpp不变,仍然指向2。指针指向如下:
(图3)
第二轮内循环,j=1,ndp指向第二个结点,6>4,第二个结点的值大于第三个结点的值(ndp->item>ndp->next->item),故需要交换第二个结点和第三个结点,交换的思想大致是将第一个结点的next指针指向第三个结点,将第三个结点next指针指向第二个结点,将第二个指针结点指向第四个结点,如下所示。
(图4)
变化一下,上面的图实际如下。
(图5)
可以看到,虽然只是调整两个结点的位置,但是需要对三个结点的next进行操作,这也是为什么程序里需要有ndpp指针,因为ndp指针指向当前结点(值为6),但是交换结点需要用到当前结点的上一个结点(值为2)的next指针,因此需要一个ndpp指针指向当前结点的前一个结点。交换结点过程具体如下,回到图3,首先保存第四个结点的地址到一个暂存变量temp,temp = ndp->next->next。
(图6)
将第一个结点(值为2)的next指针指向第三个结点,ndpp->next = ndp->next。此时链表变成这样:
(图7)
然后将ndpp往后移一个位置,ndpp = ndpp->next,指向第二个结点,虽然此时值为6的结点的next指针尚未改变,但是此时第二个结点应该是值为4的那个结点了。
(图8)
再将值为4的结点的next指针指向值为6的结点,ndp->next->next = ndp。
(图9)
最后将值为6结点的next指针指向值为3的结点,ndp->next = temp;这样就完成值为6和值为4两个结点在链表位置的交换,同时ndp指针和ndpp指针在链表位置均往后移了一位。
(图10)
对上图进行整理,链表此时如下:
(图11)
后面的交换都是类似的操作,就不细述了。
对链表倒序输出,代码如下:
void reverse(node *p) { if (p == NULL) return; else { reverse(p->next); } printf("%d\n",p->item); }
代码思想是利用递归法,一直搜索到链表尾,然后返回,一路输出结点的值。
输出链表倒数第n个结点的值,代码如下:
void backward_n(node *p, int n) { int num = 0, i = 1; node *head = p; while (p != NULL) { num++; p = p->next; } p = head; while (i < num - n + 1) { i++; p = p->next; } printf("backward n node value is %d\n", p->item); }
代码思想为先计算链表有几个结点,假设有N个结点,那么倒数第n个结点就是顺数第N-n+1个结点,所以只要重新从链表头开始,搜索到第N-n+1个结点,输出其值即可。
主函数如下:
#include <stdio.h> typedef struct NODE{ int item; struct NODE *next; }node; node nd1, nd2, nd3, nd4, nd5, nd6, nd7; void main() { nd1.item = 10; nd2.item = 8; nd3.item = 6; nd4.item = 5; nd5.item = 4; nd6.item = 3; nd7.item = 2; nd1.next = &nd2; nd2.next = &nd3; nd3.next = &nd4; nd4.next = &nd5; nd5.next = &nd6; nd6.next = &nd7; nd7.next = NULL; node *ndp = &nd1; node *ndpp = &nd1; node *head = ndp; head = sort_link_list(head); transverse(head); //reverse(&nd1); }