思路:插入排序就是从第一个数开始排,第一个数就是有序的,后面第二个数和他比较,如果比他大,这两个数就是有序序列,往下遍历,如果比他小则从有序序列的头开始遍历,找到他的位置,插入。
在链表中为了实现这个排序,需要两个指针,一个指针p指向当前需要排的数,一个指针r作为他的前继,p与r比较,如果有序,p和r都直接往下遍历;如果无序则在前面的有序序列找到p的位置。
r从头结点开始,作为一个有序序列,p从第二个数开始比较
这里引入了一个虚拟结点q插在链表的表头,这样可以通过q的下一个结点的值与p进行比较,找到位置之后p可以直接插在p>next,这样就不需要再引入一个前继指针来找位置了。
之前一直发现链表交换会断开,后面才明白是因为交换结点之后头结点没有更新,所以他一直都指向第一个数。要修改这个问题,只要在每次交换之后检查头结点有没有被交换,被交换就更新头结点。
#include <stdio.h>
#include <malloc.h>
struct cell {//单链表结点结构体定义
int x;
struct cell* next;
};
struct cell* build(void) {//新建单链表,并将建好的单链表首结点地址返回
struct cell* head, * tmp, * p;
head = tmp = p = NULL;
int n;
while(scanf("%d",&n),n!=0)
{
p=(struct cell*)malloc(sizeof(struct cell));
p->x=n;
p->next=NULL;
if(head==NULL)//必须有这个判断,否则head还是原来的指针空间,没有指向结构体的空间,会出错,与链表断裂
{
head=p;
tmp=p;
}else{
tmp->next=p;
tmp=p;
}
}
return head;//返回单链表头
}
struct cell * sort(struct cell* head) {//递增排序链表,head是单链表首结点指针
struct cell* p, * p0, * r, * r0, * q;
p = p0 = r = r0 = q = NULL;
if(head==NULL)
return NULL;
q=(struct cell*)malloc(sizeof(struct cell));//加一个虚拟结点,方便排序
q->x=0;q->next=head;
p=head->next;
r=head;
while(p!=NULL)//p是当前需要排序的结点
{
if(r->x<p->x)//有序不需要交换,向下遍历
{r=p;
p=p->next;
}else
{
p0=q;
while(p0->next->x<p->x)
p0=p0->next;//找位置
r->next=p->next;//交换结点,先断后面的指针,再变前面
p->next=p0->next;
p0->next=p;
if(p=q->next)//如果p换到了头的位置
{
head=p;//更新头结点
p=r->next;//更新p
}else p=r->next;
}
}
return head;
}
void print(struct cell* head) {//打印整个单链表,head是单链表首结点指针
struct cell*p;
p=head;
while(p!=NULL)
{if(p->next==NULL)
{
printf("%d",p->x);
p=p->next;//老是忘记这个,如果没有这条语句就会无限循环,因为p不会==NULL;
}
else
{printf("%d ",p->x);
p=p->next;
}
}
}
void release(struct cell* head) {//释放单链表空间,head是单链表首结点指针
struct cell*p;
p=head;
while(head!=NULL)
{
p=head->next;
free(head);
head=p;
}
}
int main(void) {
struct cell* head;
head= build();
if (head != NULL) {
head = sort(head);
print(head);
}else
printf("NULL");
release(head);
return 0;
}
头结点很重要,一定要注意他的变化