Linux学习—数据结构(链表2)

1.单向链表

6.链表的查找

在链表中找到指定的第一个元素

  • 沿用遍历思想,每次访问一个节点元素判断是否为要找的节点
  • 符合条件返回该节点地址
  • 到最后没有找到符号条件的节NULL
linknode *find_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;

    ptmpnode = phead->pnext;

    while(ptmpnode != NULL)
    {
        if(ptmpnode->data == tmpdata)
        {
            return ptmpnode;
        }
        else
        {
            ptmpnode = ptmpnode->pnext;
        }
    }

    return NULL;
}

7.链表的修改

沿用遍历思想,找到需要修改的节点

/*更换链表老元素为新元素*/
int update_linklist(linknode *phead, datatype olddata, datatype newdata)
{
    linknode *ptmpnode = phead->pnext;

    while(ptmpnode != NULL)
    {
        if(ptmpnode->data == olddata)
        {
            ptmpnode->data = newdata;
            ptmpnode = ptmpnode->pnext;
        }
        else
        { 
            ptmpnode = ptmpnode->pnext;   
        }
    }

    return 0;
}

8.尾插法

在链表结尾插入一个元素

  • 申请节点空间
  • 将数据存放到节点中
  • 将节点中地址赋值为NULL
  • 找到最后一个节点
  • 最后一个节点的pnext赋值为新申请节点
int insert_tail_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;
    linknode *pnewnode = NULL;

    ptmpnode = phead;       //从空白节点开始找

    pnewnode = malloc(sizeof(linknode));

    if(NULL == pnewnode)
    {
        perror("fail to malloc");
        return -1;
    }

    while(ptmpnode->pnext != NULL)
    {
        ptmpnode = ptmpnode->pnext;
    }

    pnewnode->data = tmpdata;
    pnewnode->pnext = NULL;
    ptmpnode->pnext = pnewnode;

    return 0;
}

 9.链表的销毁

  • 定义两个指针pfreenode和ptmpnode都指向头结点
  • ptmpnode向后走
  • 再释放pfreenode指向的节点
  • 再将pfreenode指向ptmpnode指向的空间
void destroy_linklist(linknode **pphead)
{
    linknode *ptmpnode = NULL;
    linknode *pfreenode = NULL;

    pfreenode = *pphead;
    ptmpnode = *pphead;

    while(ptmpnode != NULL)
    {
        ptmpnode = ptmpnode->pnext;
        free(pfreenode);
        pfreenode = ptmpnode;
    }

    *pphead = NULL;

    return;
}

10.查找链表的中间节点

  • 快指针每次走2步,慢指针每次走1步
  • 快指针走到末尾,慢指针走到中间
linknode *find_midnode(linknode *phead)
{
    linknode *pfast = NULL;
    linknode *pslow = NULL;

    pfast = pslow = phead->pnext;

    while(pfast != NULL)
    {
        pfast = pfast->pnext;
        if(pfast == NULL)
        {
            break;
        }        
        pfast = pfast->pnext;
        if(pfast == NULL)
        {
            break;
        }
        pslow = pslow->pnext;
    }

    return pslow;
}

11.查找链表倒数第k个节点

  • 快指针先走k步
  • 慢指针和快指针每次走一步
  • 快指针到达末尾,慢指针少走k步,即倒数第k个元素
/*查找链表倒数第k个节点*/
linknode *find_last_kth_node(linknode *phead, int k)
{
    int i = 0;
    linknode *pfast = NULL;
    linknode *pslow = NULL;

    pfast = phead->pnext;
    pslow = phead->pnext;

    for(i = 0; i < k && pfast != NULL; i++)
    {
        pfast = pfast->pnext;
    }

    if(pfast == NULL)
    {
        return NULL;
    }

    while(pfast != NULL)
    {
        pfast = pfast->pnext;
        pslow = pslow->pnext;
    }

    return pslow;
}

12.不知道头节点地址,如何删除链表中间节点

  • 将指针指向的下一个节点的值覆盖当前节点的值
  • 删除下一个节点
void delete_linknode(linknode *ptmpnode)
{
    linknode *pnextnode = NULL;

    pnextnode = ptmpnode->pnext;
    ptmpnode->data = pnextnode->data;
    ptmpnode->pnext = pnextnode->pnext;
    free(pnextnode);

    return;
}

13.链表的倒置

将链表所以元素倒置

  • 将原链表断开
  • 将所有的元素依次使用头插法插入
void reverse_linklist(linknode *phead)
{
    linknode *ptmpnode = NULL;
    linknode *pinsertnode = NULL;
    //将链表从头结点断开
    ptmpnode = phead->pnext;
    phead->pnext = NULL;

    //依次将所有元素使用头插法插入链表
    while(ptmpnode != NULL)
    {
        pinsertnode = ptmpnode;
        ptmpnode = ptmpnode->pnext;
        pinsertnode->pnext = phead->pnext;
        phead->pnext = pinsertnode;
    }

    return;
}

14.链表的排序

冒号排序

  • 采用冒号排序思想,定义两个指针,相邻两个元素比较
  • 指针循环向后走,直到ptmnode2为NULL,即等于pend,循环停止
  • pend赋值为ptmpnode1的节点地址
  • 下一轮就可以少比一次
void bubble_sort_linklist(linknode *phead)
{
    linknode *ptmpnode1 = NULL;
    linknode *ptmpnode2 = NULL;
    linknode *pend = NULL;
    datatype tmpdata;

    if(NULL == phead->pnext || NULL == phead->pnext->pnext)
    {
        return;
    }

    while(1)
    {
        ptmpnode1 = phead->pnext;
        ptmpnode2 = phead->pnext->pnext;
        if(ptmpnode2 == pend)
        {
            break;
        }
        while(ptmpnode2 != pend)
        {
            if(ptmpnode1->data > ptmpnode2->data)
            {
                tmpdata = ptmpnode1->data;
                ptmpnode1->data = ptmpnode2->data;
                ptmpnode2->data = tmpdata;
            }
            ptmpnode1 = ptmpnode1->pnext;
            ptmpnode2 = ptmpnode2->pnext;
        }
        pend = ptmpnode1;
    }
    
    return;
}

选择排序

  • pswapnode指向要交换的节点
  • pminnode假设的最小值
  • ptmpnode和后续节点比较
void select_sort_linklist(linknode *phead)
{
    linknode *pminnode = NULL;
    linknode *pswapnode = NULL;
    linknode *ptmpnode = NULL;
    datatype tmpdata;

    if(NULL == phead->pnext || NULL == phead->pnext->pnext)
    {
        return;
    }

    pswapnode = phead->pnext;
    while(pswapnode->pnext != NULL)
    {
       pminnode = pswapnode;
       ptmpnode = pswapnode->pnext;
       while(ptmpnode != NULL)
        {
            if(ptmpnode->data < pminnode->data)
            {
               pminnode = ptmpnode;
            }
            ptmpnode = ptmpnode->pnext;
        }
        if(pminnode != pswapnode)
        {
            tmpdata = pminnode->data;
            pminnode->data = pswapnode->data;
            pswapnode->data = tmpdata;
        }
        pswapnode = pswapnode->pnext;
    }

    return;
}

15.判断链表是否有环

  • 判断链表是否有环
  • 计算环长
  • 找到环的入口位置

判断是否有环

  • 定义两个指针:快指针(每次2步)和慢指针(每次走1步)
  • 快指针-慢指针 == 环长即相遇, 快指针和慢指针相等即为链表有环

计算环长

  • 定义一个指针从环相遇开始走一圈,知道走到该节点为止
  • 每走一个节点计数,最终得到环长

获得环的入口位置

  • 定义一个指针,从相遇点开始每次走一步,定义一个指针,从开头每次走一步
  • 两个指针相遇即为环入口

2.双向链表

1.创建空链表

参考单向链表的创建

linknode *creat_empty_linlist(void)
{
    linknode *ptmpnode = NULL;

    ptmpnode = malloc(sizeof(linknode));
    if(NULL == ptmpnode)
    {
        perror("fail to malloc");
        return NULL;
    }

    ptmpnode->pnext = NULL;
    ptmpnode->ppre = NULL;

    return ptmpnode;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值