二、线性表的顺序存储(上)

注1:顺序存储一般用数组实现,下标从0开始,而线性表的位序一般从1开始。
注2:采用动态分配一般需要free手动释放,静态分配系统自动回收。

线性表的基本操作:增删改查

(1)InitList(&L):初始化表,构造一个空的线性表

//静态分配
#define MaxSize 10
typedef struct{
	ElemType date[MaxSize];//分配元素个数
	int length;//线性表长度
}SqList;

InitList(&L){
	for(int i=0;i<MaxSize;i++)
	L.date[i]=0;//这一步是必要的,为了防止‘脏’数据
	L.length=0;//一开始线性表初始长度为0
}
//动态分配
//使用malloc动态申请内存空间
#include <stdlib.h> //malloc\free的头文件
#define initSize=100;
typedef struct{
ElemType *data;//定义指针指向新开辟内存空间地址
int MaxSize;//线性表的最大容量
int length;
}SeqList;

InitList(SeqList &L)
{
L.data=(ElemType *data)malloc(InitSize*sizeof(ElemType));
//注意要将将指针变量强制转化为线性表的指针变量类型,指针返回的是内存空间的首地址
L.length=0;
L.MaxSize=initSize;
}

采用动态分配实际上是开辟了新的大一点的内存空间存放原来的数组,再将原来那个连续的空间释放掉
(2)length(L):返回线性表长度
(3)LocateElem(L,e):按数值查找
GetElem(L,i):按位序查找

//数值查找,结果返回数值对应的位序
int LocateElem(SqList L,ElemType e){
for(int i=0;i<L.length;i++)
	if(L.data==e)
	return i+1;//返回位序,从1开始
return 0;//查找失败,返回0
}
//按位序查找,返回对应位序上的数值
int GetElem(SqList L,int i){
return L.data[i-1];//数组下标从0开始
}

(4)ListInsert(&L,i,e):在i位置上插入e数据
ListDelete(&L,i,&e):删除e数据

Q:为什么删除用&?
A:1.返回被删除元素。
2.同时保证删除操作对应同一个对象,而不是仅仅删除线性表里的那个e。

//在i处(位序)插入e,实际插入的时候,对应的数组里应该在i-1处插入e,
//需要将其后面都往下移一个单位
bool ListInsert(SqList &L,int i,ElemType e){
//尤其注意的地方:移动是从尾部都向后移一个单位,length是线性表的长度
for(i<1||i>L.length+1)
	//可以在表尾插入,但不能隔一个插入
	return false;
for(i>=L.MaxSize)
	return false;//表满不可插
for(int j=L.length;j<=i;j++)
	//线性表的最后一位对应数组里的第j-1位
	L.data[j]=L.data[j-1];
L.data[i-1]=e;
return true;

//删除从删的位置依次往前挪,使用引用变量返回删掉的值
//注意:映射到数组中实际删的是i-1,i位置是不被删除的
bool ListDelete(SqList &L,int i,ElemType &e){
for(i>L.length||i<1)
	return false;
e=L.data[i-1];
for(int j=i;j<L.length-1;j++)
	L.data[j-1]=L.data[j];
//删掉时对应表的长度需要缩短
L.length--;
return true; 
}

(5)其他操作:DestoryList(&L)、Empty(L)PrintList(L)

习题

1.顺序表具有随机存储的特性
2.一维数组R里,循环左移p个单位
算法思想:
将数组分为移位部分和移位两个部分,分别为a和b,对a做逆序,再对b做逆序,再整体对逆序后的ab做逆序即可.
reverse(&L,0,p-1);//a—>a-1
reverse(&L,p,n);//b—>b-1
reverse(&L,0,n);//ab—>ab-1
算法实现:

Reverse( int r[],int s,int e){
ElemType temp;
for(int i=s;i<(s+e)2;i++)
	temp=r[i];
	r[i]=r[e-1];
	r[e-1]=temp;
}
int main(int r[],int s,int e){
reverse(r,0,p-1);
reverse(r,p,n);
reverse(r,0,n);
}

3.找出两个等长升序序列A和B的中位数
算法思想:一个方法是将A和B依次进行比较,在A和B的中位数之前的部分总能找到A和B的中位数,但时间复杂度为O(n2)
因此,考虑另外一种方法,将A和B的中位数拿出来,分别为m1和m2,将两个中位数进行比较,如果两个中位数相等,那么答案就是二者之一,如果不等,判断,如果m1>m2,这个时候中位数一定不可能是A的较小的部分,中位数一定在A的后半部分产生,同理,B中中位数一定在小于m2的那部分产生,依次循环找下去,能够找到A和B的中位数,类似于做两个折半查找操作,因此,时间复杂度应该是O(logn)
应该注意的另一点是,根据所给数组长度的奇偶性应该又不同的去头或去尾方法。

why?
为了保证去掉前半部分或者后边部分的时候两个数组长度是一样的。因为两个数组的中位数要进行比较,如果都是偶数数组,那么一个去前,另一个取尾部(在不保留中位数的情况下),两边的长度会不一致。

算法实现:

int main(int A[],int B[],n)//n数组长度
{
	int s1,e1,m1;//首元素,尾元素,中位数
	int s2,e2,m2;
	while(s1!=e1&&s2!=e2)
	{
		m1=(s1+e1)/2;
		m1=(s1+e1)/2;
		if(m1==m2)
			return m1;
		if(m1>m2)
			{//保留m1前半部分,m2后半部分
			//需要判断偶数序列或者奇数序列
				if((s1+e1)%2==0)//奇数
				{
					e1=m1;
					s2=m2;
				}
				else//偶数
				{
					e1=m1;
					s2=m2+1;
				}
		else
		{//m1>m2,保留m1前半部分,m2后半部分
			if(s1+e1)%2==0)//奇
			{
				e1=m1;
				s2=m2;
			}
			else//偶
			{
				s1=m1+1;
				e2=m2;
			}

		}
		}
		
	}
	return A[s1]<B[S2]? A[s1]:B[s2];
}

4.求整数序列的主元素,不存在就返回-1

//O(n^2^)
int maj(int a[],int n){
int count=1;//计数
int c=a[0];预选a[0]为主元素
for(int i=1;i<n;i++){
	if(c==a[i])
		count++;
	else
		if(count>0)//不等的话分两种情况:如果当前的count=1,那么-1;,count=0,则换下一个候选主元素,并将count置1
			count--;
		else//count=0
		{
			c=a[i];
			count=1;
		}
}
count=0;
for(int j=0;j<n;j++)
	if(c==a[j])
	count++;
if(count>n/2)
	return c;
else
	return -1;
}

5.在一个整数数组里找最小正整数
算法思想:
依次遍历数组,设置最小整数数c初始值为99,将c与a[i]-1依次比较,如果a[i]-1<c,那么将c设置为a[i]-1,如果a[i]<0,则continue,如果a[i]-1==1,则break,若a[i]-1=0,则coutinue

//O(n)
int min(int a[],int n)
{
int c=99;
for(int i=0;i<n;i++)
{
	if(a[i]<0||a[i]-1=0)
	continue;
	if(a[i]-1==1)
	{
		c=a[i]-1;
		break;
	}
	if(a[i]-1<c)~~删除线格式~~ 
		c=a[i]-1;
return c;
}

未完待续…

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只爱圣女果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值