单链表的经典操作,查找链表倒数第k个节点,判断链表是否存在环,求环节点

#include<stdio.h>
#include<stdlib.h>

typedef struct date_list{
    int data;
    struct date_list* next;
}mylist;

mylist* creatlist(int x,mylist* p)        //用一个元素创建链表
{
    if(NULL == p)                         //链表创建必须判空
    {
        p = malloc(sizeof(mylist));
        p->data = x;
        p->next = NULL;
    }
    return p;
}

mylist* insert_tail(int x, mylist* Head)   //在链表的尾部插入元素
{
    if(NULL == Head)                       //尾插如果插入链表为空创建链表
        Head = creatlist(x, Head);
    else
    {
        mylist *p = NULL,*q = NULL;
        for(p = Head; p->next != NULL; p = p->next )
            ;
        q = creatlist(x, q);
        p->next = q;
    }
    return Head;
}

mylist* dellist(mylist *Head)    //删除整个链表    在堆中自己开辟的空间必须释放掉
{                                           //定义变量是从栈中开辟空间先定义,空间地址大
    mylist *p = NULL, *q = NULL;
    if(NULL == Head)
        return Head;
    else
    {
        while(Head->next != NULL)
        {
            for(p = Head, q = Head->next; q->next != NULL; p = q, q = q->next)
                ;
            free(q);
            p->next = NULL;
        }
        free(Head);
        Head = NULL;           //删除掉链表的时候必须指控,防止野指针的出现
    }
    return Head;
}

void show(mylist *Head)            //列出链表中的元素
{
    mylist *p = NULL;
    if(NULL == Head)               
        printf("it‘s a NULL point");
    else
    {
        p = Head;
        do
        {
            printf("%d ",p->data );
            p = p->next;
        }while(p != NULL);
    }
    printf("\n");
}

mylist* find_tail(mylist *Head, int n)   //寻找链表的倒数第n个元素
{
    mylist *fast = Head, *low = NULL, *get_len = Head;
    int len = 1;
    if(Head == NULL||n<0)               //链表判空,而且倒数第n个节点,n必须为正整数
        return NULL;
    for(; get_len != NULL; get_len = get_len->next, len++)
        ;                               //这里是空语句
    if(len < n)                         //n还要小于等于链表节点的个数
        return NULL;
    for(;n != 1; n--)
        fast = fast->next;
    for(low = Head; fast->next != NULL; fast = fast->next, low = low->next )
        ;
    return low;
}

int creat_circl(mylist *Head, int n)   //让单链表生成环,即环中存在n个节点   这是为了实现后续功能函数进行测试加入的
{
    if(Head == NULL)
        return 0;
    else
    {
        find_tail(Head,1)->next = find_tail(Head,n);
        return 1;
    }
}

int is_circl(mylist *Head)            //判断单链表中是否存在环
{
    mylist *fast, *low;               //两个指针指向头,一个前进一步,一个前进两步,两个指针相遇则存在环
    if(Head == NULL)                  //快的指针指向空时不存在环
        return 0;
    else
    {
        for(fast =Head->next, low = Head; fast != low&&fast->next != NULL; fast=fast->next,fast=fast->next, low = low->next )
            ;
        if(fast == low)
        {
            printf("存在环\n");
            return 1;
        }
        else
        {
            printf("不存在环\n");
            return 0;
        }
    }
}

mylist *wic_circl(mylist *Head) //求出环节点:将环中节点打断(上述判断时相遇节点为环中节点),转换成‘Y‘字链表求第一个交叉节点,再还原该链表
{
    mylist *fast, *low, *t_Head, *t_low;
    int lenth_low = 0, lenth_len = 0, i;  
    if(Head == NULL)
        return Head;
    else                        //找出环中节点,将其的指针域用low记录下,并指为空。得到两个具有‘Y‘字特性的单链表,然后找出相同的第一个节点
    {                           //则为环节点,然后将指向空的节点的指针域指向记录的指针low打断节点的地址。
                                //找出相同的第一个节点:1.用双重循环做 空间复杂度:S(1),时间复杂度:O(n^2)
                                //2.计算出两个链表的长度。让长的链表先走长出的长度,然后两个链表再同步走,可以找出相同的第一个节点。
                                //   时间复杂度为O(max(m,n))   空间复杂度为:S(1)
        for(fast =Head->next, low = Head; fast != low&&fast->next != NULL; fast=fast->next,fast=fast->next, low = low->next )
            ;
        low = low->next;
        fast->next = NULL;
        for(t_Head = Head; t_Head != NULL; t_Head=t_Head->next)
            lenth_len++;
        for(t_low = low; t_low !=NULL; t_low=t_low->next)
            lenth_low++;
        if(lenth_low >= lenth_len)
        {
            for(i = 0, t_low = low; i<(lenth_low-lenth_len); i++)
                t_low = t_low->next;
            t_Head = Head;
        }
        else
        {
            for(i = 0, t_Head = Head; i<(lenth_len-lenth_low); i++)
                t_Head = t_Head->next;
            t_low = low;
        }
        for(; t_low != t_Head; t_low = t_low->next, t_Head = t_Head->next )
            ;
        fast->next = low;
        return t_low;
    }
}

mylist *get_no_circl(mylist *Head)                  //将一个带环的单链表转换成一个单链表   
{                                                   
    mylist *circl_begin = NULL, *p = Head;          
    if(is_circl(Head))
    {
        circl_begin = wic_circl(Head);    
        for(; p->next != circl_begin; p=p->next);   //第二次碰见环节点才进行打断环
        p=p->next;
        for(; p->next != circl_begin; p=p->next);        
        p->next = NULL;
    }
    return Head;
}

int main()
{
    int i;
    mylist *head = NULL;
    for(i=0; i<10; i++)                     //创建一个链表,该链表中的值为:0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    {
        head = insert_tail(i, head);
    }
    show(head);                             //打印出链表的值
    printf("%d\n", find_tail(head,1)->data);//寻找链表中倒数第1个元素
    printf("%d\n", find_tail(head,3)->data);//寻找链表中倒数第3个元素
    printf("%d\n", find_tail(head,5)->data);//寻找链表中倒数第5个元素
    printf("%d\n", find_tail(head,6)->data);//寻找链表中倒数第6个元素
    printf("%d\n", find_tail(head,8)->data);//寻找链表中倒数第8个元素
    printf("%d\n", find_tail(head,9)->data);//寻找链表中倒数第9个元素
    printf("%d\n", find_tail(head,10)->data);//寻找链表中倒数第10个元素

is_circl(head);
    creat_circl(head, 5);
    is_circl(head);
    printf("%d\n", wic_circl(head)->data);

get_no_circl(head);
    show(head);

dellist(head);
}

时间: 2024-10-06 03:09:03

单链表的经典操作,查找链表倒数第k个节点,判断链表是否存在环,求环节点的相关文章

链表倒数第k个结点、链表中间节点、链表是否有环

题目描述: 输入一个链表,输出该链表中倒数第k个结点. (hint: 请务必使用链表.) 输入: 输入可能包含多个测试样例,输入以EOF结束. 对于每个测试案例,输入的第一行为两个整数n和k(0<=n<=1000, 0<=k<=1000):n代表将要输入的链表元素的个数,k代表要查询倒数第几个的元素. 输入的第二行包括n个数t(1<=t<=1000000):代表链表中的元素. 输出: 对应每个测试案例, 若有结果,输出相应的查找结果.否则,输出NULL. 样例输入: 5

13输入一个单向链表,输出该链表中倒数第k个结点。链表的倒数第0个结点为链表的尾指针。

转载请注明出处:http://www.cnblogs.com/wuzetiandaren/p/4250795.html 声明:现大部分文章为寻找问题时在网上相互转载,此博是为自己做个记录记录,方便自己也方便有类似问题的朋友,本文的思想也许有所借鉴,但源码均为本人实现,如有侵权,请发邮件表明文章和原出处地址,我一定在文章中注明.谢谢. 题目:输入一个单向链表,输出该链表中倒数第k个结点.链表的倒数第0个结点为链表的尾指针. 题目分析: 1.链表的倒数第0个结点为链表的尾指针,设为r,则r指向最后一

单链表的增删查 逆置 倒数第k个节点等问题

    对于单链表而言,它没有双链表那么复杂,它只有头节点,尾节点,节点数据,后继指针.在下面本人实现了 单链表的 增   删   插  查  改.      #include<stdio.h> #include<assert.h> #include<malloc.h> #include<stdlib.h> typedef int Datatype; typedef struct SListNode { Datatype data; struct SList

剑指Offer 14. 链表中倒数第k个结点 (链表)

题目描述 输入一个链表,输出该链表中倒数第k个结点. 题目地址 https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&tqId=11167&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 思路 三个特例:如果输入的链表为空:k大于链表的长度:k为0的情况.对于正常情况,设置两个指针分

C++单链表找倒数第k个节点(时间复杂度为o(n)哦,用相距k节点的2个指针进行操作)

//输入一个单向链表,输出该链表中倒数第k个结点.链表的倒数第0个结点为链表的尾指针. //我的思路是2个指针往后面找,你想啊,如果是一个指针,肯定需要遍历2次,第一个遍历总共节点数,第二次才遍历最终结果 //这样的做法明显是不够好的,时间复杂度变成了2n,但是如果我们用2个指针,他们之间的距离差k个节点,有一个节点到达NULL //时(尾部),另一个节点就是我们要求的节点可以返回得到结果. #include <iostream> using namespace std; template&l

链表学习二:链表反转与查找倒数第K个

1 //单链表反转 2 ListNode* RevertList(ListNode* m_pHead){ 3 ListNode* pCurrent = m_pHead; 4 ListNode* pPrev=NULL; 5 ListNode* pNext =NULL; 6 7 while (pCurrent != NULL) 8 { 9 pNext = pCurrent->m_pNext; 10 pCurrent->m_pNext = pPrev; 11 pPrev = pCurrent; 12

数据结构与算法-链表查找倒数第K个值

查找链表中倒数第k个结点题目:输入一个单向链表,输出该链表中倒数第k个结点.链表的倒数第0个结点为链表的尾指针.链表结点定义如下: struct ListNode { int m_nKey; ListNode* m_pNext; }; int FindCoundDownInList(pListNode head,int num) { pListNode p1,p2; p1=p2=head; while(num-->0 && p1!=NULL) p1=p1->m_pNext; i

[算法]在单链表和双链表中删除倒数第k个结点

题目: 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 要求: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1). 解答: 让链表从头走到尾,每移动一步,就让K值减一,当链表走到结尾时,如果K值大于0,说明不用调整链表,因为链表根本没有倒数第K个节点,此时将原链表直接返回即可:如果K值等于0,说明链表倒数第K个节点就是头结点,此时直接返回head.next,相当于删除了头结点.当K的值小于零时,再次从头结点开始走,每移动一步,就让

求单链表倒数第k个结点

题目: 输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第0个结点为链表的尾指针. 分析: 设置两个指针p1,p2.首先p1和p2都指向head.然后p2向前走k步,这样p1和p2之间就间隔k个节点,然后p1和p2同.... #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; struct ListNode{ char data; ListNode* next;