顺序表&算法 Implemented with C++

Sequence List 顺序表

也就是线性表的顺序存储,即用一组地址连续的存储单元一次存储线性表中的数据元素,从而使得逻辑上相邻的元素在物理位置上也是相邻的,有两种空间分配方式:

  • 静态分配(静态数组)
  • 动态分配(用户分配空间,可以在运行时决定空间分配的大小,这同样也是顺序存储结构

根据顺序表中元素的特点可以分为:

  • 无序顺序表:顺序表中的元素是没有顺序的
  • 有序顺序表:顺序表中的元素是有序的(升序或者是降序)

通常一个线性表是这样的:

class List{
private:
	ElementType data[MAXSIZE];
	int length;
public:
	bool insert(int pos, ElementType e);
	bool delet(int pos);
	bool locate(ElementType e);
}

Basic Operation 基本操作

Insert 插入

将元素插入到0length - 1 (也可以是1length,说明清楚,保持一致即可)的位置 i ,我们需要先将包括插入位置的元素在内的后面的所有元素后移一位,平均移动次数为 n / 2 n/2 n/2(考虑最坏的情况和最好的情况,相加除以二即可得到),函数实现:

bool insert(int pos, ElementType e){
	if(pos > this->length || pos < 0){
		return false;
	}
	if(this->length >= MAXSIZE){
		return false;
	}
	for(int j = this->length - 1;j >= pos;j--){
		this->data[j + 1] = this->data[j]
	}
	this->data[pos] = e;
	this->length++;
	return true;
}
Delete 删除

删除所给位置 i 的元素,删除之后,我们需要将删除元素后面的 length - 1 - i 个元素全部前移一位,平均移动次数为 ( n − 1 ) / 2 (n-1)/2 (n1)/2。(同理)

bool delet(int pos){
	if(pos > this->length - 1 || pos < 0){
		return false;
	}
	if(this->length == 0){
		return false;
	}
	for(int j = pos;j < this->length;j++){
		this->data[j] = this->data[j + 1];
	}
	this->length--;
	return true;
}
Locate 查找

查找某个特定值的元素在顺序表中的位置,返回其位置索引(index),平均访问次数为 ( n + 1 ) / 2 (n+1)/2 (n+1)/2。(同理)

int locate(ElementType e){
	if(this->length == 0){
		return -1;
	}
	for(int i = 0;i < this->length;i++){
		if(this->data[i] == e){
			return i;
		}
	}
	return -1;
}

一些算法问题

Reverse 逆置

交换第i个元素和length - 1 - i 个元素:

void reverse(){
	for(int i = 0;i < this->length / 2;i++{
		int temp = this->data[i];
		this->data[i] = this->data[length - 1 - i];
		this->data[length - 1 - i] = temp;
	}
	return;
}
Merge 合并有序顺序表

合并两个有序的顺序表,只需要遍历到其中一个顺序表末尾即可,复杂度为 O ( N ) = O ( m a x { m , n } ) O(N)=O(max\{m,n\}) O(N)=O(max{m,n}),假定序列都是升序序列:

List merge(List l1, List l2){
	List l3;
	int i = 0, j = 0, k = 0;
	while(i < l1.length && j < l2.length){
		if(l1.data[i] > l2.data[j]){
			l3.data[k] = l2.data[j];
			j++;
		}
		else{
			l3.data[k] = l1.data[i];
			i++;
		}
		k++;
	}
	// either
	while(i < l1.length){
		l3.data[k++] = l1.data[i++];
	}
	// or
	while(j < l2.length){
		l3.data[k++] = l1.data[j++];
	}
	l3.length = k;
	return l3;
}
Delete by value 按值删除
删除给定值的所有元素

如果是一个有序顺序表,那么给定值的所有元素是在相邻的位置上的,我们只需要统计该位置的元素的个数 k,然后后面的元素前移 k 位即可:

void deleteByValue(ElementType value){
	int start = 0, end = 0;
	for(int i = 0;i < this->length;i++){
		if(this->data[i] == value]){
			start = i;
			break;
		}
	}
	for(int i = start;i < this->length;i++){
		if(this->data[i] != value){
			end = i - 1;
		}
	}
	int k = end - start;
	if(k <= 0){
		return;
	}
	for(int i = end + 1;i < this->length;i++){
		this->data[i - k] = this->data[i];
	}
	return;
}

如果不是一个有序顺序表,可以有两种方法:

  • 找出每一个值不为 value 的元素,保留
  • 记录每一个值为 value 的元素的个数 k,其他元素前移 k
void deleteByValue1(ElementType value){
	// count element whose value not equal to given value
	int k = 0;
	for(int i = 0;i < this->length;i++){
		if(this->data[i] != value){
			this->data[k] = this->data[i];
			k++;
		}
	}
}
void deleteByValue2(ElementType value){
	// count element with given value
	int k = 0;
	for(int i = 0;i < this->length;i++){
		if(this->data[i] == value){
			k++;
		}
		else{
			this->data[i - k] = this->data[i];
		}
	}
	return;
}
删除给定值范围内的所有元素

同理,如果是一个顺序表那么给定范围的元素是连续的,我们依然只需要统计给定范围内元素的个数,然后将后续的元素前移相应的步长即可,只需要修改一下判断条件:

void deleteByValue(ElementType floor, ElementType ceiling){
	int start = 0, end = 0;
	for(int i = 0;i < this->length;i++){
		if(this->data[i] >= floor]){
			start = i;
			break;
		}
	}
	for(int i = start;i < this->length;i++){
		if(this->data[i] >= ceiling){
			end = i - 1;
		}
	}
	int k = end - start;
	if(k <= 0){
		return;
	}
	for(int i = end + 1;i < this->length;i++){
		this->data[i - k] = this->data[i];
	}
	return;
}

同样如果是有序顺序表,则同样只需要修改一下判断条件即可:

void deleteByValue1(ElementType floor, ElementType ceiling){
	// count element whose value not equal to given value
	int k = 0;
	for(int i = 0;i < this->length;i++){
		if(this->data[i] < floor || this->data[i] > ceiling){
			this->data[k] = this->data[i];
			k++;
		}
	}
}
void deleteByValue2(ElementType floor, ElementType ceiling){
	// count element with given value
	int k = 0;
	for(int i = 0;i < this->length;i++){
		if(this->data[i] >= floor && this->data[i] <= ceiling){
			k++;
		}
		else{
			this->data[i - k] = this->data[i];
		}
	}
	return;
}
duplicate removal 去重

如果是一个有序顺序表的话,那么重复的元素将是连续的,那么我们只需要判断下一个元素是否跟前一个元素的值相同,是的话,就增加计数,不是的话就前移相应的步长即可:

void removeDuplicate(){
	if(this->length <= 1){
		return;
	}
	int k = 0;
	for(int i = 1;i < this->length;i++){
		if(this->data[i] == this->data[i - 1]){
			k++;
		}
		else{
			this->data[i - k] = this->data[i];
		}
	}
	return;
}

如果是一个无序的顺序表,要在时间上尽可能高效的话,我们可以考虑用空间换取时间的方法,也就是用一个散列表记录每一个元素对应的值是否出现过,则增加计数,否则前移相应的步长,可以去了解散列表的用法,实现不难。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值