pat乙级:模拟链表问题(汇总,包含所有pat中链表题目分析)

更新:优化文章结构,增加了部分内容如(1110区块反转)和自己代码和他人代码分析。看完你就懂了
转载请注明出处和链接地址:(https://www.cnblogs.com/ahappyfool/p/17156470.html)

我优化并且总结分解为以下四个步骤:

  1. 第一先建立结构体,并且将这些输入数据储存起来,怎么储存呢?用结构体数组存,注意:想要存下这些数据,他们的下标都非常大,也就是要大数组。这个大数组得在main函数外定义。
  2. 在输入完链表之后,遍历链表使用另一个数组(可以是指针数组也可以是节点数组)记录下该节点的地址或者将节点的顺序调对,并且记录有多少个节点(加个变量记录就行,还可以用来作为变化的数组下标),读到-1停止。注意不能使用小于n作为终止条件,会有像-1 0 -1这样的无效节点被读入。
  3. 对该指针数组进行操作:反转还是什么,按题目要求。
  4. 然后就进行对应的操作输出就行了

下面是我做的一题:pat乙级1110区块反转。给你们演示一下步骤分析和一些应该注意的点

#include<bits/stdc++.h>
using namespace std;
//第一步
struct node {
    int addr,data, next;
}list1[100000];
node*b[100000][500];  //使用二维数组将已经储存了每个节点地址的变量分块
int main(){
    node* a[100005];
    int first,n,k;cin>>first>>n>>k;
    for (int i = 0; i < n; i++) {
        int a1;
        scanf("%d", &a1);
        list1[a1].addr=a1;
        scanf("%d%d", &list1[a1].data, &list1[a1].next);
    }
//第二步
    int tmp = first,ihh=0;     //不要忘记ihh作为变量记录有效节点个数
    while(tmp!=-1){
        a[ihh++]=&list1[tmp];
        tmp=list1[tmp].next;//遍历
    }
//第三步:
    int num=ihh/k,cnt=0;
    if(num*k<ihh)num++;
    for(int i=0;i<num;i++){
        for(int j=0;j<k&&cnt<ihh;j++){
            b[i][j]=a[cnt++];//分块
        }
    }
//第四步
    cnt=0;int kkk=ihh-num*k+k;
    for(int i=num-1;i>=0;i--){
        for(int j=0;j<kkk;j++){
            if(i==num-1&&j==0)printf("%05d %d ",b[i][j]->addr
			,b[i][j]->data);//第一个数据都是这样输入的
            else printf("%05d\n%05d %d ",b[i][j]->addr,
			b[i][j]->addr,b[i][j]->data);//后面这样
        }
        kkk=k;
    }
    printf("-1");//补个-1
    return 0;
}

pat中还有关于链表的三个题目1025:反转链表,1075,链表元素分类,1100,链表合并。你们可以分析以下代码和我的代码有什么不同之处。相信你会有所收获

以下代码来自柳婼的博客

1025:反转链表

	#include <iostream>  
	#include <algorithm>  
	using namespace std;  
	int main() {  
		int first, k, n, temp;  
		cin >> first >> n >> k;  
		int data[100005], next[100005], list[100005];  
		for (int i = 0; i < n; i++) {  
			cin >> temp;  
			cin >> data[temp] >> next[temp];  
			}  
		int sum = 0;//不⼀定所有的输⼊的结点都是有⽤的,加个计数器  
		while (first != -1) {  
			list[sum++] = first;  
			first = next[first];  
			}  
		for (int i = 0; i < (sum - sum % k); i += k)  
			reverse(begin(list) + i, begin(list) + i + k);  
		for (int i = 0; i < sum - 1; i++)
			printf("%05d %d %05d\n", list[i], data[list[i]], list[i + 1]);  
			printf("%05d %d -1", list[sum - 1], data[list[sum - 1]]);  
		return 0;  
	}

1075:链表元素分类

		将结点⽤list[10000]保存, list为node类型, node中保存结点的值value和它的next地址。 list的下标就是结点的地址。将<0、 0~k、 >k三部分的结点地址分别保存在v[0]、 v[1]、 v[2]中,最后将vector中的值依次输出即可  .即只遍历一次,减少遍历次数
		#include <iostream>  
		#include <vector>  
		using namespace std;  
		struct node {  
		int data, next;  
		}list[100000];  
		vector<int> v[3];  
		int main() {  
			int start, n, k, a;  
			scanf("%d%d%d", &start, &n, &k);  
			for (int i = 0; i < n; i++) {  
				scanf("%d", &a);  
				scanf("%d%d", &list[a].data, &list[a].next);  
				}  
			int p = start;  
			while(p != -1) {  
				int data = list[p].data;  
				if (data < 0)  
				v[0].push_back(p);  
				else if (data >= 0 && data <= k)  
				v[1].push_back(p);  
				else  
				v[2].push_back(p);  
				p = list[p].next;  
				}  
			int flag = 0;  
			for (int i = 0; i < 3; i++) {  
				for (int j = 0; j < v[i].size(); j++) {  
					if (flag == 0) {  
						printf("%05d %d ", v[i][j], list[v[i][j]].data);  
						flag = 1;  
						} 
					else {  
					printf("%05d\n%05d %d ", v[i][j], v[i][j], list[v[i][j]].data);  
					}  
				}  
			}  
			printf("-1");  
			return 0;  
		}

1105:链表合并:⽤vector L1、 L2存储题⽬中给定的两个链表, vector ans保存合并后的链表。将较⻓的⼀个链表存储在L1中,如果原本L1较短,则将L1与L2⽤swap函数互相置换~在链表合并的过程中, i从0开始,将L1中每个结点添加到ans中,如果当前i是奇数(i & 1不等于0)就把L2的⼀个结点添加到ans中,直到L2中没有剩余元素,反复,我是遍历了两遍,然后如果大小区分就swap首地址。

#include <iostream>  
#include <vector>  
using namespace std;  
struct node {  
int data, next;  
}A[100000];  
vector<int> L1, L2, ans;  
int sa, sb, n, a, ta, tb, c;  
int main() {  
	cin >> sa >> sb >> n;  
	for (int i = 0; i < n; i++) {  
		cin >> a >> A[a].data >> A[a].next;  
	}  
	ta = sa;  
	while (ta != -1) {  
		L1.push_back(ta);  
		ta = A[ta].next;  
	}  
	tb = sb;  
	while (tb != -1) {  
		L2.push_back(tb);  
		tb = A[tb].next;  
		}  
	if (L1.size() < L2.size()) swap(L1, L2);  
	for (int i = 0, c = L2.size() - 1; i < L1.size(); i++) {  
		ans.push_back(L1[i]);  
		if (i & 1 && c >= 0) ans.push_back(L2[c--]);  
		}  
		for (int i = 1; i < ans.size(); i++) {  
		printf("%05d %d %05d\n", ans[i-1], A[ans[i-1]].data, ans[i]);
	}  
	printf("%05d %d -1", ans.back(), A[ans.back()].data);  
	return 0;  
	}

总结:

  1. 你会发现可以不用指针数组,而采用结构体数组存储,
  2. 地址其实就等于结构体数组的下标,完全可以不用addr这个变量来记录地址,因为它是可以通过其他方式来表示出来的。但是我为什么还要采用有addr的结构体呢?这种方式,更容易理解,更加利于输出和思考,地址和data有相同的输出方式。
    3.方法要适合自己的方法才是好方法
    部分思路来自:
    看完后思路清晰:1025链表一连a三题链表题。
posted @ 2023-03-01 11:20  fool_king  阅读(33)  评论(0编辑  收藏  举报