单链表

建立链表结点的结构体有关链表问题,我折腾了好长时间,总是断断续续的。如果想统一花一点时间攻克,估计也差不多能攻克了,折腾来折腾去,拖延症一犯,到现在也没有完全弄清楚。现在先把自己搞明白的有关链表的内容搞明白。

说起单链表,有以下几个方面的内容需要你会写。

  1. 建立单链表。

要想实现对链表的操作,首先的当然是建立链表啦。没有链表怎么进行插入删除查找操作啊。

建立单链表有以下几个部分

  • 建立链表结点的结构体。
  • 为结点分配空间
  • 为结点赋值
  • 为结点确定位置

以下是建立的链表结点的结构体

1 typedef struct Node
2 {
3     int element;
4     struct Node *next;
5 }node;

其次是创建链表的函数了:

/********************************
*描述:创建链表
*参数:无
*返回值:链表头指针
*******************************/
node *creat()
{
    node *head, *p, *q;
    int x = 0;
    bool cycle = true;
    head = (node*)malloc(sizeof(node));
    p = head;
    while (cycle)
    {
        printf("请输入一个整数");
        scanf("%d", &x);
        if (x != 0)
        {
            q = (node*)malloc(sizeof(node));
            q->element = x;
            p->next = q;
            p = q;
        }
        else
            cycle = false;
    }
    head = head->next;
    p->next = NULL;
    return head;
}

创建链表时候尤为注意几点:1:为结点分配空间。2:为结点赋值3:为结点确定位置。

node *head;
head = creat();

在主函数当中,用这两句,就能轻松调用创建链表的函数进行使用了。

还有几个小函数,不是很关键,但是学学还是很有用的,没准什么时候就能用到,看下面。

/********************************
*描述:测量链表长度
*参数:head:链表头指针
*返回值:链表长度
*******************************/
int flength(node *head)
{
    int count = 1;
    node *p;
    p = head;
    while (p->next != NULL)
    {
        ++count; 
        p = p->next;
    }
    return count;
}
/********************************
*描述:打印链表
*参数:head:链表头指针
*返回值:链表长度
*******************************/
void fprint(node *head)
{
    int length = flength(head);
    node *pdata = head;
    for (int i = 0; i < length; ++i)
    {
        printf("第%d个元素的值为%d", i, pdata->element);
        pdata = pdata->next;
    }
}

2.删除元素

删除元素中涉及到一些技巧,注意一下。

/********************************
*描述:删除链表中的某个元素
*参数:head:链表头指针
*      num:要删除的数据
*返回值:链表头
*******************************/
node *fdelete(node *head, int num)
{
    node *p1, *p2;
    p1 = head;
    p2 = head;
    while (num != p1->element&&p1->next != NULL)
    {
        p2 = p1;
        p1 = p1->next;
    }
    if (num == p1->element)//删除的元素是头结点还是非头结点要分别对待。
    {
        if (p1 == head)
        {
            head = p1->next;
            free(p1);
        }
        else
        {
            p2->next = p1->next;
            free(p1);
            p1 = NULL;// 写这句的目的是不能让p1成为悬空指针。
        }

    }
    else
        printf("找不到要删除的元素!!!");
}

搜寻整个链表,找寻某个值是否存在于链表之中

/********************************
*描述:查询某元素
*参数:head:链表头
*      num:要查询的数据
*返回值:无
*******************************/
void fsearch(node *head, int num)
{
    node *p1;
    p1 = head;
    while (p1->element != num&&p1->next != NULL)
    {
        p1 = p1->next;//找寻下面一个链表结点是否符合条件
    }
    if (p1->element == num)
    {
        printf("%d值已经找到了",num);
    }
    else
    {
        printf("搜遍整个链表,此值不存在");
    }
}

插入一个链表的操作,现在看来已经非常简单了。

/********************************
*描述:插入一个数,插入数据的原则为从小到大
*参数:head:链表头
*       num:插入的数据
*返回值:链表头
*******************************/
node* finsert(node *head, int num )
{
    node *p0,*p1, *p2;
    p1 = p2 = head;//给予指针初始位置
    p0->element = num;
    while (p0->element >= p1->element)
    {
        p1 = p1->next;
        p2->next = p1;
    }
    if (p1 == head)
    {
        p0->next = p1;
        head = p0;
    }
    else if (p1->next != NULL)
    {
        p2->next = p0;
        p0->next = p1;
    }
    else
    {
        p1->next = p0;
        p0->next = NULL;
    }
    return head;
}

用链表实现冒泡排序和一般数组的冒泡排序没什么差别

/********************************
*描述:链表冒泡排序,从大到小
*参数:head:链表头
*返回值:无
*******************************/
void fsort(node *head)
{
    node *q;
    int len = flength(head);
    for (int i = 0; i < len; ++i)
    {
        for (q = head; q->next != NULL; q = q->next)
        {
            if (q->element < q->next->element)
            {
                int temp;
                temp = q->element;
                q->element = q->next->element;
                q->element = temp;
            }
        }
    }
}

用链表实现逆序排序

/********************************
 *描述:链表逆置
 *参数:head:表头
 *返回值:node:返回新的链表头
 *******************************/
node *freverse(node *head)
{
    node *p0=NULL,*p1=NULL,*p2=NULL;  
    
    if(flength(head)<=1){
        printf("\n链表节点至少为2");
        return NULL;
    }
    else{
        p1=head;
        p2=p1->next;
        while(p2!=NULL){         //一定要用p2判断,否则错误
            p0=p2->next;
            p2->next=p1;
            p1=p2;
            p2=p0;            
        } 
        head->next=NULL;
        head=p1;
        printf("\n链表逆置完成");
        return head;
    }
}
逆序排序这里可以重点说一下。一般而言,建立一个链表结点,结点的指针和其中的值是不会轻易分离的。p2->next=p1; 只是p2指向的下一个结点发生的改变,但是p2->element并没有发生改变。这一点上花了不短的时间才能理解清楚,不容易。
posted @ 2014-08-31 22:58  程序员小王  阅读(299)  评论(0编辑  收藏  举报