对于链表中数据节点的排序,指的是按照数据域中的某一属性进行排序运算。可以是顺序插入排序实现,在有序的序列中,插入需要排序的元素。
基础代码:
/* 结点数据类型的构造 */
typedef int data_t;
/* 整个结点数据类型: */
typedef struct node {
data_t data; /* 当前结点数据域:存储当前结点的数据 */
struct node *next; /* 当前结点指针域:存储下一个结点空间的起始地址 */
} node_t;
/* 链表的初始化 */
node_t *CreateLinkList(void)
{
node_t *head;
/* 开辟头结点存储空间 */
head = malloc(sizeof(node_t));
if (head == NULL)
return head;
memset(head, 0, sizeof(node_t)); //memset函数功能:将指针变量s所指向的前n个字节的内存单元用一个“整数”c替换,可以为任何数据类型的数据进行初始化。
head->next = NULL; /* 设置头结点指针域为NULL,表示没有后继结点 */
return head;
}
/* 链表的排序 */
void SortLinkList(node_t *head)
{
node_t *p;
node_t *q;
node_t *r;
/* 判断链表是否为空表:空表直接结束 */
if (head->next == NULL)
return;
p = head->next->next; /* 第0个有效数据结点作为有效序列,从第1个有效数据结点开始做顺序插入排序 */
head->next->next = NULL;
/* 从第1个结点开始循环遍历,并做顺序插入 */
while(p != NULL) {
q = p; /* 遍历需要排序的结点p赋值给运算结点q */
p = p->next; /* 遍历到下一个结点 */
/* 循环找到需要插入结点位置的前一个结点 */
r = head;
while(r->next != NULL) { /* r的下一个结点是否存在,r->next == NULL说明r为有效链表的最后一个结点 */
if (r->next->data > q->data) /* 下一个结点数据 > 大于插入结点的数据,说明当前结点为插入结点大的前一个结点 */
break;
r = r->next;
}
/* 在r结点后插入待排序结点q */
q->next = r->next;
r->next = q;
}
}
图形解释:
假设最开始是一个带头结点,有4个结点的链表
node_t *p;
node_t *q;
node_t *r;
if (head->next == NULL)
return;
p = head->next->next;
head->next->next = NULL;
定义了三个指针p、q、r;p = head->next->next 这条语句表示p指针指向第2个结点,head->next->next = NULL 然后把第二个结点的指针域置为NULL,q、r指针暂时还没有指向。
while(p != NULL)
{
q = p;
p = p->next;
r = head;
while(r->next != NULL)
{
if (r->next->data > q->data)
break;
r = r->next;
}
q->next = r->next;
r->next = q;
}
第一次进入第一个while,由于p不为空,进入循环
q = p; q指针指向第2个结点
p = p->next; p指针指向第3个结点
r = head; r指针指向头结点
第一次进入第二个while,由于r->next不为空,进入循环。
if (r->next->data > q->data) 第1个结点的数据大于第2个结点的数据,执行break,跳出第二个while循环。
q->next = r->next; q指针指向的第2个结点的指针域指向r指针指向的下一个结点,也就是第1个结点
r->next = q; r指针指向的头结点的指针域指向q指针指向的第2个结点
第二次进入第一个while,由于p不为空,进入循环
q = p; q指针指向第3个结点
p = p->next; p指针指向第4个结点,也就是尾结点
r = head; r指针指向头结点
第二次进入第二个while,由于r->next不为空,进入循环。
if (r->next->data > q->data) 第2个结点的数据大于第3个结点的数据,执行break,跳出第二个while循环。
q->next = r->next; q指针指向的第3个结点的指针域指向r指针指向的下一个结点,也就是第2个结点
r->next = q; r指针指向的头结点的指针域指向q指针指向的第3个结点
第三次进入第一个while,由于p不为空,进入循环
q = p; q指针指向第4个结点,也就是尾结点
p = p->next; p指针指向NULL
r = head; r指针指向头结点
第三次进入第二个while,由于r->next不为空,进入循环。
if (r->next->data > q->data) 第3个结点的数据小于第4个结点的数据,执行r = r->next 语句,然后继续进行循环,最后经过第3个结点,第2个结点,最后到第1个结点,然后判断 r->next 的时候为NULL,则不在进入第二个while循环,直接执行后面的两条语句
q->next = r->next; q指针指向的第4个结点的指针域指向r指针指向的第1个结点的下一个结点,因为为NULL,所以q->next = NULL;
r->next = q; r指针指向的第1个结点的指针域指向q指针指向的第4个结点
最后p为空,则跳出循环,程序执行完毕。最后就实现了带头结点的非循环单项链表的排序,采用的是升序排列。