蓝桥杯 双向排序 【超时70分】

又是一瓶奶,一道题,一写就是一小时。。。。思路蛮快的,链表删除反倒是出错看了半天我去。

我的思路:

我们不能一个一个机械地按照指令对数组进行排序操作。我们需要对操作序列预先处理,减少复杂度。由于处理过程需要进行增、删、遍历操作,我选择了链表作为数据结构。【不知道有没有更好的数据结构?】

首先说明一个命题:

操作为0是从前面降序,操作为1是从后面升序。假设操作0 m和1 n两次,则这俩操作区域在数组的示意图如下,阴影表示操作区域,要么:

|/m____n\\\\\\\\\\|

要么:

|nXXXm\\\\\\\|

第二种即有所交叉。

由于mn一个升序,一个降序,所以不管是先做m操作还是先做n操作,交叉的n___m段序列都一样。

以此为基础。

建立一个存储操作序列的链表。

typedef struct Link{
	Link* next;
	int p;
	int q;
}Link;
typedef Link* List;

考虑操作数为0,操作下标假设为x。如果在已知的操作序列中,存在操作数为0、操作下标为y(y<x),我们认为0 x操作覆盖了0 y操作,将0 y从操作序列中删除。

此处覆盖指的是操作范围覆盖:

|XXXXXXy\\\\\\\\x________|

【注:这里能够轻易覆盖的原因就是我上面说的命题。】

同理,当操作数为1,操作下标假设为x。如果在已知的操作序列中,存在操作数为1、操作下标为y(y>x),我们认为0 x操作覆盖了0 y操作,将0 y从操作序列中删除。

最后再根据剩下的操作序列,对数组进行排序即可。

代码如下。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//链表的定义
typedef struct Link{
	Link* next;
	int p;
	int q;
}Link;
typedef Link* List;
//链表节点创建函数
Link* CreateLinkNode(int p,int q){
	Link* haha=(Link*)malloc(sizeof(Link));
	haha->next=NULL;
	haha->p=p;
	haha->q=q;
	return haha;
}
//链表添加元素
void AddList(List* list,int p,int q){
	Link* node=CreateLinkNode(p,q);
	if(*list==NULL){
		*list=node;
		return;
	}
	List point=*list;
	while(point->next){
		point=point->next;
	}
	point->next=node;
}
//删除特定元素
void DeleteList(List* list,int p,int q){
	if(*list==NULL)	return;
//删除头节点的情况要特殊考虑
	while(((*list)->p==p)&&(((*list)->p==1&&(*list)->q>=q)||((*list)->p==0&&(*list)->q<=q))){
		*list=(*list)->next;
		if(*list==NULL)	return;
	}
//删除符合条件的一般节点
	List point=(*list)->next;
	List pre=*list;
	while(point){
		if((point->p==p)&&((point->p==1&&point->q>=q)||(point->p==0&&point->q<=q)))
		{
			pre->next=point->next;
			point=pre->next;
		}
		pre=point;
		if(point==NULL)	break;
		point=point->next;
	}
}
//qsort的比较函数
int RisingCompare(const void*a,const void*b){
	return *((int*)a)-*((int*)b);
}
int DecresingCompare(const void*a,const void*b){
	return *((int*)b)-*((int*)a);
}
//清除掉前面重复无用的操作序列,并添加新的操作到操作序列
void DeterminWhetherToLeave(List* list,int p,int q){
	DeleteList(list,p,q);
	AddList(list,p,q);
}

int main(){
//初始化数组
	int numsSize,operaCounts;
	scanf("%d %d",&numsSize,&operaCounts);
	int a[numsSize];
	for(int i=0;i<numsSize;i++){
		a[i]=i+1;
	}
//管理添加操作序列
	List list=NULL;
	for(int i=0;i<operaCounts;i++){
		int p,q;
		scanf("%d %d",&p,&q);
		DeterminWhetherToLeave(&list,p,q);
	}
//按照操作序列进行排序
	List point=list;
	int *b=a;
	while(point){
		if(point->p==1){
			qsort(b+point->q-1,numsSize-point->q+1,sizeof(int),RisingCompare);
		}
		else{
			qsort(b,point->q,sizeof(int),DecresingCompare);
		}
		point=point->next;
	}
//输出结果
	for(int i=0;i<numsSize;i++){
		printf("%d ",a[i]);
		//TODO
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值