链表的小结

最近新学的关于链表的操作,做了一个小小的总结吧,链表的一些简单操作。
文笔比较拙略,望高手谅解,指正。
代码均已经在dev上测试运行,保证无错。
如果有和我一样的新手大家可以一起交流一下。

#include <stdio.h>
#include <stdlib.h>
struct test
{
    int a;
    struct test *next;
};


struct test *Creat_from_head();
struct test *Creat_from_tail();
void print(struct test *head);
struct test *antitone1(struct test *head);
struct test *antitone2(struct test *head); 
struct test *sort1(struct test *head);
struct test *sort2(struct test *head);



int main(void)
{
    int item;
    struct test *p1;
    struct test *p2;
    struct test *p3;
    printf("创建链表(以0结束),请选择创建的方式\n");
    printf("1   头插法\n");
    printf("2   尾插法\n");
    scanf("%d",&item);
    fflush(stdin);
    printf("\n");
    switch(item)
    {
        case 1:
            {
                p1=Creat_from_head();
                break;  
            }
        case 2:
            {
                p1=Creat_from_tail();
                break;
            }
        default :
        {
            break;
        }
    }
    printf("\n");
    print(p1);
    printf("\n");
    printf("选择链表的反序方式\n");
    printf("1   三变量反序\n");
    printf("2   两变量反序\n");
    scanf("%d",&item);
    fflush(stdin);
    printf("\n");
    switch(item)
    {
        case 1:
            {
                p2=antitone1(p1);
                break;  
            }
        case 2:
            {
                p2=antitone2(p1);
                break;
            }
        default :
        {
            break;
        }
    }
    print(p2);
    printf("\n");
    printf("\n");
    printf("选择链表的排序方式\n");
    printf("1   直接排序\n");
    printf("2   选择排序\n");
    scanf("%d",&item);
    fflush(stdin);
    printf("\n");
    switch(item)
    {
        case 1:
            {
                p3=sort1(p2);
                break;  
            }
        case 2:
            {
                p3=sort2(p2);
                break;
            }
        default :
        {
            break;
        }
    }
    print(p3);
    printf("\n");



    return 0;
}

struct test *Creat_from_tail()
{
    struct test *head;
    struct test *pnew;
    struct test *tail;

    pnew=(struct test *)malloc(sizeof(struct test));
    pnew->next=NULL;
    head=pnew;
    tail=pnew;
    while(1)
    {
        pnew=(struct test *)malloc(sizeof(struct test));
        scanf("%d",&pnew->a);
        if(pnew->a==0)
        {
            free(pnew);
            return head;    
        }

        pnew->next=NULL;
        tail->next=pnew;
        tail=pnew;
    }
}


/*头插法创建链表*/ 

struct test *Creat_from_head()
{
    struct test *head;
    struct test *pnew;

    head=(struct test *)malloc(sizeof(struct test));
    head->next=NULL;

    while(1)
    {
        pnew=(struct test *)malloc(sizeof(struct test));
        scanf("%d",&pnew->a);

        if(pnew->a==0)
        {
            free(pnew);
            return head;
        }

        pnew->next=head->next;
        head->next=pnew;
    }

}





/*用于输出链表 */



void print(struct test *head)
{
    struct test *p;
    p=head->next;
    while(p!=NULL)
    {
        printf("%d\n",p->a);
        p=p->next;
    }
}



/*链表的直接比较排序(名字可能不太恰当)   (由小到大)*/
struct test *sort1(struct test *head)
{
    struct test *p;         /*这是无序链表的遍历结点*/ 
    struct test *q1,*q2;        /*q1,q2都是有序链表中的结点,q2用来和无序链表中的结点比较,q1用来保存q1前面的结点,从而方便新结点的插入*/
    struct test *tem;       /*用来保存当前无序链表中的结点,若是不保存这个结点,在每次将无序链表中结点插入,有序链表后,无序链表将无法遍历,程序陷入崩溃*/ 

    p=head->next->next;         /*这里两句是将一个链表一刀截断,分成两个,一个是存储有序的,另一个是存储无序*/ 
    head->next->next=NULL;

    while(p!=NULL)          /*当p等于NULL时候无序连表遍历完毕,也意味着排序完毕*/ 
    {
        tem=p;              /* 无序链表部分 */ 
        p=p->next;                  
        q1=head;
        q2=head->next;      /*有序链表部分*/ 
        while(q2!=NULL)
        {
            if(q2->a<tem->a)
                /*这里是排序的重点,每次从无序链表中取出的结点都要和有序链表的第
                一个有值结点比较(因为咱们创建的链表是有表头的),比这个结点大则继续向下遍历无序链表,如果小则结束遍历,直接将这个
                结点插入到有序链表中的第一个有值位置之前*/ 
            {
                q1=q2;
                q2=q1->next;
            }
            else 
            {
                break;
            }
        }
        q1->next=tem;       /*将无序链表中找出的结点插入到有序链表中*/ 
        tem->next=q2;
    }
    return head;
}



/*用来反序链表            (把删除放到这里,是应为这个思想和上面排序的思想有一定的相似)*/
struct test *antitone1(struct test *head)
{
    struct test *p1,*p2;            /*p1,是遍历用的,p2,永远都是前面链表的第一个有值结点(被插入链表的第一个有值结点)*/
    struct test *q;             /*保存p1的后面结点,因在结点的插入过程p1后面的结点会丢掉,导致无法遍历后面的结点(原因同sort1()中的q1,q2)*/

    p1=head->next->next;
    p2=head->next;
    head->next->next=NULL;

    while(p1!=NULL)
    {
        q=p1->next;         /*保存p1后面的结点*/ 
        head->next=p1;      /*这里是插入过程也是这个功能的重点*/ 
        p1->next=p2;
        p2=p1;              /*这样p2又成了第一个有值结点*/
        p1=q;               /*用于移动*/ 
    }
    return head;
} 


/*想比上面那这种,这种我觉得更加简洁明了,而且自己定义两个变量就完成了逆置*/ 
struct test *antitone2(struct test *head)
{
    struct test *p=head->next,*q=head->next;/*p为当前插入前面链表的结点,q保存p的下一个节点(原因和上面antitone1()中q类似)*/ 

    q=q->next;
    p->next=NULL;
    p=q;

    while(p!=NULL)
    {
        q=q->next;              
        p->next=head->next;     /*这里与上面的反序不同,它不管你head下面的是谁,只管向head下面添加就够了,剩下了变量,也更明了*/ 
        head->next=p;
        p=q;
    }
    return head;
}


/*链表的选择排序   (由小到大)*/
/*这个方法是在原始链表中找到最小结点后,放入新链表,并且把找到的最小在原先链表中删除*/ 
struct test *sort2(struct test *head)
{
    struct test *sorted,*tail;      /*sorted有顺序的链表的两个结点*/
    struct test *min,*p_min;        /*保存最小结点,和最小结点的前一个结点(方便删除)*/
    struct test *p;                 /*临时结点*/ 

    sorted=(struct test *)malloc(sizeof(struct test));      /*为新链表创建表头*/ 
    sorted->next=NULL; 

    while(head->next!=NULL)
    {
      for(p=head->next,min=head->next,p_min=head;p->next!=NULL;p=p->next)       /*此处找出最小的结点*/ 
      {
        if(p->next->a<min->a)
        {
            min=p->next;
            p_min=p;
        }
      }
      if(sorted->next==NULL)        /*将找出的插入到有序链表中*/ 
      {  
        sorted->next=min;
        tail=min;
      }  
      else
      {
        tail->next=min;
        tail=min;
      }
      p_min->next=min->next;        /*将最小的结点在原链表删除*/ 
    }
    if(sorted->next!=NULL)
    {
        tail->next=NULL;
    }
    head=sorted;
    return head;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值