2022年8月12日-8月19日学习周报

本周结束了c高级的学习,进入学习数据结构的阶段。为了巩固对于链表思维的培养,故总结单链表的一些基本功能。

1.尾插法创建链表;

2.头插法创建链表;

3.通过节点序号查找链表;

4.通过节点序号插入数值进入链表;

5.通过节点序号删除链表;

6.释放链表;

7.链表排序;


1.尾插法创建链表;

创建头指针head和尾指针tail;新指针pnew;

1.1)若插入的是第一个节点,则将头指针和尾指针都接收新指针pnew的值;

1.2)若插入的不是第一个节点,头指针不动,一直移动尾指针。tail->next 接收pnew的值,并将tail接收pnew的值;

struct node *create_list_by_tail()
{
    struct node *head = NULL; //头指针
    struct node *pnew = NULL; //申请新的节点
    struct node *tail = NULL; //保存最后一个节点的地址

    int x;
    scanf("%d", &x);
    while(getchar()!='\n');

    while(x)
    {
        //1、创建新的节点
        pnew = (struct node*)malloc(sizeof(struct node));
        if(NULL == pnew)
        {
            printf("malloc error, %s,%d\n", __FILE__, __LINE__);
            exit(-1);
        }

        pnew->data = x;
        pnew->next = NULL;


        //2、加入链表
        if(head == NULL)
        {
            head = pnew;
            tail = pnew;
        }
        else
        {
            tail->next = pnew;
            tail = pnew;
        }

        scanf("%d", &x);
        while(getchar()!='\n');
    }
    return head;
}

2.头插法创建链表;

创建新链,头指针为pnew,原来的链表头指针为head; 

2.1)若是空链表,则将head直接接收pnew的值即可;

2.2)若是非空链表,则先将新链表的尾巴接收head的值(pnew->next  =  head),再将head前移至pnew的位置(head = pnew)。

另:空链表的pnew->next和head都是NULL,所以头插法可以直接使用2.2。

struct node *create_list_by_head()
{
    struct node *head = NULL, *pnew = NULL;

    int x;
    scanf("%d", &x);
    while(getchar()!='\n');

    while(x)
    {
        //1、创建新的节点,并赋值
        pnew = (struct node*)malloc(sizeof(struct node));
        if(NULL == pnew)
        {
            printf("malloc error, %s, %d\n", __FILE__,__LINE__);
            exit(-1);
        }
        pnew->data = x;
        pnew->next = NULL;


        //2、加入链表
        pnew->next = head;
        head = pnew;


        scanf("%d", &x);
        while(getchar()!='\n');
    }
       return head;
}

3.通过节点序号查找链表;

节点序号index是输入的要查找的节点序号,只要做index-1遍遍历,即可找到要查找的节点。

执行遍历之前需要对index做检查。若index<1或者index>链表长度,都是查找不到的,要给予反馈。

struct node* list_search_by_index(struct node *head, int index)
{
    //入参检查
    if(NULL == head)
    {
        return NULL;
    }

    int  len = list_len(head);

    if(index < 1 || index>len)
    {
        printf("param  error!%s, %d\n", __FILE__,__LINE__ );
        return  NULL;
    }


    //若正确,流程
    struct node *p = head;

    for(int i=1; i<index; i++ )
    {
        p = p->next;
    }

    return p;
}

4.通过节点序号插入数值进入链表;

4.1)如果是头插,则直接将新节点的尾巴指向原来的头节点,head头节点接收新节点的头指针(pnew);

4.2)若是中间或者尾部插入,则通过查找下标的方法(3.通过节点序号查找链表)找到需要插入的前一个节点(index-1),设为p,则新节点接收p的尾巴(pnew->next = p->next),p的尾巴接收新节点的头指针pnew(p->next = pnew),则可以实现插入。

struct node *list_insert_by_index(struct node *head, int index, int data)
{
    //入参检查
    int  len = list_len(head);

    if(index<1)
    {
        index = 1;
    }

    if(index>len+1)
    {
        index = len+1;
    }

    //若正确,流程
    struct node * pnew=NULL;
    pnew = create_node();
    pnew->data = data;

    if(1 == index)//  头插
    {
        pnew->next = head;
        head = pnew;
    }
    else //中间或者尾部插入
    {
        struct node *psearch = NULL;
        psearch = list_search_by_index(head, index-1);
        pnew->next = psearch->next;
        psearch->next = pnew;
    }
    return head;
}

5.通过节点序号删除链表;

5.1)入参检查:

        5.1.1)头指针head不为NULL,即链表不为空;

        5.1.2)输入的下标是否在范围内。

5.2)删除操作思路:

        5.2.1)用一个临时指针,保存 要删除的节点地址;

        5.2.2)将 要删除的节点,从链表上移除;

        5.2.3)释放临时指针空间。

struct node*list_del_by_index(struct node *head, int  index)
{
    //入参检查
    if(NULL == head)
    {
        return head;
    }

    int  len = list_len(head);

    if(index<1 || index>len)
    {
        return head;
    }

    //正确流程
    //(1)保存删除节点地址
    //(2)将删除节点从链表上移下来
    // (3)释放空间
    //
    struct node *pdel = NULL ;  //保存删除节点的地址
    if(1 == index) //头删
    {
        pdel = head;
        head = head->next;
    }
    else  //中间删除  或者尾部删除
    {
        struct node *psearch = NULL;
        psearch = list_search_by_index(head, index-1);

        pdel = psearch->next;
        psearch->next = pdel->next;
    }
    free(pdel);

    return head;
}

6.释放链表;

6.1)用临时指针接收头指针的地址;

6.2)头指针做遍历;

6.3)释放临时指针;

struct node* list_free(struct node *head)
{
    struct node *pdel = NULL;
    while(head != NULL)
    {
        pdel = head;
        head = head->next;
        free(pdel);
    }
    return head;
}

7.链表排序;

7.1)从旧链表中找到最大值——假设pmax指向头指针head为最大,做遍历,遇到更大则取值,最后得到pmax存储的肯定是最大值节点;

7.2)将最大值节点从旧链表移除,得到一个单独的链表——如果头指针最大,则直接将头指针后移一位,否则找到pmax的前一个节点p(遍历直到找到pmax);将p的尾巴接收pmax的尾巴(p->next = pmax->next); 最后将pmax的尾巴指向NULL,得到一个pmax的单独链表;

7.3)将第二步的单独的链表,加入新链表——定义新链表为pnew,用头插法将每次取到的最大节点放入新链表,最后即可得到从小到大排序的新链表。

//1、从旧 链表中找到最大值
struct node* find_max_from_oldlist(struct node*head)
{
    struct node *pmax = head;

    struct node *p = head;

    while(p != NULL)
    {
        if(p->data > pmax->data)
        {
            pmax = p;
        }    
        p = p->next;
    }
    return pmax;
}
//2、将最大值从旧链表中移除
struct node* move_max_from_oldlist(struct node* head, struct node *pmax)
{
    if(head == pmax)//头部移除
    {
        head = head->next;
    }
    else
    {
        struct node *p = head;
        while(p->next != pmax)  //找最大值前面的一个节点
        {
            p = p->next;
        }
        p->next = pmax->next;
    }
    pmax->next = NULL;
    return head;
}
//3、将最大值加入新的链表
struct node* add_newlist(struct node* new_head, struct node* pmax)
{
    pmax->next = new_head;
    new_head = pmax;
    return new_head;
}
struct node *list_sort(struct node *head)
{
    struct node *new_head = NULL;
    struct node *pmax = NULL;

    while(head != NULL)
    {
       //1、从旧 链表中找到最大值
        pmax = find_max_from_oldlist(head);
       //2、将最大值从旧链表中移除
        head = move_max_from_oldlist(head, pmax);
       //3、将最大值加入新的链表
        new_head = add_newlist(new_head, pmax);
    }
    return new_head;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值