0
点赞
收藏
分享

微信扫一扫

DS单链表 入门题

豆丁趣 2022-03-16 阅读 42

DS单链表 基础例题

A.单链表的类实现

用C++语言和类实现单链表,含头结点

属性包括:data数据域、next指针域

操作包括:插入、删除、查找

注意:单链表不是数组,所以位置从1开始对应首结点,头结点不放数据

输入

输出

样例输入

样例输出

题解

#include<bits/stdc++.h>
using namespace std;
#define ok 1
#define error 0

class ListNode {
	public:
		int data;			//数据
		ListNode *next;		//next指针
		ListNode() {
			next = NULL;
		}
};
class LinkList {
	public:
		ListNode *head;
		int len;

		LinkList();
		~LinkList();
		ListNode *LL_index(int i);      	//返回目标位置指针
		int LL_get(int i);             		//获取数据
		int LL_insert(int i, int item); 	//插入数据
		int LL_del(int i);              	//删除数据
		void LL_display();              	//输出数据
};
void LinkList::LL_display(){

	for(ListNode* i = head->next; i != NULL; i = i->next){
		cout << i->data << " ";
	}cout << endl;
}
LinkList::LinkList() {
	head = new ListNode();
	len = 0;
}
LinkList::~LinkList() {
	ListNode *p, *q;
	p = head;
	while(p != NULL) {
		q = p;
		p = p->next;
		delete q;
	}
	len = 0;
	head = NULL;
}
ListNode *LinkList::LL_index(int i) { 
	int j=0;
	ListNode *p;
	p=head;
	while(p && j<i-1) { 
		p=p->next;
		++j;
	}
	if(!p || j>i-1) {
		return NULL;
	} else return p; 
}
int LinkList::LL_insert(int i,int item) {
	ListNode *p;
	if(LL_index(i) == NULL)
		return error;
	else
		p=LL_index(i);
	ListNode *s; 
	s=new ListNode();
	s->data=item; 
	s->next=p->next; 
	p->next=s; 
	len++;
	return ok;

}
int LinkList::LL_del(int i) {
	ListNode *p;
	if(LL_index(i) == NULL)
		return error;
	else {
		p=LL_index(i); 
		ListNode *q;
		q=p->next;
		p->next=q->next;
		delete q;
		len--;
		return ok;
	}
}
int LinkList::LL_get(int i) {
	if(i<=0|| i>len)
		return error;
	else {
		ListNode *p;
		p=head;
		int j=0;
		while(p->next&& j<=i-1) {
			p=p->next;
			++j;
		}
		int num=p->data;
		return num;
	}
}

int main() {	
	LinkList li;
	int n,item,i;
	cin >> n;
	//输入 
	for(i = 1; i <= n; i++){
		cin >> item;
		li.LL_insert(i,item);
	}
	li.LL_display();
	//插入 
	cin >> i >> item;
	if(li.LL_insert(i,item)) li.LL_display();
	else	cout << "error" << endl;
	
	cin >> i >> item;
	if(li.LL_insert(i,item)) li.LL_display();
	else	cout << "error" << endl;
	//删除 
	cin >> i;
	if(li.LL_del(i))	li.LL_display();
	else	cout << "error" << endl;
	
	cin >> i;
	if(li.LL_del(i))	li.LL_display();
	else	cout << "error" << endl;
	//查找
	cin >> i;
	if(item = li.LL_get(i)) cout << item << endl;
	else cout << "error" << endl;
	
	cin >> i;
	if(item = li.LL_get(i)) cout << item << endl;
	else cout << "error" << endl;
	
	
	return 0;
}

B. DS单链表–结点交换

用C++实现含头结点的单链表,然后实现单链表的两个结点交换位置。

注意不能简单交换两个结点包含数据,必须通过修改指针来实现两个结点的位置交换

交换函数定义可以参考:

swap(int pa, int pb) //pa和pb表示两个结点在单链表的位置序号

swap (ListNode * p, ListNode * q) //p和q表示指向两个结点的指针

输入

输出

样例输入

样例输出

题解

将两个节点的前驱后继交换即可


#include<bits/stdc++.h>
using namespace std;
#define ok 1
#define error 0

class ListNode {
	public:
		int data;
		ListNode *next;
		ListNode() {
			next = NULL;
		}
};
class LinkList {
	public:
		ListNode *head;
		int len;

		LinkList();
		~LinkList();
		ListNode *LL_index(int i);      
		int LL_get(int i);             
		int LL_insert(int i, int item); 
		int LL_del(int i);              
		void LL_display();   
		int LL_swap(int pa,int pb);           
};

//  题目要求函数
int LinkList::LL_swap(int pa,int pb)
{
	//非法访问跳过
	if(pa < 1 || pb < 1 || pa > len || pb > len)
		return error;
	//获取节点指针
	ListNode *a = LL_index(pa);
	ListNode *b = LL_index(pb);
	//交换后继
	ListNode *tmp = a -> next -> next;
	a -> next -> next = b -> next -> next; 
	b -> next -> next = tmp;
	//交换前驱
	tmp = a -> next;
	a -> next = b -> next;
	b -> next = tmp;
	
	return ok;
}
void LinkList::LL_display(){

	for(ListNode* i = head->next; i != NULL; i = i->next){
		cout << i->data << " ";
	}cout << endl;
}
LinkList::LinkList() {
	head = new ListNode();
	len = 0;
}
LinkList::~LinkList() {
	ListNode *p, *q;
	p = head;
	while(p != NULL) {
		q = p;
		p = p->next;
		delete q;
	}
	len = 0;
	head = NULL;
}
ListNode *LinkList::LL_index(int i) { 
	int j=0;
	ListNode *p;
	p=head;
	while(p && j<i-1) { 
		p=p->next;
		++j;
	}
	if(!p || j>i-1) {
		return NULL;
	} else return p; 
}
int LinkList::LL_insert(int i,int item) {
	ListNode *p;
	if(LL_index(i) == NULL)
		return error;
	else
		p=LL_index(i);
	ListNode *s; 
	s=new ListNode();
	s->data=item; 
	s->next=p->next; 
	p->next=s; 
	len++;
	return ok;

}
int LinkList::LL_del(int i) {
	ListNode *p;
	if(LL_index(i) == NULL)
		return error;
	else {
		p=LL_index(i); 
		ListNode *q;
		q=p->next;
		p->next=q->next;
		delete q;
		len--;
		return ok;
	}
}
int LinkList::LL_get(int i) {
	if(i<=0|| i>len)
		return error;
	else {
		ListNode *p;
		p=head;
		int j=0;
		while(p->next&& j<=i-1) {
			p=p->next;
			++j;
		}
		int num=p->data;
		return num;
	}
}

int main() {
	
	LinkList li;
	int n,item,i;
	cin >> n;
	//输入 
	for(i = 1; i <= n; i++){
		cin >> item;
		li.LL_insert(i,item);
	}
	li.LL_display();
	//交换 
	int pa,pb;
	cin >> pa >> pb;
	if(li.LL_swap(pa,pb))	li.LL_display();
	else cout << "error" << endl;
	
	cin >> pa >> pb;
	if(li.LL_swap(pa,pb))	li.LL_display();
	else cout << "error" << endl;
	
	
	return 0;
}

C. DS单链表–合并

假定两个单链表是递增有序,定义并实现以下函数,完成两个单链表的合并,继续保持递增有序

int LL_merge(ListNode *La, ListNode *Lb)

输入

输出

样例输入

样例输出

题解

这里给出两个方法,完整代码中给出的是方法一


方法一:直接链接节点
这里是合并得到新的头节点,但是原来的节点没有改变。就是说如果原链表变化,该新链表中的节点数据也会发生变化。

ListNode* LL_merge(ListNode* list1, ListNode* list2) {
    	//创建新节点
        ListNode* preHead = new ListNode();
        ListNode *head = preHead;
    	//链接节点
        while(list1 != NULL|| list2 != NULL)
        {
            if(list1 == NULL)
            {
                head->next = list2;
                list2 = list2->next;
            }
            else if(list2 == NULL)
            {
                head->next =list1;
                list1 = list1->next;
            }
            else if(list1->data > list2->data)
            {
                head->next = list2;
                list2 = list2->next;
            }
            else
            {
                head->next =list1;
                list1 = list1->next;
            }

            head = head->next;
        }
    	//返回新的头节点
        return  preHead->next->next;
}

方法二:通过原链表数据,创建新节点再插入。

这里是使用的 La 链表为合并链表,也可以创建一个新的链表 Lc

int LL_merge(ListNode *La, ListNode *Lb){
    //LinkList Lc;
    //ListNode *p = Lc.head;
	ListNode *p;
	p = La;
	
	for(ListNode *i = La->next, *j = Lb->next; i != NULL || j != NULL;)
	{
		if(i == NULL || (j != NULL && j->data < i->data)){
          	ListNode *s = new ListNode;
          	s->data = j -> data;
			p -> next = s;
         	j = j -> next;
		}
		else if(j == NULL || (i != NULL && j->data >= i->data)){
          	ListNode *s = new ListNode;
          	s->data = i -> data;
			p -> next = s;
          	i = i -> next;
		}
		if(p->next != NULL) p = p -> next;
	}
	//Lc.LL_display();
	return 1;
}

完整代码

#include<bits/stdc++.h>
using namespace std;
#define ok 1
#define error 0


class ListNode {
	public:
		int data;
		ListNode *next;
		ListNode() {
			next = NULL;
		}
};
class LinkList {
	public:
		ListNode *head;
		int len;

		LinkList();
		~LinkList();
		ListNode *LL_index(int i);      
		int LL_get(int i);             
		int LL_insert(int i, int item); 
		int LL_del(int i);              
		void LL_display();         
};

void LinkList::LL_display(){

	for(ListNode* i = head->next; i != NULL; i = i->next){
		cout << i->data << " ";
	}cout << endl;
}
LinkList::LinkList() {
	head = new ListNode();
	len = 0;
}
LinkList::~LinkList() {
	ListNode *p, *q;
	p = head;
	while(p != NULL) {
		q = p;
		p = p->next;
		delete q;
	}
	len = 0;
	head = NULL;
}
ListNode *LinkList::LL_index(int i) { 
	int j=0;
	ListNode *p;
	p=head;
	while(p && j<i-1) { 
		p=p->next;
		++j;
	}
	if(!p || j>i-1) {
		return NULL;
	} else return p; 
}
int LinkList::LL_insert(int i,int item) {
	ListNode *p;
	if(LL_index(i) == NULL)
		return error;
	else
		p=LL_index(i);
	ListNode *s; 
	s=new ListNode();
	s->data=item; 
	s->next=p->next; 
	p->next=s; 
	len++;
	return ok;

}
int LinkList::LL_del(int i) {
	ListNode *p;
	if(LL_index(i) == NULL)
		return error;
	else {
		p=LL_index(i); 
		ListNode *q;
		q=p->next;
		p->next=q->next;
		delete q;
		len--;
		return ok;
	}
}
int LinkList::LL_get(int i) {
	if(i<=0|| i>len)
		return error;
	else {
		ListNode *p;
		p=head;
		int j=0;
		while(p->next&& j<=i-1) {
			p=p->next;
			++j;
		}
		int num=p->data;
		return num;
	}
}

// 合并函数
ListNode* LL_merge(ListNode* list1, ListNode* list2) {
        ListNode* preHead = new ListNode();
        ListNode *head = preHead;
        while(list1 != NULL|| list2 != NULL)
        {
            if(list1 == NULL)
            {
                head->next = list2;
                list2 = list2->next;
            }
            else if(list2 == NULL)
            {
                head->next =list1;
                list1 = list1->next;
            }
            else if(list1->data > list2->data)
            {
                head->next = list2;
                list2 = list2->next;
            }
            else
            {
                head->next =list1;
                list1 = list1->next;
            }

            head = head->next;
        }
        return  preHead->next->next;
}

int main() {
	
	LinkList la,lb;
	int n,item,i;
	cin >> n;
	//输入 
	for(i = 1; i <= n; i++){
		cin >> item;
		la.LL_insert(i,item);
	}

	cin >> n;
	for(i = 1; i <= n; i++){
		cin >> item;
		lb.LL_insert(i,item);
	}
	//
	la.head = LL_merge(la.head,lb.head);
	la.LL_display();


	return 0;
}

D. DS链表—学生宿舍管理

假设某校有20间宿舍,宿舍编号101,102,…,120。每间只住一名学生。初始部分宿舍已用。用两个链表(已用宿舍链表和可用宿舍链表)维护宿舍的管理,实现宿舍分配、宿舍交回。

约定已用宿舍链表按宿舍号升序链接。初始可用宿舍链表也按宿舍号升序链接。

宿舍分配从可用宿舍链表中摘取第一间宿舍分配给学生。学生交回的宿舍挂在可用宿舍链表最后。

备注:使用list容器或静态链表。不用考虑宿舍分配和交回不成功的情况。

输入

输出

样例输入

样例输出

题解

通过结构 Student 来存储 nameid 即姓名和房间号两个数据,方便后续插入比较。

这里采用直接比较,直接插入对应排序位置。
不过 list 中有自定义的 sort 的函数可以使用,可以自定义一个 sort 来在每次输出前进行一次排序

#include<bits/stdc++.h>
using namespace std;

//学生房间结构体定义 
struct student{
	string name;
	int id;
	student(string na,int i){
		name = na; id = i;
	}
};

int main() {
	//初始化链表 
	list <student> stu;
	list <int> fre;
	
	//初始化迭代器 
	list<int>::iterator i;
	list<student>::iterator j;
	
	//哈希表备用 
	map<int,int> ha;
	
	//初始化
	int n,it;
	cin >> n;
	string name;
	for(int i = 0; i < n; i++) {
		cin >> name >> it;
		stu.push_back(student(name,it));
		ha[it]++;
	}
	for(int i = 101; i <= 120; i++) {
		if(!ha[i]) {
			fre.push_back(i);
		}
	}
	
	//房间分配收回操作 
	int m;
	string sign;
	cin >> m;	
	while(m--) {
		cin >> sign;
		//拿取房间
		if(sign == "assign") {
			cin >> name;
			int tmp = fre.front();		
			for(j = stu.begin(); j != stu.end(); ){
				//找到第一个比拿取房间id大的房间或到达末尾,插入房间数据 
				if(j->id > tmp || ++j == stu.end()){
					stu.insert(j,1,student(name,tmp));
					break;
				}
			}
			fre.pop_front();
		}

		//返回房间
		if(sign == "return") {
			cin >> it;
			for(j = stu.begin(); j != stu.end();j++) {
				if(j->id == it) {
					stu.erase(j);
					fre.push_back(it);
					break;
				}
			}
		}

		//输出已使用房间 
		if(sign == "display_used") {
			for(j = stu.begin(); j != stu.end();) {
				cout << j->name << "(" << j->id << ")" ;
				if(++j != stu.end()) cout << "-";
			}
			cout << endl;
		}
		
		//输出未使用房间 
		if(sign == "display_free") {
			for(i = fre.begin(); i != fre.end();) {
				cout << *i ;
				if(++i != fre.end()) cout << "-";
			}
		}
	}
	return 0;
}

举报

相关推荐

0 条评论