数据结构水一篇(冠宏路过要看一下)

本文介绍了如何在已排序的顺序表和链表中去除重复元素,分别给出了线性时间和链表操作的解决方案。此外,探讨了多种解决最大子列和问题的方法,包括O(n^3)、O(n^2)和O(n)的贪心算法,并分析了它们的性能。
摘要由CSDN通过智能技术生成

水一篇

今天主要把论文格式弄完了,感谢沁廷的帮助
然后就写了一下数据结构的实验,顺便看一下冠宏的数据结构作业,写一篇吧
还有,为什么今天不能tab了???导致我这个题解写的很难看,草!

我的数据结构作业

作业真的是so easy(瞎说的)

实验一、
1)针对一个由小到大有序的顺序表,编写程序将其中的重复数据只保留一个,算法时间复杂度为O(n);
例如: 原始表为:3, 5, 5, 5, 5, 7, 8, 8, 8, 9, 9, 11
修改表为:3, 5, 7, 8, 9, 11

/*
实验01 线性表的应用 
思路:
	由于所给的顺序表是由小到大排序的,因此重复的元素一定相邻
	那么就遍历整个线性表,每次遇到新元素就记录一下,如果后面的和它相等就不存进去
	可以重新开辟一个数组用来存放元素,然后复制回原数组,不过这样的空间复杂度高
	考虑到如果有重复的元素,那么可以设置一个new_len用来记录不重复的元素的个数,这样也不会干扰后面还没有遍历的元素

*/

#include<stdio.h>
#define N 12

int List[N]={1,2,3,4,5,6,7,8,9,10,11,12};

int main(){
	int new_len=0;
	int element=List[0];//第一个直接放进去 
	for(int i=1;i<N;i++){
		if(List[i]==element){//如果相同 
			;
		}
		else{
			List[++new_len]=List[i];
		}
		element=List[i];
	}
	for(int i=0;i<=new_len;i++)
		printf("%d ",List[i]);
	return 0;
} 

实验二、
题目:(2)针对一个由小到大有序的链表,编写程序将其中的重复数据只保留一个。(选做)

/*
因为之前我自己已经实现了链表的大部分操作,因此直接将那些操作引入进来
重点是对于重复元素的处理
这个思路应该和上一个实验很相似
这里我们对于一个新的,应该添加进去的,方法同实验一,只需要设置一个新元素指针即可 
*/


#include<stdio.h>
#include<stdlib.h>
//预定义常量
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;//函数结果状态 

typedef int ElemType;//数据元素类型定义,此处选择常用的int,后续可根据数据类型自行更改 

//线性表的单链表存储结构(结构指针):
typedef struct LNode{
	ElemType data;//数据域 
	struct LNode*next;//指针域 
}LNode,*LinkList;//LNode是struct LNode的别名,LinkList是LNode的指针(LinkList=struct LNode*)

LinkList Create(LinkList head){
	 head=(LinkList)malloc(sizeof(LNode));//这个作为头指针
	 LinkList newnode=(LinkList)malloc(sizeof(LNode));
	 LinkList tmp_node;
	 head->next=newnode;
	 ElemType a;scanf("%d",&a);
	 while(a>0){
	 	newnode->data=a;
	 	tmp_node=newnode;
	 	newnode=(LinkList)malloc(sizeof(LNode));
	 	tmp_node->next=newnode;
	 	scanf("%d",&a);
	 } 
	 //此时最后一个结构体中没有值,然后如果将null放在这个结构体的指针域不妥
	 //因此null应该放在前面的那个结构体的指针域中 
	 tmp_node->next=NULL;
	 return head;
}

int main(){
	LinkList head;
	printf("测试数据:\n");
	head=Create(head);//head已经弄好了 
	LinkList p;
	LinkList newnode;
	p=head->next;//p当前指在数据域的第一个
	newnode=p;
	//第一个肯定留下来,就单独处理
	int element;
	element=p->data;
	p=p->next;
	while(p->next){//相当于遍历了,时间复杂度为O(n)
		if(element==p->data){//如果是重复的 
			;
		} 
		else{
			newnode=newnode->next;
			newnode->data=p->data;
		}
		element=p->data;
		p=p->next;
	}
	//还有最后一个单独考虑
	if(element!=p->data){
		newnode=newnode->next;
		newnode->data=p->data;
	} 
	newnode->next=NULL;
	//可以把后面的结点都free了,但是这个我没写 
	newnode=head->next;
	while(newnode->next){
		printf("%d ",newnode->data);
		newnode=newnode->next; 
	}
	printf("%d",newnode->data);
	return 0;
} 

冠宏的数据结构作业

题目一

求最大子列和。设计并实现2种求最大子列和的方法,并分析其算法的时间复杂度。

方法一

  • 这个算法复杂度为O(n三次方)
/*
最大子列和 
方法一就是遍历就

行了,直接看代码吧,easy 
*/


#include<stdio.h>
#include<iostream>
using namespace std;
//方法一: 
int main(){
	int n;
	long long a[2002];
	long long ans=-9223372036854775808;
	long long tem=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){//序列数的个数 
		for(int j=1;j<=n-i+1;j++){//从第几个开始遍历 
			for(int k=j,time=1;time<=i;k++,time++){//具体的遍历过程
				tem+=a[k];
			}
			ans=tem>=ans?tem:ans;
			tem=0;
		}
	}
	cout<<ans;
	return 0;
}

为什么我感觉法一是对的,但是在oj上测试不对呢,而且我数据都不能全部输入进去,疑惑。

冠宏别用方法一,可能不对

方法二

  • 这个是我早晨时候看题解猛然醒悟的方法,其实和方法一 一样,但是我们只需要O(n方)的复杂度就可以了。我真憨,我单知道那个方法拉的一批,我还写。。。
/*
此方法为n方复杂度 
*/ 

#include<iostream>
using namespace std;
int n;
long long a[200002];
long long ans=-9223372036854775807;
long long tem=0;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){//从第几个开始 
		tem=0;
		for(int j=i;j<=n;j++){
			tem+=a[j];
			ans=tem>=ans?tem:ans;
		}
	}
	cout<<ans;
	return 0;
}

这个在OJ上只能过2个,后面超时,说明n方的方法依旧不行

方法三

贪心,直接贴代码

/*
方法三、
本方法是贪心算法:
贪心的思路是
我们遍历,如果当前子序列的和是负数的话,那么果断舍弃重开,因为开头就是负数,我加了岂不是吃亏?
如果当前的和不是负数,那就记录,依旧是用当前的子序列加上新的元素
之前我对这个还有疑惑,但是现在想一下,要是求元素和最大的子序列
如果没有负数的话,岂不是数越多越好??那么如果刚开始的都是正数,那我们就要了
当然如果是负数就类似于上面的方法,我们直接重新开始子序列。
这样的贪心肯定是对的,当然为了确保该子序列最后那些都不是复制,也要设置tem和ans,详见代码,你会懂的 
该算法时间复杂度为O(n),效率感人。 
*/ 

#include<iostream>
using namespace std;
int n;
long long a[200002];
long long ans=-92233720368547757;
long long tem=0;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	} 
	for(int i=1;i<=n;i++){
		tem+=a[i];
		ans=tem>=ans?tem:ans;
		if(tem<0)
			tem=0;	
			
	}
	cout<<ans;
	return 0;
}

方法四

DP算法,和贪心好类似啊😌

/*
dp做法 
思路:
	定义一下:dp[i]表示到第i个能有的最大子序列和
	那么在dp[i]处就有继承和重头开始这两个选项
	那么就是包含a[i]这里我们要比较一下,加上这个之后的序列和从头开始(a[i])比较,选取一个大的
    因为我们希望加后面的话,让前面的基础大一点最好
	如果发现加上后整体大,那么就继承
	如果发现加上后整体小,那么就重新开始(其实就是和贪心很像,如果前面序列和是负的,那么我们就不要)
	猛然惊醒,这不就是贪心算法吗??? 
*/
#include<iostream>
using namespace std;
long long a[200002];
long long dp[200002];
int n;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		dp[i]=max(dp[i-1]+a[i],a[i]);
	}
	long long ans;
	ans=dp[1];
	for(int i=2;i<=n;i++){
		ans=dp[i]>ans?dp[i]:ans;
	}
	cout<<ans;
	return 0;
} 

好的,不写了,饭饭去了

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值