您的位置:首页 > 其它

链表基本排序(逆置、冒泡、选择、插入)

2017-07-25 21:47 267 查看


单链表的反序

单向链表的反序图示:
                ---->[1]---->[2]---->[3]...---->
---->[NULL](原链表)

               

              1->next  2->next  3->next   n->next  head

                head   1->next  2->next  3->next   n->next

                [NULL]<----[1]<----[2]<----[3]<----...
<----(反序后的链表)

反序也就是头指针指向最后一个结点,然后最后一个结点指向倒数第二个结点,以此类推,直到第一个结点指向空指针

           实现方法:

(1)首先考虑如何能实现整个反序过程,很容易想到必须有一个指针P1进行读取每个结点,将每个结点的指向改变,还要有一个指针P2来存储每次要更改的那个指向,然后还要有一个临时指针P用来存储需要更改的指针的下一个指针。

(2)先将各个功能指针初始化,P1指向头指针,P2指向空指针;

(3)先用P把下一个要截取的结点储存起来,然后开始改变当前结点的指向

(4)改变要指向的结点P2,P1移动到下一个结点,循环遍历
struct num *Reverse(struct *pHead)
{
struct *p1;              //用来遍历结点一个一个截取结点
struct *p2;             //用来储存要指向的结点
struct *p;             //用来保存下一个要截取的结点
p1=pHead;             //从头指针开始遍历
p2=NULL;             //第一个要指向空指针
while(p1!=NULL)
{
p=p1->next;          //保存下一个结点
p1->next=p2;        //改变该结点的指向
p2=p1;             //将下一个要指向的结点替换掉上一个
p1=p;             //移动下标到下一个结点
}
pHead=p1;                //头指针指向最后,改变顺序呢
return pHead;
}


单链表的选择排序

(1)基本思想:

对单链表进行选择排序的基本思想和数组基本一样,选择一个结点或者元素和其他进行比较,每次找出剩下成员中最小的那个,因为单链表和数组有差异,因此在一些操作上有差别,对于链表,则是选出一个结点进行比较,然后将最小的结点放入另一个空链表中,依次类推,直到将原链表排成有序链表。

(2)

单向链表的选择排序图示:

         ---->[1]---->[3]---->[2]...---->
---->[NULL](原链表)

         head   1->next  3->next  2->next   n->next

         ---->[NULL](空链表)

        first

        tail

         ---->[1]---->[2]---->[3]...---->
---->[NULL](排序后链表)

         first   1->next  2->next  3->next   tail->next

(3)实现方法:

1.从第一个结点开始,找到最小的,放进另一个空链表中

2.空链表中放入第一个结点,形成一个有序链表,并将找到的结点从原链表中分离出来,不在让其参与下一次寻找

3.继续在原链表中找最小的,将其放入 有序链表的尾指针的next,然后将其标记为尾指针

4.需注意:

①所找到最小的结点是否是头结点,需要分情况讨论

②所放入的结点是否是第一个放入的结点,也需要分情况讨论
struct num *SelectSort(struct num *pHead)
{
struct num *first;                   // 排序后有序链表的头指针
struct num *tail;                   //排序后有序链表的尾指针
struct num *p_min;                 //用来储存所找到 最小结点的前驱结点
struct num *min;                  //储存最小结点
struct num *p;                    //提取每一个结点记性比较
first=NULL;                       //将未放入结点的头指针指向空
while(pHead!=NULL)                //当所有结点都被分离以后头指针指向空,跳出循环
{
for(p=pHead,min=pHead;p->next!=NULL;p=p->next)//循环遍历链表中的结点,判断p->next是否 指到最后的节点
{
if(p->next->number<min->number)
{
p_min=p;
min=p->next;              //找出最小的结点,并保存其前驱结点
}
}
if(first==NULL)                  //如果有序链表还是一个空链表
{
first=min;                  //第一个结点即是头指针又是尾指针
tail=min;
}
else
{
tail->next=min;            //将取出的结点和有序链表链接起来并标记为尾指针
tail=min;
}
if(min==pHead)                 //如果找到最小的结点是头结点
pHead=pHead->next;        //将头结点指向第二个结点
else
p_min->next=min->next;    //否则就是去除的结点前驱指向其后继结点
}
if(first!=NULL)
tail->next=NULL;            //单链表最后一个结点指向空指针
pHead=first;
return pHead;
}


单链表的插入排序

(1)基本思想:

依然和数组类似,显示取出第一个结点作为有序数组,然后依次将后面的结点插入到相应位置

(2)

单向链表的直接插入排序图示:

         ---->[1]---->[3]---->[2]...---->
---->[NULL](原链表)

        head   1->next  3->next  2->next   n->next

         ---->[1]---->[NULL](从原链表中取第1个节点作为只有一个节点的有序链表)

        head

        图11

        ---->[3]---->[2]...---->
---->[NULL](原链表剩下用于直接插入排序的节点)

        first   3->next  2->next   n->next

        图12

        ---->[1]---->[2]---->[3]...---->
---->[NULL](排序后链表)

        head   1->next  2->next  3->next   n->next
struct num *InsertSort(struct num *pHead)
{
struct num *first;              //作为剩下待排序的链表的头指针
struct num *t;                  //临时变量,保存准备插入的结点
struct num *p,*q;               //临时变量,表示要插入位置前后两个结点
first=pHead->next;              //将第一个结点看做有序数列,从第二个结点开始待插入
pHead->next=NULL;               //未插入结点时,头指针指向空
while(first!=NULL)              //遍历剩下未插入的结点
{
for(t=first,q=pHead;((q!=NULL)&&(q->number<t->number));p=q;q=q->next);
//此循环是在有序链表中找到插入的位置
first=first->next;             //将待插入的结点从无序链表中分离
if(q==pHead)                   //插在第一个结点之前
{
pHead=t;
}
else
{
p->next=t;              //p是q的前驱
}
t->next=q;                  //完成插入操作
}
return pHead;
}


单链表冒泡排序

(1)基本思想:

对链表的冒泡排序和对数组冒泡排序的基本思想是一样的,每次比较相邻两个数的大小,进行交换。

(2)单链表冒泡排序示意图

单向链表的冒泡排序图示:

        ---->[1]---->[3]---->[2]...---->
---->[NULL](原链表)

       head   1->next  3->next  2->next   n->next

       ---->[1]---->[2]---->[3]...---->
---->[NULL](排序后链表)

       head   1->next  2->next  3->next   n->next

       有N个节点的链表冒泡排序

      任意两个相邻节点p、q位置互换图示:

      假设p1->next指向p,那么显然p1->next->next就指向q,

      p1->next->next->next就指向q的后继节点,我们用p2保存

      p1->next->next指针。即:p2=p1->next->next,则有:

       [  ]---->[p]---------->[q]---->[  ](排序前)

       p1->next  p1->next->next  p2->next

       

       [  ]---->[q]---------->[p]---->[  ](排序后)

(3)实现方法:

(1)基本实现思路是,相邻两个结点,比较得出较小的结点,将其从原来链表中分离,然后插入到较大结点之前,要注意链表的连续和完整性

(2)设置一个标记可以将每趟排完序的最后位置记录下来,下一趟可以到那个位置停止,那个位置以后的结点都已经有序。
struct num *BubbleSort(struct num *pHead)
{
struct num *flag;         //控制循环比较终止位置的标志
struct num *p;           //临时指针变量,用来储存已经排好序的位置
struct num *p1,p2;
p1=(struct num *)malloc(sizeof(struct num));
p1->next=pHead;         //这里增加一个结点是给要排序的链表增加一个前驱,方便对前两个结点进行排序
pHead=p1;               //排序完成后将P1结点释放掉
for(flag=NULL;flag!=pHead;flag=p)           //设置标志,控制循环趟数
{
for(p1=pHead;p1->next->next!=flag;p1=p1->next)    //循环遍历到标记处
{
if(p1->next->number>p1->next->next->number)  //比较相邻两个结点的大小
{
p2=p1->next->next;                       //取出后一个结点
p1->next->next=p2->next;                 //将较大结点和较小结点的后驱连接
p2->next=p1->next;                       //取出的结点放到较大结点之前
p1->next=p2;                              //较小结点和较大结点的前驱连接
p=p1->next->next;                        //记录下每次排序的位置,传给flag
}
}
}
p1=pHead;               //把P1原来储存的信息去掉
pHead=pHead->next;      //将头指针指向原来的头结点
free(p1);             //释放P1
p1=NULL;           //p1置为空,保证不产生“野指针”,即地址不确定的指针
return pHead;
}


有序链表插入结点

有序链表插入节点示意图:

        ---->[NULL](空有序链表)

        head

       图18:空有序链表(空有序链表好解决,直接让head指向它就是了。)

       以下讨论不为空的有序链表。

        ---->[1]---->[2]---->[3]...---->
---->[NULL](有序链表)

        head   1->next  2->next  3->next   n->next

       图18:有N个节点的有序链表

       插入node节点的位置有两种情况:一是第一个节点前,二是其它节点前或后。

       ---->[node]---->[1]---->[2]---->[3]...---->
---->[NULL]

       head  node->next  1->next  2->next  3->next   n->next

       图19:node节点插在第一个节点前

       ---->[1]---->[2]---->[3]...---->[node]...---->
---->[NULL]

      head   1->next  2->next  3->next    node->next  n->next
struct num *SortInsert (struct num *pHead, struct num *node)
{
struct num *p;		//P用来保存当前要比较的结点
struct num *t;		//临时指针变量

if (pHead==NULL)		//处理空的有序链表
{
pHead=node;
node->next=NULL;
n+= 1;			//插入完毕,节点总数加1
return pHead;
}
p=pHead;			  //当有序链表不为空
while(p->num <node->num&&p!=NULL)	   //p指向的节点的学号比插入节点的学号小,并且它不等于NULL
{
t=p;			  //保存当前节点的前驱,以便后面判断后处理
p=p->next;		//后移一个节点
}

if (p==pHead)		//刚好插入第一个节点之前
{
node->next=p;
pHead=node;
}
else				 //插入其它节点之后
{
t->next=node;		//把node节点加进去
node->next=p;
}
n+= 1;			//插入完毕,节点总数加
return pHead;
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息