数据结构(2)—单向链表(2)

一、链表的查找

每次访问一个节点元素判断是否为要找的节点,符合条件返回该节点地址,到最后依旧没有找到符合条件的节点,返回NULL

linknode *find_linklist(linknode *phead, datatype tmpdata)
{
        linknode *ptmpnode = NULL;
        ptmpnode = phead->pnext;
        while (ptmpnode != NULL)
        {
                if (ptmpnode->data == tmpdata)
                {
                        return ptmpnode;
                }
                ptmpnode = ptmpnode->pnext;
        }
        return NULL;
}

二、 链表的修改

沿用遍历思想,找到符合条件的元素修改为新的值

int update_linklist(linknode *phead, datatype olddata, datatype newdata)
{
        linknode *ptmpnode = NULL;
        ptmpnode = phead->pnext;
        while (ptmpnode != NULL)
        {
                if (ptmpnode->data == olddata)
                {
                        ptmpnode->data = newdata;
                }
                ptmpnode = ptmpnode->pnext;
        }
        return 0;
}

三、链表的尾插

申请节点空间,将数据存放到节点中,将节点中地址赋值为NULL,找到最后一个节点,最后一个节点的pnext赋值为新申请节点

int insert_tail_linklist(linknode *phead, datatype tmpdata)
{
        linknode *ptmpnode = NULL;
        linknode *plastnode = NULL;

        ptmpnode = malloc(sizeof(linknode));
        if (NULL == ptmpnode)
        {
                perror("fail to malloc")
                return -1;
        }
        ptmpnode->data = tmpdata;
        ptmpnode->pnext = NULL;

        plastnode = phead;    //如果链表中只有头文件,此时为phead->pnext,下面将无法进行

                                           //必须为phead
        while (plastnode->pnext != NULL)
        {
                plastnode = plastnode->pnext;
        }

        plastnode->pnext = ptmpnode;
        return 0;
 }      

四、链表的销毁

定义两个指针pfreenode和ptmpnode都指向头节点,ptmpnode向后走,再释放pfreenode指向的节点,再将pfreenode指向ptmpnode指向的空间(需要用二级指针

 int destroy_linklist(linknode **pphead)
{
        linknode *pfreenode = NULL;
        linknode *ptmpnode = NULL;
        ptmpnode = *pphead;
        pfreenode = *pphead;
        while (ptmpnode != NULL)
        {
                ptmpnode = ptmpnode->pnext;
                free(pfreenode);
                pfreenode = ptmpnode;
        }
        *pphead = NULL;
        return 0;

}

五、查找链表中间节点

快指针每次走2步,慢指针每次都1步;快指针走到末尾,慢指针走到中间,慢指针处就是中间节点

linknode *find_midnode(linknode *phead)
{
        linknode *pslow = NULL;
        linknode *pfast = NULL;
        pslow = pfast = phead->pnext;
        while (pfast != NULL)
        {
                pfast = pfast->pnext;
                if (NULL == pfast)
                {
                        break;
                }
                pfast = pfast->pnext;
                if (NULL == pfast)
                {
                        break;
                }
                pslow = pslow->pnext;
        }
        return pslow;
}

六、查找链表倒数第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;
        for (i = 0; i < k && pfast != NULL; i++)
        {
                pfast = pfast->pnext;
        }
        if (NULL == pfast)
        {
                return NULL;
        }
        pslow = phead->pnext;
        while (pfast != NULL)
        {
                pfast = pfast->pnext;
                pslow = pslow->pnext;
        }
        return pslow;
}

七、 不知道头节点地址如何删除链表中间节点

将指针指向的下一个节点的值完全覆盖当前节点的值,释放下一个节点

int delete_linknode(linknode *ptmpnode)
{
        linknode *pnextnode = NULL;
        pnextnode = ptmpnode->pnext;
        ptmpnode->data = pnextnode->data;
        ptmpnode->pnext = pnextnode->pnext;
        free(pnextnode);
        return 0;
}

八、链表的倒置

将原链表断开,将所有的元素依次使用头插法插入即可实现

int reverse_linklist(linknode *phead)
{
        linknode *pinsertnode = NULL;
        linknode *ptmpnode = NULL;

        //将链表从头结点处断开
        ptmpnode = phead->pnext;
        phead->pnext = NULL;

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

九、 链表的排序

1.冒泡排序

①定义两个指针,相邻两个元素比较

②指针循环向后走,直到ptmpnode2为NULL,即等于pend,循环停止

③pend赋值为tmpnode1的节点地址‘下一轮就可以少比1次

④循环将所有大的元素找到,剩余一个小的元素即可

int 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 0;
        }
        while (1)
        {
                ptmpnode1 = phead->pnext;
                ptmpnode2 = phead->pnext->pnext;
                if (pend == ptmpnode2)
                {
                       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 0;
}

2.选择排序 

pswapnode指向要交换的节点,pminnode假设的最小值,ptmpnode和后续节点比较,如果小的话就和pswapnode交换,pswapnode不断向后增加不断比较得到排序

int select_sort_linklist(linknode *phead)
{
        linknode *pswapnode = NULL;
        linknode *ptmpnode = NULL;
        linknode *pminnode = NULL;
        datatype tmpdata;
        if (NULL == phead->pnext || NULL == phead->pnext->pnext)
        {
                return 0;
        }
        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 (pswapnode != pminnode)
                {
                        tmpdata = pswapnode->data;
                        pswapnode->data = pminnode->data;
                        pminnode->data = tmpdata;
                }
                pswapnode = pswapnode->pnext;
        }
        return 0;
}

十、 判断链表是否有环

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

2.环长为:定义一个指针从环相遇点开始走一圈,直到走该该节点为止;每走一个节点计数,最终可得到环长

3.入口位置:定义一个指针从相遇点开始每次走一步,定义一个指针从开头每次走一步,两个指针相遇的位置即为环入口位置

int circle_linklist(linknode *phead, int *pis_circle, int *pcirlen, linknode **ppnode)
{

        linknode *pfast = NULL;
        linknode *pslow = NULL;
        linknode *ptmpnode = NULL;
        linknode *pstartnode = NULL;
        int cnt = 1;

        

        /* 判断是否有环 */
        pfast = phead->pnext;
        pslow = phead->pnext;
        while (1)
        {
                pfast = pfast->pnext;
                if (NULL == pfast)
                {
                        break;
                }
                pfast = pfast->pnext;
                if (NULL == pfast)
                {
                        break;
                }
                pslow = pslow->pnext;
                if (pfast == pslow)
                {
                        break;
                }
        }
        if (NULL == pfast)
        {
                *pis_circle = 0;
                return 0;
        }
        else
        {
                *pis_circle = 1;
        }

        /* 统计环长 */
        ptmpnode = pslow->pnext;
        while (ptmpnode != pslow)
        {
                cnt++;
                ptmpnode = ptmpnode->pnext;
        }
        *pcirlen = cnt;

        /* 找到环入口 */
        pstartnode = phead->pnext;
        ptmpnode = pslow;
        while (pstartnode != ptmpnode)
        {
                pstartnode = pstartnode->pnext;
                ptmpnode = ptmpnode->pnext;
        }

        *ppnode = ptmpnode;
        return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值