【数据结构】顺序表(下)

所属专栏:初始数据结构
博主首页:初阳785
代码托管:chuyang785>
感谢大家的支持,您的点赞和关注是对我最大的支持!!!>博主也会更加的努力,创作出更优质的博文!!
关注我,关注我,关注我,重要的事情说三遍!!!!!!!!

【数据结构】顺序表(下)

  • 1.前言
    • 1.1函数的声明
  • 2.查找数据
  • 3.给定一个位置插入数据
  • 4.给定一个位置删除数据
  • 5.整体代码优化

1.前言

相信看到这里的小伙伴肯定是看过我上一期的博客【数据结构】顺序表(下)同时也完成了上一期我给你们布置的作业,当然你们肯定是实现好了接口函数。而我出这一期的目的是对比一下小伙伴们的写法和我的写法有什么不同,后者说谁的更优,如果小伙伴们的更优欢迎在评论区指出我的不足,如果不是的话也欢迎小伙伴们互相学习,可以那我的当作借鉴。
好了我们们直接进入本章节的主题:

1.1函数的声明

//找到x并返回它的下标,找不到返回-1
int SeqListFind(SL* ps, SLDataType x);
//给定一个位置插入
void SeqListInsert(SL* ps, int pos, SLDataType x);
//给定一个位置删除
void SeeqListErase(SL* ps, int pos);

这里pos就是我们给定的位置。

2.查找数据

int SeqListFind(SL* ps, SLDataType x)
{
	int bigan = 0;
	for (bigan = 0; bigan < ps->size; bigan++)
	{
		if (ps->a[bigan] == x)
		{
			return bigan;
		}
	}
	return -1;
}

首先查找数据就不用多说了,直接一个for循环一个一个的遍历,当然这里的时间复杂度是O(N),如果小伙伴们对时间复杂度很敏感的话也是可以尝试一下用二分查找法的,二分查找法的时间复杂度是O(以2为底的N的对数)。

3.给定一个位置插入数据

void SeqListInsert(SL* ps, int pos, SLDataType x)
{
	//下标是从0开始的但是我们常识是从1开始的。
	assert(pos >= 0 && pos <= ps->size+1);
	//判断是否满了
	CheckSeqListCapacity(ps);
	//插入 
	int end=0;
	for (end = ps->size-1; end >= pos-1; end--)
	{
		ps->a[end + 1] = ps->a[end];
	}
	ps->a[pos - 1] = x;
	ps->size++;
}

上面要注意的地方就是我们的小标是从0开始的,但是如果我们要在日常生活中使用的话,我们正常人是把1当作开始的下标的,所以我们这里就是我们要注意的点。

还有一点就是我们的assert(pos >= 0 && pos <= ps->size+1);这里后面的 pos <= ps->size+1这里为什么是<=ps->size+1原因是如果我们要插入的数据是在size后面的那个的话我们也是可以插入的,他还是满足我们的顺序表的连续性的,但是其他的地方就不行了。

4.给定一个位置删除数据

void SeeqListErase(SL* ps, int pos)
{
	assert(pos <= ps->size && pos >= 0);
	int bigan = 0;
	for (bigan = pos-1; bigan < ps->size; bigan++)
	{
		ps->a[bigan-1] = ps->a[bigan];
	}
	ps->size--;
}

这里同样的考虑下标是从0开始的,我们的常识是从1开始的。

5.整体代码优化

我们可以知道我们目前实现的接口函数主要有:

  1. 尾插
  2. 打印
  3. 尾删
  4. 头插
  5. 头删
  6. 查找
  7. 给定位置插入
  8. 给定位置删除

在上面的接口函数里面我们每个函数里面都是单独的编写功能代码,但是如果我们仔细点就会发现上面的接口函数有些功能代码其实是重复累赘的,也就是说其实我们并不需要把每个接口函数的功能代码都写一遍,而是可以接口函数对接接口函数,这个时候我们的接口函数的功能就体现出来了。

我们可以来进行对比一些下:


//尾插
void SeqListPushBack(SL* ps, SLDataType x)
{
	SeqListCheckCapacity(ps);
	ps->a[ps->size] = x;;
	ps->size++;
} 

//头插
void SeqListPushFront(SL* ps, SLDataType x)
{
	//判断是否满了
	SeqListCheckCapacity(ps);

	int end = 0;
	for (end = ps->size - 1; end >= 0; end--)
	{
		ps->a[end+1] = ps->a[end];
	}
	ps->a[0] = x;
	ps->size++;
}


//给定一个位置插入
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
	//下标是从0开始的但是我们常识是从1开始的。
	assert(pos >= 0 && pos <= ps->size+1);
	//判断是否满了
	CheckSeqListCapacity(ps);
	//插入 
	int end=0;
	for (end = ps->size-1; end >= pos-1; end--)
	{
		ps->a[end + 1] = ps->a[end];
	}
	ps->a[pos - 1] = x;
	ps->size++;
}

你就会发现其实他们的主题部分都是一样的结构,其实都是给定一个位置插入的特殊位置插入。
我们的尾插就是我们给定一个位置插入接口函数的size的地方插入,而我们的头插就是给定一个位置插入接口函数的下标为0出的地方插入。

这个时候我们的头插和尾插都是可以用给定一个位置插入接口函数表示的。

改进:
1.尾插

//尾插
void SeqListPushBack(SL* ps)
{
	SeqListInsert(ps, ps->size,x);
}

尾插就是在size的地方插入x。
2.头插

void SeqListPushFront(SL* ps, SLDataType x)
{
	SeqListInsert(ps,0,x);
}

头插就是子在下标为0出的地方插入x。

后面我们的删除也是一样的我们的尾删和头删都是在给定一个位置删除接口函数的特殊地方删除的。
我们对比一下:

//尾删
void SeqListPopBack(SL* ps)
{
	assert(ps->size > 0);
	ps->size--;
}

//头删
void SeqListPopFront(SL* ps)
{
	assert(ps->size > 0);

	int bigan = 1;
	for (bigan = 1; bigan < ps->size; bigan++)
	{
		ps->a[bigan-1] = ps->a[bigan];
	}
	ps->size--;
}

//给定一个位置删除
void SeeqListErase(SL* ps, int pos)
{
	assert(pos <= ps->size && pos >= 0);
	int bigan = 0;
	for (bigan = pos-1; bigan < ps->size; bigan++)
	{
		ps->a[bigan-1] = ps->a[bigan];
	}
	ps->size--;
}

我们发现他们其实是通用的。
改进:
1.尾删

void SeeqListErase(SL* ps, int pos)
{
	SeeqListErase(ps, ps->size);//这里传ps->szie而不是ps->size是因为考虑到了下标从0开始但是我们常识是从1开始的。

}

2.头删

void SeqListPopFront(SL* ps)
{
	SeeqListErase(ps, 1);//这里传1也是和上面一样的。
}

好到这里我们的优化就到此为止了,这期出的有点赶如果哪里写的不好的或者哪里写错了,请大家帮我指出,我也会认真改进的。

你可能感兴趣的:(#,初始数据结构,数据结构,算法,java)