编程题实训-链表应用

第1关:基于链表的两个一元多项式的基本运算

任务描述

本关任务:给定两个一元多项式A(x)与B(x),利用链表表示A(x)与B(x),实现A(x)与B(x)的加法、减法、乘法和求导运算。

编程要求

输入

输入多组数据,总计n*( a+b+2)+1行。其中,第一行整数n代表总计有n组数据,之后依次输入n组数据。每组数据包括a+b+2行,其中第一行是两个整数a和b,分别代表A(x)与B(x)的项数。之后紧跟a行,每行两个整数a1和a2,分别代表A(x)每项的系数和指数,再之后紧跟b行,每行两个整数b1和b2,分别代表B(x)每项的系数和指数,每组数据最后一行为一个字符(+、-、*、'),分别代表多项式的加法、减法、乘法和求导运算。所有数据的绝对值小于100,指数大于等于0。

输出

对于每组数据输出一行,按照多项式次数从大到小排列,参考格式:5x^17+22x^7+11x^1+7。

#include <iostream>
#include <string>
using namespace std;
typedef struct  LNode{
	int coe;
	int exp;
	struct LNode *next;
}LNode,*LinkList;
void CreatePolynomial(LinkList &L,int n){
	L = new LNode;
	L->next = NULL;
	for(int i=0;i<n;i++){
		LinkList p = new LNode;
		cin>>p->coe>>p->exp;
		LinkList pre =L,cur = L->next;
		while(cur&&p->exp<cur->exp){
			pre = cur;
			cur = cur->next;
		}
		p->next = cur;
		pre->next=p;
	}
}
void OutputPolynomial(LinkList L)
{//输出多项式
	if(!L||!L->next) cout<<0;
	LinkList p=L->next;     //p是多项式链表的工作指针,初始化为首元结点
	while(p)
	{
		if(p==L->next)     //p指向首元结点时,根据指数的情况输出多项式
        {
			if (p->exp!=0)
				cout<<p->coe<<"x^"<<p->exp;
			else
				cout<<p->coe;
		}
		else      //p指向其他结点时,根据系数的正负和指数的情况输出多项式
        {
			if(p->coe>0) cout<<"+";
			if(p->exp!=0)
				cout<<p->coe<<"x^"<<p->exp;
			else
				cout<<p->coe;
		}
		p=p->next;
	}
	cout<<endl;
}


LinkList Add(LinkList LA,LinkList LB){
	LinkList pa = LA->next;
	LinkList pb = LB->next;
	LinkList LC;
	CreatePolynomial(LC,0);
	LinkList pc = LC;
	while(pa&&pb){
		if(pa->exp == pb->exp){
			int sum = pa->coe + pb->coe;
			if(sum){
				pa->coe = sum;
				pc->next = pa;
				pc = pa;
				pa = pa->next;
				pb = pb->next;
			}else{
				pa = pa->next;
				pb = pb->next;
			}
		}else if(pa->exp>pb->exp){
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}else{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}
	pc->next = pa?pa:pb;
	return LC;
}


void Minus(LinkList LA,LinkList LB){
	LinkList p = LB->next;
	while(p){
		p->coe*= -1;
		p = p->next;
	}
	OutputPolynomial(Add(LA,LB));
}

LinkList Mul(LinkList LA,LinkList LB){
	LinkList pa = LA->next;
	LinkList pb = LB->next;
	LinkList LC;
	CreatePolynomial(LC,0);
	LinkList temp;
	CreatePolynomial(temp,0);
	while(pa){
		while(pb){
			LinkList p = new LNode;
			p->next = NULL;
			p->coe = pa->coe*pb->coe;
			p->exp = pa->exp + pb->exp;
			temp->next = p;
			LC = Add(LC,temp);
			pb = pb->next;  
		}
		pb = LB->next;
		pa = pa->next;
	}
	OutputPolynomial(LC);
	
}

void Diff(LinkList L)
{//多项式的求导运算
	LinkList p=L->next;  //p是链表L的工作指针,初始化为首元结点
	LinkList r=NULL;  //r是删除操作的辅助指针
	while(p)
	{
		p->coe*=p->exp;
		p->exp--;
		if(p->exp<0)  //所有数据的指数大于等于0
        {
			r=p;
			p=p->next;
			delete r;
		}
		else
		{
			p=p->next;
		}
	}
	OutputPolynomial(L);
}

void Opt(LinkList &LA,LinkList &LB,string s)
{//依据字符选择多项式的加法、减法、乘法和求导运算
    if(s=="+") OutputPolynomial(Add(LA, LB));
    if(s=="-") Minus(LA, LB);
    if(s=="*") Mul(LA, LB);
    if(s=="'")
    {
        Diff(LA);
        Diff(LB);
    }
}


int main(){
	int n;
	cin>>n;
	while(n--){
		int a,b;
		cin>>a>>b;
		LinkList LA,LB;
		CreatePolynomial(LA,a);
		CreatePolynomial(LB,b);
		string s;
		cin>>s;
		Opt(LA,LB,s);
	}
	return 0;
}

第2关:基于链表的两个递增有序序列的合并

任务描述

本关任务:给定两个递增的整数序列A和B,利用链表表示序列A和B,将A和B合并为一个递增的有序序列C,序列C不允许有重复的数据。要求空间复杂度为O(1)。

编程要求

输入

多组数据,每组数据有三行,第一行为序列A和B的长度n和m,第二行为序列A的n个元素,第三行为序列B的m个元素(元素之间用空格分隔)。n=0且m=0时输入结束。

输出

对于每组数据输出一行,为合并后的序列,每个数据之间用空格分隔。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void PrintList(LinkList &L)
{//打印依次输出链表中的数据
    L=L->next;
    while(L){
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
    }
    cout<<endl;
}
void MergeList(LinkList &LA,LinkList &LB)
{//求基于链表的两个递增有序序列的合并
/**************begin************/
    
LinkList pa,pb,pc,q;
LinkList LC;
    pa=LA->next;
    pb=LB->next;
    pc=LC=LA;
    while (pa&&pb)
    {
        if (pa->data<pb->data)
        {
            pc->next=pa;
            pc=pa;
            pa=pa->next;
        }
        else if (pa->data>pb->data)
        {
            pc->next=pb;
            pc=pb;
            pb=pb->next;
        }
        else 
        {
            pc->next=pa;  //删掉一样的
            pc=pa;
            pa=pa->next;
            q=pb->next;
            delete pb;
            pb=q;
        }
    }
    pc->next=pa?pa:pb;  //如果一个序列比完,结束循环,剩余的直接插在链表后面
    delete LB;


    /**************end************/
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0&&m==0) break;
        LinkList LA,LB;
        CreateList_R(LA,n);
        CreateList_R(LB,m);
        MergeList(LA,LB);
        PrintList(LA);
    }
    return 0;
}

第3关:基于链表的两个非递减有序序列的合并

编程要求

输入

多组数据,每组数据有三行,第一行为序列A和B的长度n和m,第二行为序列A的n个元素,第三行为序列B的m个元素(元素之间用空格分隔)。n=0且m=0时输入结束。

输出

对于每组数据输出一行,为合并后的序列,每个数据之间用空格分隔。

//要结合上下文,本题与上题思路相似,但注意主函数中PrintList(LC);

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void PrintList(LinkList &L)
{//打印依次输出链表中的数据
    L=L->next;
    while(L){
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
    }
    cout<<endl;
}
void MergeList(LinkList &LA,LinkList &LB,LinkList &LC)
{//求基于链表的两个非递减有序序列的合并
/**************begin************/
LinkList pa,pb,pc,q;
pa=LA->next;
pb=LB->next;
LC=pc=LA;
LC->next=NULL;
while (pa||pb)
{
    if (!pa)//LA表为空,用q指向pb,pb指针后移
    {
        q=pb;
        pb=pb->next;
    }
    else if (!pb)//LB表为空,用q指向pa,pa指针后移
    {
        q=pa;
        pa=pa->next;
    }
    else if (pa->data<=pb->data)
    {
        q=pa;
        pa=pa->next;
    }
    else 
    {
        q=pb;
        pb=pb->next;
    }
    q->next=LC->next;
    LC->next=q;//将q指向的节点插在LC表的表头节点之后
}
delete LB;



    /**************end************/
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0&&m==0) break;
        LinkList LA,LB,LC;
        CreateList_R(LA,n);
        CreateList_R(LB,m);
        MergeList(LA,LB,LC);
        PrintList(LC);
    }
    return 0;
}

第4关:基于链表的两个集合的交集

任务描述

本关任务:给定两个递增的整数集合A和B,分别用链表表示集合A和B,求出A和B的交集,并存放在A中。要求空间复杂度为O(1)。

编程要求

输入

多组数据,每组数据有三行,第一行为序列A和B的长度n和m,第二行为序列A的n个元素,第三行为序列B的m个元素(元素之间用空格分隔)。n=0且m=0时输入结束。

输出

对于每组数据输出一行,为A和B的交集,每个数据之间用空格分隔。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void PrintList(LinkList &L)
{//打印依次输出链表中的数据
    L=L->next;
    while(L){
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
    }
    cout<<endl;
}
void Intersection(LinkList &LA,LinkList &LB)
{//求基于链表的两个集合的交集
/**************begin************/
LinkList pa,pb,pc,u,LC;
pa=LA->next;
pb=LB->next; //pa 和 pb 分别是链表 La 和 Lb 的工作指针 , 初始化为相应链表的第一个结点
	LC=pc=LA; // 用 La 的头结点作为 Lc 的头结点
	while(pa&&pb) 
	{ 
		  if (pa->data==pb->data)//交集并入结果表中。
	 	  { pc->next=pa;
            pc=pa;pa=pa->next; 
	        u=pb;pb=pb->next; 
            delete u;
          } 
		else if(pa->data<pb->data) 
		{
        u=pa;
        pa=pa->next; 
        delete u;
        } 
		else 
		{
        u=pb; 
        pb=pb->next;
        delete u;
        } 
	}
	while(pa)
    {
    u=pa; 
    pa=pa->next; 
    delete u;
    } //释放结点空间
	 while(pb) 
     {
     u=pb; 
     pb=pb->next; 
     delete u ;
     } //释放结点空间
	pc->next=NULL;//置链表尾标记。
	delete LB; // 释放 Lb 的头结点


    /**************end************/
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0&&m==0) break;
        LinkList LA,LB;
        CreateList_R(LA,n);
        CreateList_R(LB,m);
        Intersection(LA,LB);
        PrintList(LA);
    }
    return 0;
}

第5关:基于链表的两个集合的差集

任务描述

本关任务:给定两个递增的整数集合,分别用链表A和B表示,求出A和B的差集(即仅由在A中出现而不在B中出现的元素所构成的集合),并以同样的形式存储,同时返回该集合的元素个数。要求空间复杂度为O(1)。

编程要求

输入

多组数据,每组数据有三行,第一行为序列A和B的长度n和m,第二行为序列A的n个元素,第三行为序列B的m个元素(元素之间用空格分隔)。n=0且m=0时输入结束。

输出

对于每组数据输出两行,第一行是A和B的差集,第二行为差集中的元素个数,每个数据之间用空格分隔。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void PrintList(LinkList &L)
{//依次输出链表中的数据和该集合的元素个数
    L=L->next;
    int s=0;
    while(L)
    {
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
        s++;
    }
    cout<<endl<<s<<endl;
}
void Difference(LinkList &LA,LinkList &LB)
{//求基于链表的两个集合的差集
/**************begin************/
   LinkList pa,pb,u,pre;
pa=LA->next;
pb=LB->next;
pre=LA;//pre为LA中pa所指结点的前驱结点的指针
while (pa&&pb)
{
    if (pa->data<pb->data)
    {
        pre=pa;
        pa=pa->next;
       
    }
    else if (pa->data>pb->data)
    {
        pb=pb->next;

    }
    else 
    {
        pre->next=pa->next;//处理A,B中元素相同的结点,应删除
        u=pa;
        pa=pa->next;
        delete u;
    }
}



   
    /**************end************/
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0&&m==0) break;
        LinkList LA,LB;
        CreateList_R(LA,n);
        CreateList_R(LB,m);
        Difference(LA,LB);
        PrintList(LA);
    }
    return 0;
}

第6关:链表的分解

任务描述

本关任务:利用单链表A表示一个非零整数序列,把A分解为两个具有相同结构的链表B和C,其中B表的结点为A表中值小于零的结点,而C表的结点为A表中值大于零的结点。要求空间复杂度为O(1),链表B和C均利用链表A的结点空间。

编程要求

输入

多组数据,每组数据有两行,第一行为链表A的长度n,第二行为链表A的n个元素(元素之间用空格分隔)。当n=0时输入结束。

输出

对于每组数据分别输出两行,分别对应链表B和C的元素,每个数据之间用空格分隔。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void PrintList(LinkList &L)
{//打印依次输出链表中的数据
    L=L->next;
    while(L){
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
    }
    cout<<endl;
}
void Decompose(LinkList &LA,LinkList &LB,LinkList &LC)
{//链表的分解
/**************begin************/
    LB=new LNode;
  LB->next=NULL;
  LC=new LNode;
  LC->next=NULL;
  LinkList pa=LA->next,pb=LB,pc=LC,q;//pa,pb和pc分别是LA,LB和LC的工作指针,q暂存pa的后继
  while (pa!=NULL)
  {
      q=pa->next;
      if (pa->data<0)//将小于0的结点链入LB表,尾插法
      { 
        pb->next=pa;
        pb=pa;
      }
      else
      {
        pc->next=pa;
        pc=pa;
      }
      pa=q;
  }
  pb->next=NULL;
  pc->next=NULL;
  


  
    /**************end************/
}
int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0) break;
        LinkList LA,LB,LC;
        CreateList_R(LA,n);
        Decompose(LA,LB,LC);
        PrintList(LB);
        PrintList(LC);
    }
    return 0;
}

第7关:查找链表中的最大值 

任务描述

本关任务:利用单链表表示一个整数序列,通过一趟遍历在单链表中确定值最大的结点。

编程要求

输入

多组数据,每组数据有两行,第一行为链表的长度n,第二行为链表的n个元素(元素之间用空格分隔)。当n=0时输入结束。

输出

对于每组数据分别输出一行,输出每个链表的最大值。

#include <iostream>
using namespace std;

typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;

void CreateList_R(LinkList &L,int n)
{
    L->next=NULL;
    LinkList r=new LNode;
    r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}

int MaxData(LinkList L)
{//确定单链表中值最大的结点
/**************begin************/
  LinkList p ,MaxData;
  if (L->next==NULL)
  return NULL;
   MaxData=L->next;
   p=L->next->next;
  while (p!=NULL)
  {
      if (p->data > MaxData->data)// 如果 p 的值大于 pmax 的值,则重新赋值
      {
        MaxData=p;
      }
      p=p->next;
  } 
return MaxData->data;



  
    /**************end************/
}

int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0) break;
        LinkList L=new LNode;
        CreateList_R(L,n);
        cout<<MaxData(L)<<endl;
    }
    return 0;
}

第8关:链表的逆转 

任务描述

本关任务:利用单链表表示一个整数序列,通过一趟遍历,将单链表中所有结点的链接方向逆转。要求空间复杂度为O(1)。

编程要求

输入

多组数据,每组数据有两行,第一行为链表的长度n,第二行为链表的n个元素(元素之间用空格分隔)。当n=0时输入结束。

输出

对于每组数据分别输出一行,逆序输出链表中的元素,元素之间用空格分隔。

#include <iostream>
using namespace std;

typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;

void CreateList_R(LinkList &L,int n)
{
    L->next=NULL;
    LinkList r=new LNode;
    r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}

void Inverse(LinkList &L)
{//逆置带头结点的单链表L
/**************begin************/
LinkList p,q;
p=L->next;
L->next=NULL;
while (p)
{
    q=p->next;
    p->next=L->next;
    L->next=p;
    p=q;
}




    /**************end************/
}

void PrintList(LinkList &L)
{
    L=L->next;
    while(L){
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
    }
    cout<<endl;
}

int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0) break;
        LinkList L=new LNode;
        CreateList_R(L,n);
        Inverse(L);
        PrintList(L);
    }
    return 0;
}

第9关:删除链表中满足区间值的结点 

任务描述

本关任务:利用单链表表示一个递增的整数序列,删除链表中值大于等于mink且小于等于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同)。

编程要求

输入

多组数据,每组数据有两行,第一行为链表的长度n,第二行为链表的n个元素(元素之间用空格分隔),第三行为给定的mink和maxk(用空格分隔)。当n=0时输入结束。

输出

对于每组数据分别输出一行,依次输出删除元素后的链表元素,元素之间用空格分隔。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void PrintList(LinkList &L)
{//打印依次输出链表中的数据
    L=L->next;
    while(L){
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
    }
    cout<<endl;
}
void DeleteMinMax(LinkList &L,int mink,int maxk)
{//删除链表中满足区间值的结点
/**************begin************/
LinkList p,q,pre=L,s;
p=L->next;
while (p&&p->data<mink)
{
    pre=p;
    p=p->next;//查找第一个值>mink的结点
}
 
    while (p&&p->data<=maxk)
    {
        p=p->next;
    }
    
    q=pre->next;
    pre->next=p;
    while (q!=p)
    {
        s=q->next;
        delete q;
        q=s;
    }



    /**************end************/
}
int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0) break;
        LinkList L;
        CreateList_R(L,n);
        int mink,maxk;
        cin>>mink>>maxk;
        DeleteMinMax(L,mink,maxk);
        PrintList(L);
    }
    return 0;
}

第10关:双向循环链表中结点的交换 

任务描述

本关任务:利用双向循环链表表示一个整数序列,指定一个结点位置用p指向该结点,交换p所指向的结点及其前驱结点的顺序。

编程要求

输入

多组数据,每组数据有三行,第一行为链表的长度n,第二行为链表的n个元素(元素之间用空格分隔),第三行为p所指向的结点位置。当n=0时输入结束。

输出

对于每组数据分别输出一行,依次输出交换结点顺序后的链表元素,元素之间用空格分隔。

#include<iostream>
using namespace std;
typedef struct DuLNode
{
	int data;
	struct DuLNode *next;
	struct DuLNode *prior;
}DuLNode,*DuLinkList;
void CreateList(DuLinkList &L,int n)
{//建立双向循环链表

    L=new DuLNode;    //初始化链表L的头结点
	L->prior=L;
	L->next=L;
	DuLinkList r=L;     //工作指针r初始化指向头结点
	while(n--)
	{
		DuLinkList p=new DuLNode;
		cin>>p->data;
		p->next=r->next;
		r->next=p;
		p->prior=r;
		p->next->prior=p;
		r=p;
	}
}
void Exchange(DuLinkList &L,int loc)
{//双向循环链表中结点的交换
/**************begin************/
   DuLinkList p,q;
int j;
p=L->next;
j=1;
while (p&&j<loc)
{
    p=p->next;
    j++;
}
q=p->prior;//定位前一个结点
p->prior=p->prior->prior;//更改p的前驱
q->prior->next=p;//更改q的前驱的后继指向p
q->next=p->next;
p->next=q;
q->prior=p;

    /**************end************/
}
void PrintList(DuLinkList &L)
{//依次输出链表中的数据
    DuLinkList p=L->next;
	while(p->next&&p->next!=L)
	{
		cout<<p->data<<" ";
		p=p->next;
	}
	cout<<p->data<<endl;
}
int main()
{
	int n;
	while(cin>>n)
	{
	 	if(n==0) break;
	 	DuLinkList L;
	 	CreateList(L,n);
	 	int loc;
		cin>>loc;
		if(n==1)          //链表仅有一个元素时输出其自身
		{
			cout<<L->next->data<<endl;
			continue;
		}
		Exchange(L,loc);
		PrintList(L);
	}
	return 0;
}

第11关:查找链表中倒数第k个结点 

任务描述

本关任务:利用单链表表示一个整数序列,请实现一个时间复杂度为O(n)、空间复杂度为O(1)的算法,通过一趟遍历在单链表中确定倒数第k个结点。

编程要求

输入

多组数据,每组数据有三行,第一行为链表的长度n,第二行为链表的n个元素(元素之间用空格分隔),第三行为k。当n=0时输入结束。

输出

对于每组数据分别输出一行,输出每个链表的倒数第k个结点对应的数值。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void Search_k(LinkList L,int k)
{
    /**************begin************/
LinkList p=L->next,q=L->next;
int n=0;
while (p!=NULL)//p先走k步,然后和q一起走,p到达尾部时,q所指的刚好就是倒数第k的结点
{
    if (n<k)
    {
    p=p->next;
    n++;
    }
    else 
    {
        p=p->next;
        q=q->next;
    }
}
cout<<q->data<<endl;





    /**************end************/
}
int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0) break;
        LinkList L;
        CreateList_R(L,n);
        int k;
        cin>>k;
        Search_k(L,k);
    }
    return 0;
}

第12关:删除链表中绝对值相等的结点 

任务描述

本关任务:利用单链表表示一个整数序列,实现一个时间复杂度为O(n)的算法,对于链表中绝对值相等的结点,仅保留第一次出现的结点而删除其余绝对值相等的结点。

例如,若给定的单链表HEAD如下:

,

删除后的单链表HEAD为:

,

编程要求

输入

多组数据,每组数据有两行,第一行为链表的长度n,第二行为链表的n个元素(元素之间用空格分隔)。当n=0时输入结束。

输出

对于每组数据分别输出一行,依次输出删除结点后的链表元素,元素之间用空格分隔。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void PrintList(LinkList &L)
{//打印依次输出链表中的数据
    L=L->next;
    while(L){
        if(L->next!=NULL) cout<<L->data<<" ";
        else cout<<L->data;
        L=L->next;
    }
    cout<<endl;
}
int Abs(int x)
{//绝对值函数
	return x>0?x:-x;
}
void DeleteEqualNode(LinkList &L,int n)
{//删除链表中绝对值相等的结点
/**************begin************/
    LinkList p,r;
p=L;
int a[100],m;
for (int i=0;i<100;i++)
{
    a[i]=0;
}
while (p->next!=NULL)
{
    if (p->next->data>=0)
        m=p->next->data;//看结点的绝对值在数组的位序中是否是1
    else 
    m=-(p->next->data);
    if (a[m]==0)
    {
        a[m]=1;
        p=p->next;
    }
    else 
    {
        r=p->next;
        p->next=r->next;
        delete r;
    }
}





    /**************end************/
}
int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0) break;
        LinkList L;
        CreateList_R(L,n);
        DeleteEqualNode(L,n);
        PrintList(L);
    }
    return 0;
}

第13关:查找两个单词链表共同后缀的起始结点 

任务描述

本关任务:假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀空间。 例如,“loading”和“being”的存储映像如下图所示:

,

设str1和str2分别指向两个单词所在单链表的头结点,请实现一个时间上尽可能高效的算法,找出由str1和str2所指的两个链表共同后缀的起始位置的结点,输出该结点对应的字符(如图中的字符i)。

编程要求

输入

多组数据,每组数据有三行,第一行为链表str1和str2的长度n和m,第二行为链表str1的n个元素,第三行为链表str2的m个元素(元素之间用空格分隔)。n=0且m=0时输入结束。

输出

对于每组数据输出一行,为共同后缀的起始位置结点对应的字符。

#include <iostream>
using namespace std;
typedef struct LNode
{
    char data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void FindSuffix(LinkList str1, LinkList str2,int n,int m)
{//查找两个单词链表共同后缀的起始结点

/**************begin************/
 
LinkList longstr,shortstr;
 int k;
 if (n>m)
 {
     longstr=str1->next;
     shortstr=str2->next;
     k=n-m;
 }
else 
{
    longstr=str2->next;
    shortstr=str1->next;
    k=m-n;
}
while (k--)
longstr=longstr->next;
LinkList t=longstr;
int flag=0;
while (longstr)
{
    if (longstr->data==shortstr->data)
    {
        if (flag==0)
        {
            t=longstr;
            flag=1;
        }
    }
    else 
    {
        flag=0;
    }
    longstr=longstr->next;
    shortstr=shortstr->next;
}
cout<<t->data<<endl;



 
   /**************end************/
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        if(n==0&&m==0) break;
        LinkList str1,str2,p;
        CreateList_R(str1,n);
        CreateList_R(str2,m);
        FindSuffix(str1,str2,n,m);
    }
    return 0;
}

第14关:猴子选大王问题 

任务描述

本关任务:一堆猴子都有编号,编号是1,2,3 ...m,这群猴子(m个)按照1~m的顺序围坐一圈,从第1开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,直到圈中只剩下最后一只猴子,则该猴子为大王。利用单向循环链表模拟此过程,依次输出出圈的猴子编号。

编程要求

输入

多组数据,每组数据占一行,包括两个数据m和n。m代表猴子个数,n代表步数,m=0且n=0时输入结束。

输出

依次输出出圈的猴子编号,编号之间用空格隔开。

#include <iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateCirList(LinkList &L,int m)
{//后插法创建单向循环链表
    L=new LNode;
    L->next=NULL;
    L->data=1;
    LinkList r=L;
    for(int i=2;i<=m;i++)
    {
        LinkList p=new LNode;
        p->data=i;
        p->next=NULL;
        r->next=p;
        r=p;
    }
    r->next=L;                                   //尾结点的指针指向首元结点,单向循环链表建成
    L=r;                                          //L需要指向尾结点,以防n=1时第一个需要删除的是首元结点,不易得到前驱结点
}
void MonkeyKing(LinkList &L,int n)
{//猴子选大王(约瑟夫问题)
/**************begin************/
   // int answer[100];
 
LinkList tail,head,p,q;
head=L;
tail=head;
p=head->next;
q=tail;//p在最前面时,最后一个节点是他的前继结点
int i=1;
while (p!=q)
{
    if (i==n)
    {
        q->next=p->next;
        printf ("%d ",p->data);
        delete p;
        p=q->next;
        i=1;
    }
    else 
    {//p,q各自向后移动一个节点,其中q总在p的前面
    q=p;
    p=p->next;
    i++;
    }
   
}
 printf ("%d",q->data);
 printf ("\n");






   
    /**************end************/
}
int main()
{
    int m,n;
    while(cin>>m>>n)
    {
        if(n==0&&m==0) break;
        LinkList L;
        CreateCirList(L,m);
        MonkeyKing(L,n);
    }
    return 0;
}

第15关:奇偶链表的分割 

任务描述

本关任务:给定一个单链表,把所有的奇数结点和偶数结点分别排在一起,重新链成一个新链表。请注意,这里的奇数结点和偶数结点指的是结点编号的奇偶性,而不是结点的值的奇偶性。

要求:空间复杂度应为 O(1),时间复杂度应为 O(n),n 为链表结点总数。

编程要求

输入

多组数据,每组数据有两行,第一行为链表的长度n,第二行为链表的n个元素(元素之间用空格分隔)。当n=0时输入结束。

输出

奇数结点和偶数结点分割后重新链成的新链表。

#include<iostream>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_R(LinkList &L,int n)
{//后插法创建单链表
    L=new LNode;
    L->next=NULL;
    LinkList r=L;
    for(int i=0;i<n;i++)
    {
        LinkList p=new LNode;
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}
void Decollate(LinkList L,LinkList L1)
{//奇偶链表的分割
/**************begin************/
  LinkList p=L->next;//初始化p指向L的首元节点
  LinkList q=L;//初始化q指向L的头节点
  LinkList p1=L1;//初始化p1指向新链表L1的头结点
  int num=1;
  while (p)
  {
      if (num%2!=0)
      {
          p1->next=p;
          p1=p1->next;
          q->next=p->next;
          p->next=NULL;
          p=q->next;
      }
      else 
      {
          q=q->next;
          p=p->next;
      }
      num++;//结点序号加1;
  }
  p1->next=L->next;//将剩余链表部分链入新链表的表尾
  delete L;//删除原链表的头结点





  
    /**************end************/
}
void PrintList(LinkList &L)
{//依次输出链表中的数据
    LinkList p=L->next;
    while(p)
    {
        if(p->next!=NULL) cout<<p->data<<" ";
        else cout<<p->data;
        p=p->next;
    }
    cout<<endl;
}
int main()
{
	int n;
	while(cin>>n)
	{
		if(n==0) break;
		LinkList L=new LNode;
        CreateList_R(L,n);
        LinkList L1=new LNode;    //申请新链表L1
        L1->next=NULL;
        Decollate(L,L1);      //奇偶链表的分割
        PrintList(L1);
	}
	return 0;
}

  • 12
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值