顺序表:找未出现最小正整数,时间尽可能高效【C语言,数据结构】(内含源代码)

目录

 

题目:

题目分析:

思路解析:

源代码:

总结:


题目:

给定一个含n(n>=1)个整数的数组,请设计并实现一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。

例如,数组{-5,3,2,3}中未出现的最小正整数是1;数组{1,2,3}中未出现的最小正整数是4。

题目分析:

1.输入数据是无序的。

2.时间上尽可能高效,代表着我们不能去对数组排序,不然就不是时间高效了。也不能一个一个找,从1开始找该数是否出现,这样的操作时间也是不够高效的。

思路解析:

要找出最小正整数,肯定要对数组中每一个数都要遍历。

首先,负数对我们的结果没有影响,所以先判断是否是负数,不是负数在进行接下来的操作。

其次,我们做一个表来检测哪些数出现过,就像签到表,出现过就在它对应的地方做一个标记。这样我们只需要遍历一边输入数组,再遍历一边签到表就能找出答案了。

d68f47e89045419496bf2f20020a303f.png

如例题所示,签到表就应该长这样。

那么还有个问题,签到表应该多长呢? 

这个问题十分尖锐,因为签到表至少需要装下输入元素中最大的元素,而我们又不知道表中最大元素,所以我们需要在便利一遍数组,找出最大元素。

还有个方法,那就是当扫描到下一个数,超出签到表长度的时候,我们就再创建这么多数组,给签到表加长。这个方法是最优解,这个就交给你们自己去完成了。

怎么做呢?

用签到表的顺序i来表示哪个数,便利到这个数n那么就让签到表a[n]++,让它不是0,就代表出现过。

源代码:

#include <stdio.h> 			//头文件
#include <stdlib.h>
#include <malloc.h>
#include <conio.h>
#define ERROR 0 			//函数结果状态代码
#define OK 1
#define EQUAL 1
#define OVERFLOW -1
#define LIST_INIT_SIZE 100	//顺序表存储空间的初始分配量
#define LISTINCREMENT 10	//顺序表存储空间的分配增量

typedef int Status;			//Status为函数返回值类型,其值为函数结果状态代码

struct NUMBER {
	int number;
};
typedef struct NUMBER ElemType;//顺序表中数据元素类型

struct LIST {
	ElemType *elem;			//顺序表的存储空间基址
	int length;				//当前长度
	int listsize;			//当前分配的存储容量
};
typedef struct LIST SqList;	//线性表的顺序存储结构定义

Status InitList_SqList(SqList *);	//构造一张新的顺序表L
Status ListInsert_SqList(SqList *, int, ElemType );	//在顺序表L的第i个元素前插入新元素e
int ListLength_SqList(SqList);		//求顺序表L的长度
Status Destroy_SqList(SqList *);		//销毁一张顺序表
void printlist_SqList(SqList);		//输出顺序表
int FindMax(SqList);	//找最大数
int FindUMin(SqList);	//返回数组中未出现的最小正整数

void input(SqList *);	//输入操作

//****main****
int main() {
	int UMin;	//未出现最小正整数
	SqList La;
	InitList_SqList(&La);
	
	input(&La);					//根据输入创建La
	
	printf("Original SqList: ");
	printlist_SqList(La);		//输出原顺序表
	
	UMin = FindUMin(La);	//找出未出现最小正整数
	printf("Number is: %d",UMin);	//输出结果
	
	return 0;
}//main

void input(SqList *La){	//输入操作
	int l;		//用户想要创建的列表长度
	ElemType e;
	printf("How long a sequence list do you want to create?\n");
	scanf("%d",&l);
	printf("Please enter some integers to fill the sequence List:\n");

	for(int i = 1; i<=l; i++) {	//挨个把用户输入存入顺序表
		scanf("%d",&e.number);
		ListInsert_SqList(La,i,e);
	}
}	//input


Status InitList_SqList(SqList *L) {	//构造一个空顺序表L
	L->elem=(ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));//分配内存
	if(!L->elem)
		exit(OVERFLOW);
	L->length = 0;
	L->listsize = LIST_INIT_SIZE;
	return OK;
}	//InitList_SqList

Status ListInsert_SqList(SqList *L, int i, ElemType e) {	//在顺序表L的第i个元素前插入新元素e
	ElemType *newbase, *p, *q;
	if(i<1 || i>L->length+1)
		return ERROR;				//插入位置不合法
	if(L->length >= L->listsize) {	//当前存储空间已满,增加分配
		newbase = (ElemType *)realloc(L->elem, (L->listsize + LISTINCREMENT)*sizeof(ElemType));
		if(!newbase)
			return ERROR;			//存储分配失败
		L->elem = newbase;			//新基址
		L->listsize += LISTINCREMENT;	//增加存储容量
	}
	q = &(L->elem[i-1]);			//q指向插入位置
	for(p = &L->elem[L->length - 1]; p>=q; --p)
		*(p+1) = *p;				//插入位置之后的数据元素右移
	*q = e;							//插入e
	L->length++;
	return OK;
}	//ListInsert_SqList

int ListLength_SqList(SqList L) {	//求顺序表L的长度
	return L.length;
}	//ListLength_SqList;

Status Destroy_SqList(SqList *L) {	//销毁一张顺序表
	free(L);
	return OK;
}	//Destroy_SqList

void printlist_SqList(SqList L) {	//输出顺序表
	int i;
	for(i = 0; i<L.length; i++)
		printf("%d ", L.elem[i].number);
	printf("\n");
}	//printlist_SqList;

int FindUMin(SqList L) {	//返回数组中未出现的最小正整数
	int max = 0;FindMax(L);
	if(max<1){
		return 1;
	}else {
		for(int i=0;i<L.length;i++){
			List[L.elem[i].number]++;
		}
		for(int i=1;i<max;i++){
			if(List[i]==0){
				return i;
			}
		}
		return max+1;
	}
}	//FindUMin

int FindMax(SqList L){	//找最大数
	int max = L.elem[0].number;
	for(int i=0;i<L.length;i++){
		if(max<L.elem[i].number){
			max = L.elem[i].number;
		}
	}
	return max;
}//FindMax

总结:

这道题还是要懂一点脑筋的↖(^ω^)↗

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值