SXU-数据结构与算法实验一(链表)

1、创建并操作循环链表

【问题描述】输入n个整数,创建一个双向循环链表进行存储。这些整数从第二个开始,递增有序(设a2<a3<...<an) (ai为第i个整数)。试编写程序,创建双向循环链表,依次将输入的整数存储在该链表的各节点中。然后,将第一个结点删除并插入链表中的适当位置,使整个链表递增有序。
【输入形式】先输入整数的个数,再输入整数列。
【输出形式】以整数递增的顺序,依次输出双向循环链表各个节点存储的整数。
【样例输入】5 3 1 2 4 5
【样例输出】1 2 3 4 5

#include<iostream>
using namespace std;
//定义双向循环链表结构体类型
typedef struct DuLNode {
	int data;
	struct DuLNode* prior;
	struct DuLNode* next;
}DuLNode, * DuLinkList;
//尾插法创建循环双链表
void CreateList(DuLinkList& L) {
	L = (DuLinkList)malloc(sizeof(DuLNode));
	L->next = L;
	L->prior = L;
	int n;
	cin >> n;
	DuLNode* q = L;//设置一个哨兵
	for (int i = 0; i < n; i++) {
		DuLNode* p = new DuLNode;//生成新节点
		cin >> p->data;
		q->next = p;
		p->prior = q;
		p->next=L;
		L->prior=p;
		q = q->next;
	}
}
//删除链表中第一个节点并插入合适的位置
void Sort(DuLinkList& L) {
	DuLNode* p = L->next;//p为首节点
	DuLNode* elem = p->next; //遍历剩余节点,确定插入位置
	while (p->data > elem->data && elem!=L ) {//elem永远指向插入位置的后一个位置,共有三种情况:
		elem = elem->next;                    //1.插入位置在链表开头
	}										  //2.插入位置在中间
	//删除首节点p							   //3.插入位置在链表末尾
	p->next->prior = p->prior;
	p->prior->next = p->next;
	//将p插入适当位置
	p->prior = elem->prior;
	p->next = elem->prior->next;
	elem->prior->next = p;
	elem->prior = p;
}
//链表的输出
void Output(DuLinkList& L) {
	DuLNode* p = L->next;
	while (p != L) {
		cout << p->data << " ";
		p = p->next;
	}
}
int main() {
	DuLinkList L;
	CreateList(L);
	Sort(L);
	Output(L);
	return 0;
}

2、创建链表

【问题描述】定义一个包含学生某门课程成绩信息(学号、成绩)的单链表,读入相应的成绩数据来完成学生成绩信息表的创建。然后,逐行输出每个学生的成绩信息。
【输入形式】输入1行,包括3位同学的成绩信息(学号、成绩)。学号、成绩之间用半角逗号“,”分隔,相邻同学的成绩信息用空格分隔。其中学号取最后三位,成绩为整数类型。
【输出形式】总计输出3行,每个学生成绩信息占一行,学号、成绩用半角逗号“,”分隔,其中学号取后三位。
【样例输入】201,98  202,94  203,89
【样例输出】

[num=201,score=98]

[num=202,score=94]

[num=203,score=89]

# include<iostream>
using namespace std;

typedef struct StuInfo {
	struct StuInfo* next;
	int num;//学号
	int score;//成绩
}StuInfo, * StuInfoList;

//尾插法创建单链表
void Creat_List(StuInfoList& L) {
	L = (StuInfoList)malloc(sizeof(StuInfo));//建立带头结点的单链表
	L->next = NULL;
	StuInfo* q = L;//设一个哨兵
	char c;//处理逗号
	for (int i = 0; i < 3; i++) {
		StuInfo* p = new StuInfo;//生成新节点
		cin >> p->num;
		getchar();
		cin >> p->score;
		q->next = p;
		q = p;
	}
}
void Output(StuInfoList& L) {
	StuInfo* p = L->next;
	for (int i = 0; i < 3; i++) {
		int num = p->num;
		if (num >= 0 && num < 10) {   //学号后三位为一位数
			cout << "[num=00" << p->num << ",score=" << p->score << "]" << endl;
		}
		else if (num >= 10 && num < 100) {//学号为两位数
			cout << "[num=0" << p->num << ",score=" << p->score << "]" << endl;
		}
		else
			cout << "[num=" << p->num << ",score=" << p->score << "]" << endl;
		p = p->next;
	}
}
int main() {
	StuInfoList L;
	Creat_List(L);
	Output(L);
	return 0;
}

3、数组主元素

【问题描述】已知一个整数序列A长度为N其中若存在a且a的个数大于N/2则称为A的主元素。例如:0 5 5 3 5 7 5 5 ,则为主元素 5。又如:0 5 5 3 5 1 5 7,则其中没有主元素。假设中的个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出的主元素。若存在主元素则输出该元素否则输出-1
【输入形式】一个整数数组
【输出形式】主元素

[方法一]:双层循环遍历数组,找到主元素(节省了空间,时间复杂度为n^2)

[方法二]:设置一个计数数组count[maxnum],每出现一个数字num,count[num](当maxnum很大时,非常浪费空间)

这里采用第一种方法

# include<iostream>
using namespace std;
typedef struct {
	int* elem;
	int length;
}SqList;

int main() {
	SqList L;
	L.elem = new int[100];
	L.length = 0;
	int num = 0;
	int maxnum = 0;
	char ch = ' ';
	while (cin >> num) {  //读入数据
		L.elem[L.length] = num;
		L.length++;
		if (ch = getchar() == '\n')//读到回车,停止读入
			break;
	}
	for (int i = 0; i < L.length / 2 + 1; i++) {//对表中前半段元素依次查找
		int count = 0;
		for (int j = i; j < L.length; j++) {
			if (L.elem[i] == L.elem[j])
				count++;
		}
		if (count > L.length / 2) {
			maxnum = L.elem[i];//记录count取最大值时对应的元素
			break;
		}
		maxnum = -1;//未找到,将maxnum赋值为一
	}
	cout << maxnum << endl;//输出结果
	return 0;
}

4、合并链表

【问题描述】
 两个非降序链表的并集,例如将链表1->2->3 和 2->3->5 并为 1->2->3->5,只能输出结果,不能修改两个链表的数据。

【输入形式】
 第一行为第一个链表的各结点值,以空格分隔。
 第二行为第二个链表的各结点值,以空格分隔。

【输出形式】
 合并好的链表,以非降序排列,值与值之间以空格分隔

⚠注意题目中要求不能修改原链表,因此需要新建一个单链表,每次建立需要建立新节点,并将原链表中的值赋给新节点

# include<iostream>
using namespace std;
typedef struct LNode {
	struct LNode* next;
	int data;
	int length;
}LNode, * LinkList;

//尾插法创建单链表
void Creat_List(LinkList& L) {
	L = new LNode;
	L->length = 0;
	LNode* q = L;
	LNode* p = new LNode;
	p->next = NULL;
	cin >> p->data;
	q->next = p;
	q = p;
	while (cin.get() != '\n') {   //按下回车时循环停止
		LNode* np = new LNode;
		np->next = NULL;
		cin >> np->data;
		q->next = np;
		q = np;
	}
	q->next = NULL;
}
//Merge算法合并链表
void MergeList(LinkList L1, LinkList L2, LinkList& L3) {
	L3 = new LNode; L3->next = NULL;
	LNode* p1 = L1->next; LNode* p2 = L2->next; LNode* p3 = L3;
	while (p1 != NULL && p2 != NULL) {
		LNode* newnode = new LNode;
		if (p1->data <= p2->data) {
			newnode->data = p1->data; p1 = p1->next;
		}
		else {
			newnode->data=p2->data; p2 = p2->next;
		}
		p3->next = newnode;
		p3 = newnode;
	}
	while (p1 != NULL) {
		LNode* newnode = new LNode;
		newnode->data = p1->data;
		p3->next = newnode; p3 = newnode; p1 = p1->next;
	}
	while (p2 != NULL) {
		LNode* newnode = new LNode;
		newnode->data = p2->data;
		p3->next = newnode; p3 = newnode; p2 = p2->next;
	}
	p3->next = NULL;
}
//删除链表中重复元素
void Delete_Node(LinkList& L) {
	int max = -10000;
	LNode *p = L;
	LNode *q = L->next;
	while (q!=NULL) {
		p->next = NULL;
		if (q->data > max) {
			p->next = q;
			p = q;
			max = q->data;
		}
		q = q->next;
	}
}
//输出链表
void Output(LinkList L) {
	LNode* elem = L->next;
	while (elem != NULL) {
		cout << elem->data << ' ';
		elem = elem->next;
	}
	cout << endl;
}
int main() {
	LinkList L1;
	LinkList L2;
	LinkList L3;
	Creat_List(L1);
	Creat_List(L2);
	MergeList(L1, L2, L3);
	Delete_Node(L3);
	Output(L3);
	return 0;
}

5、输出链表倒数第K个节点值

【问题描述】输入一个单向链表,输出该链表中倒数第k个结点,链表的最后一个结点是倒数第1个节点。
【输入形式】输入第一位为K值,其后接一串以空格分隔的整型值。
【输出形式】输出为倒数第K个结点的值,若无,则输出Not Found

方法一:(投机取巧,不建议这样做)直接用头插法创建单链表,这样倒数第k个节点,即为头插法正数第k个节点

# include<iostream>
using namespace std;
typedef struct LNode {
	struct LNode* next;
	int data;
	int length;
}LNOde,*LinkList;

//头插法创建单链表
LinkList Create_List(LinkList &L) {
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	L->length = 0;
	while (cin.get()!='\n') {   //按下回车时循环停止
		LNode* p = new LNode;
		cin >> p->data ;
		p->next = L->next;
		L->next = p;
		L->length++;
	}
	return L;
}
//输出倒数第k个节点
void Output(LinkList L,int k) {
	LNode* p = L;
	if (k <= 0 || k > L->length) {
		cout << "Not Found" << endl;
	}
	else {
		for (int i = 0; i < k; i++) {
			p = p->next;
		}
		cout << p->data << endl;
	}
}
int main() {
	LinkList L;
	int k;
	cin >> k;
	L=Create_List(L);
	Output(L, k);
	return 0;
}

方法二:(最推荐的做法)当用尾插法得到一个正序的链表时

思路:设置双指针,前一个指针p移动k个距离后后一个指针q开始移动,两个指针相隔的距离始终为k当p指针碰到末尾时,q指针正好指向倒数第k个节点

#include<iostream>
using namespace std;

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

//尾插法创建链表
void CreateList(LinkList& L) {
	L = new LNode;//创建带有头节点的单链表
	LNode* p = L;
	char c = ' ';
	int num;
	while (c != '\n') {
		LNode* q = new LNode;
		q->link = NULL;
		cin >> num;
		q->data = num;
		p->link=q;
		p = p->link;
		c = getchar();
	}
}
void find(LinkList L) {
	int k;
	cin >> k;
	LNode* p = L;
	int count = 0;
	while (p&&count<k) {//p指针先走k
		count++;
		p = p->link;
	}
	if (!p) {//p为空查找失败
		cout << "Not Found" << endl;
		return 0;
	}
	LNode* q = L->link;//q指针与p指针相隔k个单位移动
	while (p->link!=NULL) {
		p = p->link;
		q = q->link;
	}
	cout << q->data<<endl;
}
int main() {
	LinkList L;
	CreateList(L);
	find(L);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值