合并链表,判断链表是否有环、是否相交,相交的第一个节点,进入环的第一个节点,O(1)时间复杂度删除某节点

#include<iostream>
#include<assert.h>
#include<stdlib.h>
#include<stack>
#define type char
using namespace std;
typedef struct node{
        struct node *next;
        type value;
}mynode;
/********************************************/
//尾插法创建列表
/********************************************/
mynode *create_node()
{
    mynode *head,*pre,*p;
    type x;
    head=(mynode *)malloc(sizeof(mynode));
    assert(head!=NULL);
    head->next=NULL;
    pre=head;
    cout<<"输入各节点的值,以0结束:";
    while(cin>>x && x!='0')
    {
        p=(mynode *)malloc(sizeof(mynode));
        assert(p!=NULL);
        p->value=x;
        p->next=pre->next;
        pre->next=p;
        pre=p;
    }
    return head->next;
}
/********************************************/
//显示打印列表
/********************************************/
void print_node(mynode *head)
{
    mynode *p;
    cout<<"打印链表:";
    p=head;
    while(p)
    {
        cout<<p->value<<"--";
        p=p->next;
    }
    if(p==NULL)
        cout<<"^-"<<endl;
}
/*******************************************/
//已知两个单链表各自有序,把它们合并成一个链表依然有序
//已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序
//先比较两个头元素,确定新链的头元素phead,此时切记phead->next=NULL,切断其与前链表的关系
//下面进行比较完,都要执行此步骤
/*******************************************/
//非递归
mynode* mergesortedlist(mynode *head1,mynode *head2)
{
    if(head1==NULL)
        return head2;
    if(head2==NULL)
        return head1;
    mynode *phead,*p;
    if(head1->value<head2->value)
    {
        phead=head1;
        head1=head1->next;
    }
    else
    {
        phead=head2;
        head2=head2->next;
    }
    phead->next=NULL;
    p=phead;
    while(head1 && head2)
    {
         if(head1->value<head2->value)
        {
            p->next=head1;
            head1=head1->next;
        }
        else
        {
            p->next=head2;
            head2=head2->next;
        }
        p=p->next;
        p->next=NULL;
    }
    if(head1==NULL)
        p->next=head2;
    else if(head2==NULL)
        p->next=head1;
    cout<<"合并后链表如下:"<<endl;
    return phead;
}
//递归
mynode* mergesortlist(mynode *head1,mynode *head2)
{
    mynode *phead=NULL;
    if(head1==NULL)
         return head2;
    if(head2==NULL)
         return head1;
    if(head1->value<head2->value)
    {
        phead=head1;
        phead->next=mergesortlist(head1->next,head2);
    }
    else
    {
        phead=head2;
        phead->next=mergesortlist(head1,head2->next);
    }
    return phead;
}
/****************************************/
//判断一个链表是否有环
//设定两个指针,其中一个指针走一步,另一个走两步,如果存在环,两个指针肯定相遇。
/****************************************/
void is_circle(mynode *head)
{
    assert(head!=NULL);
    mynode *p1,*p2;
    p1=p2=head;
    while(p2 && p2->next)
    {
        p2=p2->next->next;
        p1=p1->next;
        if(p1==p2)
        {
            cout<<"链表中存在环"<<endl;
            return;
        }
    }
    cout<<"链表中没有环"<<endl;
}
/*********************************************/
//判断两个链表是否相交
//只需要分别对两个链表遍历一边,然后判断最后一个节点是否相等即可
/*********************************************/
void is_intersect(mynode *head1,mynode *head2)
{
    assert(head1!=NULL && head2!=NULL);
    mynode *p1=head1;
    while(p1->next)
        p1=p1->next;
    mynode *p2=head2;
    while(p2->next)
        p2=p2->next;
    if(p1==p2)
        cout<<"两个链表相交"<<endl;
    else
        cout<<"两个链表不相交"<<endl;

}
/************************************/
//求两个单链表相交的第一个节点
//首先判断两个链表是否相交,同时记录链表的长度len1,len2
//先对齐两个链表的当前节点,然后一起向后遍历
/************************************/
mynode *findfirstcommonnode(mynode *head1,mynode *head2)
{
    assert(head1!=NULL && head2!=NULL);
    int len1,len2;
    mynode *p1,*p2;
    len1=len2=1;
    p1=head1;
    p2=head2;
    while(p1->next)
    {
        len1++;
        p1=p1->next;
    }
    while(p2->next)
    {
        len2++;
        p2=p2->next;
    }
    if(p1!=p2)  //先判断两个链表是否相交
    {
        cout<<"两个链表不相交" << endl;
        return NULL;
    }
    mynode *p3,*p4;
    int n=abs(len1-len2);
    p3=head1;
    p4=head2;
    if(len1>len2) //两个链表的当前指针要对齐
    {
        while(n--)
            p3=p3->next;
    }
    else
    {
        while(n--)
            p4=p4->next;
    }
    while(p3!=p4) //一起向后遍历,相等就退出,并输出
    {
        p3=p3->next;
        p4=p4->next;
    }
    return p3;
}
/***************************************/
//已知一个单链表中存在环,求进入环中的第一个节点
//首先判断是否有环,在环的一个节点处断开,形成两个相交的单链表,而这个节点作为这两个单链表的尾节点
//此时问题转化为求两个单链表相交的第一个节点
/***************************************/
mynode *findfirstnodeincircle(mynode *head)
{
    assert(head!=NULL && head->next!=NULL);
    mynode *p1,*p2;
    p1=p2=head;
    while(p2!=NULL && p2->next!=NULL)//判断是否有环
    {
        p1=p1->next;
        p2=p2->next->next;
        if(p1==p2)
            break;
    }
    assert(p2!=NULL && p2->next!=NULL);
    //形成两个相交的单链表p3、p4,它们的尾节点是ptailnode
    mynode *ptailnode=p1;
    mynode *p3=head;
    mynode *p4=ptailnode->next;
    mynode *p5=p3;
    mynode *p6=p4;
    int len1,len2,n;
    len1=len2=0;
    while(p5!=ptailnode)
    {
        p5=p5->next;
        len1++;
    }
    while(p6!=ptailnode)
    {
        p6=p6->next;
        len2++;
    }
    //求相交的第一个节点即满足题目要求
    n=abs(len1-len2);
    if(len1>len2)
    {
        while(n--)
          p5=p5->next;
    }
    else{
        while(n--)
            p6=p6->next;
    }
    //对齐链表的当前节点
    while(p5!=p6)
    {
        p5=p5->next;
        p6=p6->next;
    }
    return p5;
}
/************************************/
//给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted
//对于删除节点,我们普通的思路就是让该节点的前一个节点指向该节点的下一个节点,
//这种情况需要遍历找到该节点的前一个节点,时间复杂度为O(n)。
//对于链表,链表中的每个节点结构都是一样的,
//所以我们可以把该节点的下一个节点的数据复制到该节点,然后删除下一个节点即可。
//要注意最后一个节点和只有一个节点的情况,这个时候只能用常见的方法来操作,
//先找到前一个节点,但总体的平均时间复杂度还是O(1)
/*************************************/

int main()
{
    mynode *head1;
    mynode *head2;
    head1=create_node();
    head2=create_node();
    print_node(head1);
    print_node(head2);
    print_node(mergesortlist(head1,head2));
    //print_node(mergesortedlist(head1,head2));
    //is_circle(head1);
    //is_intersect(head1,head2);
    //findfirstcommonnode(head1,head2);
    return 0;
}
//引自http://blog.csdn.net/luckyxiaoqiang/article/details/7393134


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值