链表练习1

1、查找序列元素(链表)

问题描述

使用带头结点的单链表编程:

一群学生排成一行,输入一个学号,请确定该学号学生所在的位置。

输入说明

第一行输入学生信息:

第一个整数n(0<=n<=100),表示共有n个学生,其后有n个整数,表示n个学生的学号

第二行及以后各行,每行输入一个整数,表示要查找的学生学号。

输出说明

对于每个要查找的学号,输出一个整数,表示要查找学生的位置。如果共有n个学生,则位置序号为1~n。

如果学生不存在,输出“no”,不包括双引号。

每个输出占一行。

输入范例

12 50 51 52 53 54 49 4 5 10 11 9 12
50
11
12
3

输出范例

1
10
12
no


代码
#include<iostream>

using namespace std;

struct student {
	int num;
	struct student *next;
};

//创建单链表
struct student* create(struct student* head,int n) {
	struct student* p, * q;
	head = new student;
	p = head;
	q = head;
	for (int i = 0; i < n; i++) {
		q = new student;
		p->next = q;
		p = q;
		cin>>q->num;
	}
	q->next = NULL;
	return head;
}

//寻找学号
int find(struct student* head, int num) {
	int locate = 0;
	while (head) {
		if (head->num == num) return locate;
		head = head->next;
		locate++;
	}
	return 0;
}

int main() {
	student* head = new student;
	int n, num;
	cin >> n;
	head = create(head,n);
	int no;
	while (cin >> no) {
		int res = find(head, no);
		if (res == 0) {
			cout << "no" << endl;
		}
		else
			cout << res << endl;
	}
	return 0;
}

2、在链表指定位置插入结点

问题描述

输入若干(不超过100个)非负整数,创建一个不带头结点的单向链表。
再输入一个位置index以及一个数据data,程序中首先创建一个新结点s,s的数据成员为data,然后调用函数insertNode将s插入到链表的指定位置index处,最后输出结果链表。
返回值:
函数返回结果链表的头指针。

输入说明

 首先输入若干非负整数,每个整数作为数据放入一个链表结点中,输入-1表示输入结束。
然后输入若干组整数,每组一行,每行包含两个整数,第一个表示需要插入位置index,第二个为新结点的数据。如:输入“1 5”表示在链表的第一个位置(最前面)插入一个结点,结点的数据为5。

输出说明

对于每组输入,输出插入结点之后的结果链表。输出的信息以head开头,以tail结尾,以“-->”分隔。具体见输出范例。
如果输入的index超出了链表的范围(如果链表中已有n个结点,则index的有效范围为 1<= index <= n+1),则不插入,输出原链表。如果是空链表,则直接输出“head-->tail”。

输入范例

1 2 3 -1
1 10
3 20

输出范例

head-->10-->1-->2-->3-->tail
head-->10-->1-->20-->2-->3-->tail

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

struct student{
	int num;
	struct student* next;
}; 

//从键盘读入数据创建链表,新结点插入到尾部
struct student *createByTail(){
	struct student *head;
 	struct student *p1,*p2;
	int n;
    n=0;
    p1=p2=(struct student*)malloc(sizeof(struct student));
    scanf("%d",&p1->num);
    head=NULL;  //首先置链表为空链表
    while(p1->num!=-1)    //num为-1,意味着用户输入结束
   {
   		n=n+1;
  		if(n==1)            //创建第一个结点
   			head=p1;
  		else
   			p2->next=p1;
  		p2=p1;            //p2始终指向最后一个结点(即尾指针)
  		p1=(struct student*)malloc(sizeof(struct student)); //p1指向新结点
        scanf("%d",&p1->num);
 	}
 	p2->next=NULL;  //最后一个结点的next赋值为NULL
    return head;
}

//输出链表中的信息(num)
void displayLink(struct student* head){
	struct student *p;
	p=head;
	printf("head-->");
	while(p!=NULL){
		printf("%d-->",p->num);
		p=p->next;
	}
	printf("tail\n");
} 

//在链表中第index处插入s指针所指向的结点。index从1开始。
//由于可能插在第一个结点,所以函数返回头指针给主调函数
struct student *insertNode(struct student *head,struct student *s,int index){
	struct student *q=head;
	int n=1,len=0;
	while(q != NULL){
		q=q->next;
		len++;
	}
	if(index<1||index>len+1) return head;
	q=head;
	
	while(n != index){
		q=q->next;
		n++;
	}
	//第一个位置插入结点
	if(q == head){
		s->next=head;
		head=s;
	}else{
		student *p = head;
		while(p->next != q){
			p=p->next;
		}
		s->next=q;
		p->next=s;
	}
	return head;
} 

int main(){
	struct student *head;
	int index,data;
	head=createByTail();
	while(scanf("%d%d", &index,&data) != -1)
    {
        struct student * s = (struct student *) malloc(sizeof(struct student));
        s->num = data;
        head=insertNode(head, s, index);
        displayLink(head);
    }
    return 0;
}

3、删除链表第index个结点

问题描述

输入若干(不超过100个)非负整数,创建一个不带头结点的单向链表。在输入一个位置index,从链表中删除第index个结点,输出结果链表。

输入说明

首先输入若干非负整数,每个整数作为数据放入一个链表结点中,输入-1表示输入结束。

然后输入若干组整数,每组一行,每行仅包含一个整数,表示需要删除的结点的位置index。如:输入1表示删除链表的第一个(最前面一个)结点。

输出说明

对于每组输入,输出删除第index个结点之后的结果链表。输出的信息以head开头,以tail结尾,以“-->”分隔。具体见输出范例。

如果输入的index超出了链表的范围,则不删除,输出原链表。如果是空链表,则直接输出“head-->tail”。

输入范例

1000 2342 8883 -1
4
3
1
1

输出范例

head-->1000-->2342-->8883-->tail
head-->1000-->2342-->tail
head-->2342-->tail
head-->tail

代码
#include <stdio.h>
#include <stdlib.h>
struct student{
	int num;
	struct student *next;
}; 
//从键盘读入数据创建链表,新结点插入到尾部
struct student *createByTail(){
	struct student *head;
	struct student *p1,*p2;
	int n;
	n=0;
	p1=p2=(struct student*)malloc(sizeof(struct student));
	scanf("%d",&p1->num);
	head=NULL;  //首先置链表为空链表 
	while(p1->num!=-1){  //num为-1.意味着用户输入结束 
		n=n+1;
		if(n==1) head=p1;
		else p2->next=p1;
		p2=p1;
		p1=(struct student*)malloc(sizeof(struct student));
		scanf("%d",&p1->num);
	}
	p2->next=NULL;
	return head;
} 
//输出链表中的信息(num)
void displayLink(struct student *head){
	struct student *p;
	p=head;
	printf("head-->");
	while(p!=NULL){
		printf("%d-->",p->num);
		p=p->next;
	}
	printf("tail\n");
} 
//删除链表中第index个结点,index从1开始
//由于可能删除第一个结点,所以函数返回头指针给主调函数
struct student *deleteNode(struct student *head,int index){
	struct student *q=head;
	int n=1,len=0;
	while(q != NULL){
		q=q->next;
		len++;
	}
	if(index<1||index>len) return head;
	q=head;
	while(n!=index){
		q=q->next;
		n++;
	}
	if(index==1){
		head=q->next;
	}else{
		struct student *p=head;
		while(p->next!=q){
			p=p->next;
		}
		p->next=q->next;
	}
	return head;
}

int main(){
    struct student *head;
    int index;
    head=createByTail();
    while(scanf("%d", &index) != -1){
    	head=deleteNode(head, index);
		displayLink(head);
    }
}

4、集合的操作

问题描述

输入A、B、C、D四个集合(集合中无重复元素,且元素值都大于0),分别存储在不带头结点的链表中。

本程序先将四个集合执行以下操作:

  1. 对A、B、C、D分别进行升序排序;

  2. 做A=A+B操作:先执行两个有序链表A和B的合并,并仍然保持有序,结果存储在A中,然后删除重复元素;

  3. 做A=A-C操作:将C中出现的元素从A中删除;

  4. 对D中出现的元素,逐一到A中查询:

    1. 如果在A中存在,则从A中删除

    2. 如果在A中不存在,则将元素添加到A中,并保持链表A有序。

    3. 输出集合A中的元素。

输入说明

首先输入一行,包含一个整数N,表示共测试N组数据。

后面接着输入4*N行,每行为一个集合的元素。

每组数据的第1行为集合A的元素,第2行为集合B的元素,第3行为集合C的元素,第4行为集合D的元素。

每个集合的元素值都为大于0的整数,输入时,-1表示结束。

输出说明

 输出的信息以head开头,以tail结尾,以“-->”分隔。如果是空链表,则直接输出“head-->tail”。具体见输出范例。

输入范例

2
3 5 8 10 15 9 -1
2 5 8 11 14 -1
2 5 10 -1
3 1 9 -1
3 5 8 10 15 9 -1
2 5 8 11 14 -1
2 5 10 -1
2 3 8 -1

输出范例

head-->1-->8-->11-->14-->15-->tail
head-->2-->9-->11-->14-->15-->tail

代码
#include<stdio.h>
#include<stdlib.h>
struct student{
	int num;
	struct student *next;
};

//尾接法创建单链表 
struct student* createByTail(){
	struct student *head;
	struct student *p1,*p2;
	int n=0;
	p1=p2=(struct student*)malloc(sizeof(struct student));
	scanf("%d",&p1->num);
	head=NULL;
	while(p1->num!=-1){
		n=n+1;
		if(n==1) head=p1;
		else p2->next=p1;
		p2=p1;
		p1=(struct student*)malloc(sizeof(struct student));
		scanf("%d",&p1->num);
	}
	p2->next=NULL;
	return head;
}

//输出链表中的信息
void displayLink(struct student *head){
	struct student *p;
	p=head;
	printf("head-->");
	while(p!=NULL){
		printf("%d-->",p->num);
		p=p->next;
	}
	printf("tail\n");
} 

//根据数据域的大小插入,stu指向待插入结点 
struct student *insertNodeInOrder(struct student *head,struct student *stu){
	struct student *p0,*p1,*p2;
	p1=head;
	p0=stu;
	if(head==NULL){  //目前还是空链表 
		p0->next=head;
		head=p0;
	}else{
		while((p0->num>p1->num)&&(p1->next!=NULL)){
			p2=p1;
			p1=p1->next;
		}
		if(p0->num<=p1->num){
			if(head==p1) head=p0;
			else p2->next=p0;
			p0->next=p1;
		}else{
			p1->next=p0;
			p0->next=NULL;
		}
	}
	return head;
}

struct student *sort(struct student *head){
	struct student *p,*s;
	p=head;
	head=NULL;
	while(p){
		s=p;
		p=p->next;
		head=insertNodeInOrder(head,s);
	}
	return head;
}
struct student * merge(struct student *LA, struct student *LB){
	struct student  *p,*s;
	p=LB;
    while(p)
    {
		s=p;
		p=p->next;
		LA=insertNodeInOrder(LA, s);
    }
    return LA;
}

 

struct student* subtract(struct student* LA, struct student* LB){
	struct student *q, * p=LB;
	struct student *pre=NULL;//pre指向q的前驱,所以最开始赋为NULL
    while(p!=NULL) //对LB链表遍历
    {
        q=LA;
        while (q!=NULL && q->num!=p->num)
        {
            pre=q;
            q=q->next; //在LA中查找是否有元素与p->num相同
        }
        if (q!=NULL) //找到了相同的元素,则删除q所指向结点
        {
            if (q==LA) //如果删除第一个结点
            {
                LA = LA -> next;
                free(q);
            }
            else
            {
                 pre->next=q->next;
                 free(q);
            }
        }
        p=p->next;
     }
     return LA;
}

 

void purge(struct student * head){
       struct student  *p,*q;
       if(head== NULL || head->next == NULL)
        return;
       p=head;
       while(p->next!= NULL){
	   		if(p->num == p->next->num){
                q=p->next;
				p->next=q->next;
                free(q);
            }
            else{
				p=p->next;
           }
       }
}

struct student* fun(struct student* L1,struct student *L2){
	struct student *p1,*p2=L2;
	int flag=0;  //是否存在相同元素
	while(p2!=NULL){  //对L2链表遍历 
        flag=0;
        p1=L1;
        while(p1!=NULL){
            if(p1->num==p2->num){
                flag=1;
                break;
            }
            p1=p1->next;
        }
        struct student* temp;
        temp=p1;
        if(flag==1){
            struct student* q;
            if(temp==L1){
                L1=temp->next;
            }else{
                q=L1;
                while(q->next!=temp) q=q->next;
                q->next=temp->next;
            }
            delete temp;
        }else{
            student *node = new student;
            node->num=p2->num;
            L1=insertNodeInOrder(L1,node);
        }
		p2=p2->next;
	}
	return L1;
}
int main(){
    struct student *headA, *headB, *headC, *headD;
    int i,n;
    while(scanf("%d", &n)!= EOF){
		i=0;
        while(i<n){
            headA=createByTail();//创建链表A
            headB=createByTail();//创建链表B
            headC=createByTail();//创建链表C
            headD=createByTail();//创建链表D
            headA = sort(headA);//链表A排序
            headB = sort(headB);//链表B排序
            headC = sort(headC);//链表C排序
            headD = sort(headD);//链表D排序
            headA = merge(headA, headB);//将链表B合并到链表A中
            purge(headA);//删除链表A中重复元素
            headA = subtract(headA, headC);//从链表A中减去链表C中元素
            headA=fun(headA, headD);//对链表A和链表D调用fun函数
            displayLink(headA);//输出链表A中的元素
            i++;
        }

    }

return 0;

}

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
A:好的,下面是K - 双向链表练习题的解答。 题目描述: 设计一个数据结构,要求实现双向链表的基本操作:插入、删除、反转等,并实现一个方法向链表中添加一个元素。同时,该数据结构需要支持以下操作: 1. get(k):返回链表中第 k 个节点的值。如果 k 小于 1 或大于链表的长度,则返回 -1。 2. addAtHead(val):在链表的头部插入一个值为 val 的节点。 3. addAtTail(val):在链表的尾部插入一个值为 val 的节点。 4. addAtIndex(index,val):在链表中的第 index 个节点前插入一个值为 val 的节点。如果 index 等于链表的长度,则在链表的末尾添加该节点。如果 index 大于链表的长度,则不会插入。 5. deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。 解题思路: 题目要求我们设计一个双向链表数据结构,并提供选定的一些操作。这是一个经典的链表问题,我们需要先设计链表节点的结构体,并在节点中保留前驱和后继指针,便于双向操作。然后,我们可以定义一个链表类,在该类中定义一些方法来实现链表的基本操作。 本题需要实现的方法包括: 1. get(k):遍历链表,找到第 k 个节点并返回该节点的值。 2. addAtHead(val):创建一个新节点,将该节点作为头节点,并更新头节点的前驱指针。 3. addAtTail(val):创建一个新节点,将该节点作为尾节点,并更新尾节点的后继指针。 4. addAtIndex(index,val):遍历链表,找到第 index - 1 个节点,创建一个新节点,并将其插入到该节点的后面。如果 index 为零,则将新节点插入到头部。如果 index 等于链表的长度,则将新节点插入到末尾。 5. deleteAtIndex(index):遍历链表,找到第 index - 1 个节点,并将其后继指针指向第 index + 1 个节点。如果 index 为零,则更新头节点。如果 index 等于链表的长度 - 1,则更新尾节点。 代码实现: 下面是基于C++的实现代码,其中Node是一个链表节点的结构体,List是链表类的定义: ```cpp #include<iostream> using namespace std; // 链表节点结构体 struct Node { int val; // 节点的值 Node* pre; // 前驱指针 Node* nxt; // 后继指针 Node(int _val):val(_val),pre(nullptr),nxt(nullptr){} // 构造函数 }; // 链表类 class List{ private: Node* head; // 头节点 Node* tail; // 尾节点 int size; // 链表长度 public: List():head(nullptr),tail(nullptr),size(0){} // 构造函数 int get(int k){ if(k < 1 || k > size) // 判断k是否合法 return -1; Node* p = head; for(int i=1; i<k; i++) // 遍历链表,找到第k个节点 p = p->nxt; return p->val; // 返回节点的值 } void addAtHead(int val){ Node* p = new Node(val); // 创建新节点 if(size == 0){ // 链表为空的情况 head = p; tail = p; }else{ // 链表非空的情况 p->nxt = head; // 插入节点 head->pre = p; head = p; } size++; // 更新链表长度 } void addAtTail(int val){ Node* p = new Node(val); // 创建新节点 if(size == 0){ // 链表为空的情况 head = p; tail = p; }else{ // 链表非空的情况 tail->nxt = p; // 插入节点 p->pre = tail; tail = p; } size++; // 更新链表长度 } void addAtIndex(int index, int val){ if(index > size) // index不合法,不插入 return; if(index <= 0) // 如果index小于等于0,插入到头部 addAtHead(val); else if(index == size) // 如果index等于size,插入到尾部 addAtTail(val); else{ // 如果index在链表中 Node* p = head; for(int i=1; i<index; i++) // 找到第index-1个节点 p = p->nxt; Node* q = new Node(val); // 创建新节点 q->nxt = p->nxt; // 插入节点 p->nxt->pre = q; p->nxt = q; q->pre = p; size++; // 更新链表长度 } } void deleteAtIndex(int index){ if(index < 0 || index >= size) // index不合法,不删除 return; if(index == 0){ // 如果要删除的是头节点 head = head->nxt; // 更新头节点 if(head == nullptr) // 如果链表为空,尾节点也需要更新 tail = nullptr; else head->pre = nullptr; }else if(index == size-1){ // 如果要删除的是尾节点 tail = tail->pre; // 更新尾节点 tail->nxt = nullptr; }else{ // 如果要删除的是中间节点 Node* p = head; for(int i=1; i<index; i++) // 找到第index-1个节点 p = p->nxt; p->nxt = p->nxt->nxt; // 删除节点 p->nxt->pre = p; } size--; // 更新链表长度 } }; int main(){ List l; l.addAtHead(1); l.addAtTail(3); l.addAtIndex(1,2); // 链表变为[1,2,3] cout<<l.get(1)<<" "; // 返回2 l.deleteAtIndex(1); // 现在链表是[1,3] cout<<l.get(1)<<" "; // 返回3 return 0; } ``` 总结: 双向链表实现相对较多的语言,相对单向链表更适合一些场景;比如说LUR Cache。对于双向链表的实现,我们需要注意节点间指针的指向关系,以及头节点和尾节点的处理。感兴趣的读者可以继续尝试其他链表问题,如链表的分割、链表的反转等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值