王道书链表课后代码题

//考前一个月把真题中和王道书上所有的代码再自己手敲一遍,然后检查错误,所有的代码要非常熟练,其实瓜大考的代码题真的非常基础,多做点模板题就行
//注意把本章学习完成后,自己再动手把顺序表的课后题再敲一遍
//9.5 链表王道书课后代码题
#include<stdlib.h>
#include<iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
typedef  int ElemType;
#define MaxSize 100
typedef struct
{
    ElemType data[MaxSize];
    int top;//栈顶
}SqStack;

bool Push(SqStack &S,ElemType x)//入栈
{
    if(S.top==MaxSize-1)return  false;//栈满
    S.data[++S.top]=x;//相当于S.top++ S.data[top]=x;
    return true;
}

bool Pop(SqStack &S)
{
    if(S.top==-1)return false;
    cout<<S.data[top--]<<endl;//输出栈顶元素  首先cout 然后再进行top--
}
int Length(LinkList L)
{
    int length;
    LNode *p=L->next;
    while(p!=NULL)
    {
        length ++;
    }
    return length;
}


//1.递归删除不带头结点的链表中值为x的结点
void Delete(LinkList &L,int x)
{
      LNode *p;
      if(L->data==x)
      {
        p = L;
        L = L->next;
        free(p);
        Delete(L,x);
      }//若data!=x,则向下继续调用
      else {  Delete(L->next,x);  }


}
//2.删除所有值为x的结点
void DeleteElem(LinkList &L,int x)
{
    LNode *p=L->next;
    while(p!=NULL)
    {
        if(p->next->data==x)//注意是找到值为x的前面一个结点有利于删除
        {
            LNode *q=(LNode*)malloc(sizeof(LNode));
            q = p->next;
            p->next = q->next;
            free(q);
        }
        p = p->next;
    }
}

//3.链表反向输出
//法一:借用辅组数组
void PrintReverse(LinkList L,int a[])
{
    int i = 0;
    LNode *p=L->next;
    while(p!=NULL)
    {
        a[i++]=p->data;
        p  = p->next;      
    }
    for(int j=i;j>0;j--)cout<<a[j]<<endl;  //在辅助数组中反向输出
}
//法二:利用栈
void PrintReverse(LinkList L)
{
    SqStack &S;//使用栈
    LNode *p=L->next;
    while(p!=NULL)
    {
        Push(S,p->data);  //入栈
    }
    
    while(S.top!=-1)
    {
        Pop(S);//依次出栈输出序列;
    }
}


//4.删除链表中一个最小的元素
//法一:
void DeleteMinNode(LinkList &L)
{
    int min;
    LNode *p=L->next;
    min = p->data;
    //可以定义一个下一个结点是最小值结点的结点
    while(p!=NULL)
    {
        if(p->data<min)min=p->data;//更新min
        p = p->next;
    }
    for(p=L->next;p!=NULL;p=p->next)
    {
        if(p->next->data==min)
        {
            LNode *q = p->next;
            p->next = q->next;
            free(q);
        }
    }
}
//法二
void DeleteMinNode(LinkList &L)
{
    int min;
    LNode *p=L->next;
    LNode *minpre;
    min = p->data;
    //可以定义一个下一个结点是最小值结点的结点
    while(p!=NULL)
    {
        if(p->next->data<min)
        {  
            min=p->next->data;
            minpre = p;
        }//更新min
        p = p->next;
    }
    LNode *q=minpre->next;
    minpre->next = q->next;
    free(q);//minpre->next所指向的就是最小值的结点,即对q进行free
}

//5.链表逆置 :
//法一:头插法实现链表逆置
void Reverse(LinkList &L)
{
    LNode *p=L->next;
    L->next = NULL;//重新链表置空
    L->next = p;//首先将L->next = p;指向p
    while(p!=NULL)
    {
       LNode *r = p->next; //r为p的后继,防止断链   头插法一般要使用一个存储结点
       p->next = L->next;
       L->next = p;
       p = r;     
    }
}



//6.设计算法使其元素递增有序:
//法一:借用辅助数组首先对链表中的元素进行排序,然后将排序好的序列导入链表,使其有序
void IncreaseSquence(LinkList &L,int a[])
{
    
}

//法二:直接对链表进行排序,交换结点的信息值:冒泡法 或者使用直接插入排序
void IncreaseSq(LinkList &L )
{
    int temp;
   LNode *p = L->next;
    LNode *q=L->next;
   while(q!=NULL)
   {
       for(p=q;p!=NULL;p=p->next)
       { 
           if(p->data>p->next->data)
       {
           temp = p->data;
           p->data = p->next->data;
           p->next->data = temp;//交换
       }
       
       }
      q = q->next;//冒泡排序,每一次把最小的送过来 时间复杂度为O(n^2)

   }
    


}

//7.删除介于给定两个值之间的元素
void DeleteStoT(LinkList &L,ElemType s,ElemType t)
{
     if(s>=t)return ;
     LNode *p=L->next;
     while(p!=NULL)
     {

         if(p->next->data > s&&p->next->data<t)
         {
             LNode *q = p->next;
             p->next = q->next;
             free(q);
         }
         p = p->next;
     }
}
//答案一般都是使用的利用一个pre指针来进行删除,其实使用p->next判断的方法也是可行的,只不过没有保存指针

.

//10.划分奇偶元素
void Divided(LinkList &A,LinkList &B)
{
    LNode *p=A->next;
    LNode *r=B->next;//尾插法建立链表
    int j = 1;
    for(;p!=NULL;p=p->next,j++)
    {
        if(j%2==0)
        {
            LNode *q = p;
            r->next = p;
            r = p;
            free(q);//若free(p),则找不到下一次循环进入的入口,不可将其作为辅助变量释放空间

        }
    }
}
//答案的方法是先保存A的信息然后把A置空,重新来创建链表
//11.拆分链表 :注意B是从小到大,对A使用尾插法,对B使用尾插法
void DisPatch(LinkList &A,LinkList &B,LinkList &C)
{
    LNode *rA=A->next;//A的尾指针
    LNode *rB;
    LNode *p=C->next;
    int j = 1;
    for(;p!=NULL;p=p->next,j++)
    {
        if(j%2==0){rA->next = p;rA = p;}
        else{rB=p->next;p->next = B->next;B->next = p;p=rB; }//注意在此使用尾插法
    }
    rA->next = NULL;//后面的元素置空
}
//12.删除重复的元素
void DeleteRepeatElem(LinkList &L)
{
    LNode *p=L->next;
    if(p==NULL)return ;
    while(p!=NULL)
    {
        if(p->data == p->next->data)
        {
            LNode *q = p->next;
            p->next = q->next;
            free(q);
          
        }
        p = p->next;   
    }
}

//13.链表的归并
//法一:大胖の垃圾方法
/*
   step1:首先将链表逆置
   step2:开辟数组来存放归并排序的次序
   step3:将数组中的元素放置于两个链表中覆盖原来的元素
*/
void Reverse(LinkList &L)
{
    //将链表逆置
}
void MergeSort(LinkList &A,LinkList &B,int a[])
{
     Reverse(A);
     Reverse(B);
     LNode *p=A->next;
     LNode *q=B->next;
     A->next = NULL;//将A置空
     int k=0;
     while(p!=NULL&&q!=NULL)
     {
         if(p->data > q->data){a[k++]=p->data;p=p->next;}
         else {a[k++]=q->data;q=q->next;}
     }
     while(p!=NULL){a[k++]=p->data;p=p->next;}
     while(q!=NULL){a[k++]=q->data;q=q->next;}
     int i ,j=0;
    //用A来保存归并后的结果
    for(int i=0;i<k;i++)
    {
        p->data = a[i];
        p = p->next;//依次向下搜索
    }
//法二:利用头插法+归并
}
void MergeSort(LinkList &A,LinkList &B)
{
    LNode *r;//用于头插
    LNode *pa = A->next;
    LNode *pb = B->next;
    A->next = NULL;//A置为空保存归并后的结果
    while(pa!=NULL&&pb!=NULL)
    {
        if(pa->data<=pb->data)
        {
            r = pa->next;
            pa->next = A->next;
            A->next = pa;
            pa = r;
        }
        else 
        {
            r = pb->next;
            pb->next = A->next;
            A->next = pb;
            pb = r;
        }
    }
    if(pa!=NULL)pb = pa;//以下两个判断逻辑可以实现对任何一个链表非空进行插入
    while(pb)
    {
        r = pb->next;
        pb->next = A->next;
        A->next = pb;
        pb = r;
    }
    free(B);

}



// 14.找公共元素
//法一:
void PublicElem(LinkList A,LinkList B,LinkList &C)
{
    if(A->next==NULL||B->next==NULL)
    {
        return ;
    }
    LNode *p=A->next;
    LNode *q=B->next;
    LNode *r = C;//r指向C链表的尾部,利用尾插法来建立链表
    while(p!=NULL)
    {
            for(q=B->next;q!=NULL;q=q->next)
            {
               if(p->data==q->data)//两层遍历找到A B的公共元素
               {
                   LNode *s=(LNode*)malloc(sizeof(LNode));                    //用此时的p或者q指针都可以
                   s->data = p->data;
                   r->next = s;
                   r = s;//尾插法重新将尾指针指向s
                   continue;//跳出
               }   
            }
        p = p->next;

    }
}
//法二:元素较小者后移,利用三个分支判断,在第三个分支内创建链表
void PublicElem(LinkList A,LinkList B,LinkList &C)
{
    if(A->next==NULL||B->next==NULL)
    {
        return ;
    }
    LNode *p=A->next;
    LNode *q=B->next;
    LNode *r = C;//r指向C链表的尾部,利用尾插法来建立链表
    while(p!=NULL&&q!=NULL)
    {
        if(p->data < q->data)p = p->next;
        else if(p->data>q->data)q = q->next;
        else 
        {
               LNode *s=(LNode*)malloc(sizeof(LNode));                    //用此时的p或者q指针都可以
                   s->data = p->data;
                   r->next = s;
                   r = s;//尾插法重新将尾指针指向s
                   p = p->next;
                   q = q->next;
        }
    }
    r->next = NULL;//注意利用尾插法创建链表完成后,最后尾指针的next域要指向NULL    
}
//由于本题是递增序列,可以不用O(n2)复杂度的算法,可以利用一些优化的算法,看一下答案最优算法,链表归并问题

//15 取交集 存放到A 可以使用辅助数组  
//算法思想:
//step1:两层循环分别遍历,由于最后需要将公共元素存放至A,则在A中只保存公共元素即可
//step2:将不是公共元素的结点free掉,最终保存都是公共元素结点
void PublicElem(LinkList &A,LinkList B)
{
    if(A->next==NULL||B->next==NULL)
    {
        return ;
    }
    LNode *p=A->next;
    LNode *q=B->next;
   // LNode *r = C;//r指向C链表的尾部,利用尾插法来建立链表
    while(p!=NULL)
    {
            for(q=B->next;q!=NULL;q=q->next)
            {
               if(p->data==q->data)//两层遍历找到A B的公共元素
               {
                    continue;//找到相同跳出
               }   
            }
        LNode *de = p;
        p = p->next;
        free(de);//把不是公共的元素进行free
    }
}

//答案做法:
void PublicElem(LinkList &A,LinkList B)
{
    LNode *pa = A->next;
    LNode *pb = B->next;
    LNode *r = A;//利用尾插法建立链表
    while(pa!=NULL&&pb!=NULL)
    {
        if(pa->data == pb->data)
        {
            r->next = pa;
            r = pa;
            pa = pa->next;//头插法将公共元素插入A中
            LNode *q;
            q = pb; 
            pb = pb->next;
            free(q);//将B中的公共元素进行free 释放掉公共元素
        }
        else if(pa->data<pb->data)//若不相等,将较小的元素后移
        {
            LNode *de = pa;
            pa = pa->next;
            free(de);
        }
        else 
        {
            LNode *de=pb;
            pb = pb->next;
            free(de);
        }
    }
    while(pa)
    {
          LNode *de = pa;
            pa = pa->next;
            free(de);

    }
       while(pb)
    {
        LNode *de=pb;
            pb = pb->next;
            free(de);

    }
   r->next =NULL;
   free(B);
}

//16题 B是否为A的子序列,先找到公共结点,然后依次遍历  类似于KMP
bool SubSequence(LinkList A,LinkList B)
{
    LNode *pa = A->next;
    LNode *pb = B->next;
    while(pa&&pb)
    {
        if(pa->data==pb->data)
        {
            pa = pa->next;
            pb = pb->next;
        }
        else 
        {
            pa = pa->next;
            pb = B->next;//匹配失败,B从头开始
        }
    }
    if(pb=NULL)return true;
    else return false;//匹配失败

}

//双链表结构体定义
typedef int ElemType ;
typedef struct DNode
{
    ElemType data;
    struct  DNode *next;
    struct  DNode *prior;
    
}DNode,*DLinkList;


//17 判断双链表是否为对称的:重点是找到头和尾然后依次一个向前一个向后比较

void DUICHEN(DLinkList L)
{
    DNode *p = L->next;//头结点指向的第一个结点
    DNode *q = L->prior;//表尾指针
    while(p!=NULL&&q!=NULL)//循环跳出条件??需要改正
    {
        if(p->data==q->data)
        {
             p = p->next;//后移
             q = q->prior;//前移
        }
        else cout<<"不对称"<<endl; break;

    }
    cout<<"对称"<<endl;
}

//18 链接两个循环链表
void Link(LinkList &A,LinkList B)
{
    //A B 为循环链表
    LNode *h1=A->next;
    LNode *h2=B->next;
    while(h1!=NULL)
    {
        h1=h1->next;//找到A表的末结点
    }
    h1->next = B;//h1指向B链表的头指针
    while(h2!=NULL)
    {
        h2=h2->next;
    }
    h2->next = A;//合并完成

}

//19 可以使用递归算法
void DeleteMinNode(LinkList &L)
{
    int min;
    while(L->next!=L)
    {
    LNode *p=L->next;
    LNode *minpre=L;
    min = p->data;
    //可以定义一个下一个结点是最小值结点的结点
    while(p!=NULL)
    {
        if(p->next->data<min)
        {  
            min=p->next->data;
            minpre = p;
        }//更新min
        p = p->next;
    }
    cout<<"最小值为:"<<min<<endl;
    LNode *q=minpre->next;
    minpre->next = q->next;
    free(q);
    }
     free(L);
}

//24 判断一个链表是否有环 ?
//注意进入环以后不可能有指向NULL的结点,所有若slow或者fast==NULL则一定可以判定无环
LNode *FindLoopStart(LNode *head)
{
    LNode *fast = head;
    LNode *slow = head;
    while(slow!=NULL&&fast->next!=NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow==fast)break;
    }
    if(slow==NULL||fast->next==NULL)
    {
        return NULL;
    }
    LNode *p1=head;
    LNode *p2=slow;
    while(p1!=p2)
    {
        p1=p1->next;
        p2=p2->next;
    }
    return p1;
}







//25 2019年408真题 
//本题可分为三个板块:1.找到中间结点 2.中间结点以后的内容进行逆置 3.头插法依次插入
void SpeicalSort(LinkList &L)
{
    LNode *p=L->next;
    LNode *q=L->next;//跳两步指针
     LNode *r;
    while(p&&q)
    {
        p = p->next;
        q = q->next;
        if(q->next!=NULL)q = q->next;//执行完以后p便是指向了中间结点
    }
    //中间结点以后的结点进行逆置
    LNode *mid = p;//用mid暂存中间结点的位置
    LNode *head = p;
    while(p!=NULL)
    {
        r = p->next;
        r->next = head->next;
        head->next = r;
        p = r;
    }
    head = L->next;
    q = mid->next;//
    while(q!=NULL)
    {
        r = q->next;
        q->next = head->next;
        head->next = q;
        head = q->next;
        q = r; 
    }

}





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值