动态数组的实现及相关算法

一、数组

1.概念

特点:

内存是连续的

优点:

下标访问(随机访问)时间复杂度是O(1)

末尾位置增加删除元素时间复杂度是O(1)

访问元素前后相邻位置的元素非常方便

缺点:

非末尾位置增加删除元素需要进行大量的数据移动O(n)

搜索的时间复杂度 无序数组-线性搜索O(n)

有序数组-二分搜索O(logn)

数组扩容消耗比较大

2.动态数组实现

2.1、创建操作对象

template<class T>
class DARR
{
public:
	DARR(int sizeArr = 10); //构造函数
	void PushBack(T value); //末尾插入
	void PopBack();//末尾删除
	void Insert(int pos, T value); //按位置增加元素
	void erase(int pos); //按位置删除
	T find(T value); //元素查询
	void print(); //打印
	~DARR(); //析构
private:
	void expand(int size); //扩容
	T* pAddr; //存放数据的地址
	int size; //当前有多少个元素
	int capacity; //容纳的最大数
};

2.2、构造函数

DARR(int sizeArr = 10) :size(0), capacity(sizeArr) {
	this->pAddr = new T[sizeArr];
}

数组默认容量为10(后期不够用可以扩容),初始化列表初始数组的容纳数以及最大容纳数

2.3、数组扩容

void expand(int size) {
	T* p = new T[size];
	memcpy(p, this->pAddr, sizeof(T) * this->capacity);
	delete[] this->pAddr;
	this->pAddr = p;
	this->capacity = size;
}

创建一个可容纳size个数组元素的内存空间,将原来的数组通过memcpy函数拷贝到新创建的内存中,并且把老内存delete掉,将维护数组指针的pAddr指向新内存首地址,并且更新数组最大的容纳数

2.4、末尾插入元素

void PushBack(T value) { //末尾插入
	if (this->size == this->capacity) {
		this->expand(this->capacity+10);//扩容
	}
	this->pAddr[this->size] = value;
	this->size++;
}

首先要判断当前数组容纳的元素数量是否等于数组最大容纳数,如果条件满足,则将该数组扩容10个容量,之后将新增的这个元素放入到数组中,容量数加一

2.5、末尾删除

void PopBack() { //末尾删除
	if (this->size == 0) {
		return;
	}
	this->size--;
}

先判断该数组是不是空,若是则返回,否则数组容量数减一

2.6、按位置增加元素

void Insert(int pos, T value) { //按位置增加元素
	if (pos<0 || pos>this->size) {
		return;
	}
	if (this->size == this->capacity) {
		this->expand(this->capacity+10);//扩容
	}
	//移动元素
	for (int i = this->size - 1; i >= pos; i--) {
		this->pAddr[i + 1] = this->pAddr[i];
	}
	this->pAddr[pos] = value;
	this->size++;
}

先判断传入位置的有效性,若数组满了则扩容,之后将该位置往后的所有元素向后移动一个位置,

再将该位置赋上新添的元素,容纳数加一

2.7、按位置删除元素

void erase(int pos) { //按位置删除
	if (pos < 0 || pos >= this->size) {
		return;
	}
	for (int i = pos; i < this->size - 1; i++) {
		this->pAddr[i] = this->pAddr[i + 1];
	}
	this->size--;
}

也是一样,先判断传入位置的有效性,再将该位置往后的所有元素向前挪动一个位置,此时被删除的元素被后面的元素所覆盖掉了,容纳数减一

2.8、元素查询

int find(T value) { //元素查询
	for (int i = 0; i < this->size; i++) {
		if (this->pAddr[i] == value) {
			return i;
		}
	}
	return -1;
}

遍历数组,如果查询到了,返回下标索引,循环结束还没查询到,返回-1

2.9、打印数组

void print() { //打印
	for (int i = 0; i < this->size; i++) {
		cout << this->pAddr[i] << ' ';
	}
	cout << endl;
}

遍历数组,打印每个元素值

2.10、析构

~DARR() {
	delete[] this->pAddr;
	this->pAddr = nullptr;
}

回收维护数组的指针指向的首地址,并将该指针指向nullptr

2.11、测试

DARR<int> arr;
//往容器内注入数据
for (int i = 0; i < 11; i++) {
	arr.PushBack(i);
}
arr.print();

//测试:
//find
cout << arr.find(8) << endl;

//erase
arr.erase(0);
arr.print();

//PopBack
arr.PopBack();
arr.print();

//Insert
arr.Insert(4, 100);
arr.print();

经过测试,所有功能都能正常工作

2.12、完整代码

#include<iostream>
using namespace std;
/*
动态数组的搭建:
*/
template<class T>
class DARR
{
public:
	DARR(int sizeArr = 10) :size(0), capacity(sizeArr) {
		this->pAddr = new T[sizeArr];
	}
	//末尾插入
	void PushBack(T value) {
		if (this->size == this->capacity) {
			this->expand(this->capacity+1);//扩容
		}
		this->pAddr[this->size] = value;
		this->size++;
	}
	//末尾删除
	void PopBack() {
		if (this->size == 0) {
			return;
		}
		this->size--;
	}
	//按位置增加元素
	void Insert(int pos, T value) {
		if (pos<0 || pos>this->size) {
			return;
		}
		if (this->size == this->capacity) {
			this->expand(2 * this->capacity);//扩容两倍
		}
		//移动元素
		for (int i = this->size - 1; i >= pos; i--) {
			this->pAddr[i + 1] = this->pAddr[i];
		}
		this->pAddr[pos] = value;
		this->size++;
	}
	//按位置删除
	void erase(int pos) {
		if (pos < 0 || pos >= this->size) {
			return;
		}
		for (int i = pos; i < this->size - 1; i++) {
			this->pAddr[i] = this->pAddr[i + 1];
		}
		this->size--;
	}
	//元素查询
	int find(T value) {
		for (int i = 0; i < this->size; i++) {
			if (this->pAddr[i] == value) {
				return i;
			}
		}
		return -1;
	}
	//打印
	void print() {
		for (int i = 0; i < this->size; i++) {
			cout << this->pAddr[i] << ' ';
		}
		cout << endl;
	}
	~DARR() {
		delete[] this->pAddr;
		this->pAddr = nullptr;
	}
private:
	//扩容
	void expand(int size) {
		T* p = new T[size];
		memcpy(p, this->pAddr, sizeof(T) * this->capacity);
		delete[] this->pAddr;
		this->pAddr = p;
		this->capacity = size;
	}
	T* pAddr;//存放数据的地址
	int size;//当前有多少个元素
	int capacity;//容纳的最大数
};

int main() {
	DARR<int> arr;
	//往容器内注入数据
	for (int i = 0; i < 11; i++) {
		arr.PushBack(i);
	}
	arr.print();

	//测试:
	//find
	cout << arr.find(8) << endl;

	//erase
	arr.erase(0);
	arr.print();

	//PopBack
	arr.PopBack();
	arr.print();

	//Insert
	arr.Insert(4, 100);
	arr.print();

	system("pause");
	return 0;
}

3.相关算法

3.1奇偶数位置调整

问题描述:给定一个数组,将所有偶数放前面,奇数放后面

实现代码:

void AdjustArr(int arr[], int size) {
	int* p = arr;
	int* q = arr + size - 1;
	while (p < q) {
		while (p < q) {
			if (*p % 2 == 1) {
				break;
			}
			p++;
		}
		while (p < q) {
			if (*q % 2 == 0) {
				break;
			}
			q--;
		}
		if (p < q) {
			int temp = *p;
			*p = *q;
			*q = temp;
			p++;
			q--;
		}
	}
}

问题分析

创建两个指针,p指向首元素,q指向尾元素

int* p = arr;
int* q = arr + size - 1;

p从左往右找奇数,找到才退出循环

while (p < q) {
	if (*p % 2 == 1) {
		break;
	}
	p++;
}

q从右往左找偶数,找到才退出循环

while (p < q) {
	if (*q % 2 == 0) {
		break;
	}
	q--;
}

此时p是奇数,q是偶数,交换二则位置

if (p < q) {
	int temp = *p;
	*p = *q;
	*q = temp;
	p++;
	q--;
}

循环上述过程,直到p越过了q,循环结束,最终所有的偶数在前面,奇数在后面

3.2移除元素问题

问题描述:给定一个数组和一个值(value),你需要原地(使用O(1)的空间复杂度),移除值为value的元素,元素顺序可以改变,返回新数组的首地址

实现代码:

int* RemoveValue(int* arr, int arrSize, int value) {
	int p = 0;//找不是value的值
	int q = arrSize - 1;//找value值
	while (p < q) {
		while (p < q) {
			if (arr[p] != value) {
				break;
			}
			p++;
		}
		while (p < q) {
			if (arr[q] == value) {
				break;
			}
			q--;
		}
		if (p < q) {
			//p、q都找到后将符合value移除的放到前面
			arr[q] = arr[p];
			p++;
			q--;
		}
	}
	return arr + p;
}

问题分析

创建两个变量,p等于数组首索引值,q等于数组尾索引值

int p = 0;//找不是value的值
int q = arrSize - 1;//找value值

p从前往后找不是value的元素,q从后往前找值是value的元素

while (p < q) {
	if (arr[p] != value) {
		break;
	}
	p++;
}
while (p < q) {
	if (arr[q] == value) {
		break;
	}
	q--;
}

此时此刻,arr[p] != value,arr[q] == value,交换二则位置

if (p < q) {
	//p、q都找到后将符合value移除的放到前面
	arr[q] = arr[p];
	p++;
	q--;
}

循环以上过程,直到p越过了q,循环结束,最终所有值为value的元素在数组的最左边,p地址往后的元素里就没有值为value的元素了,返回该地址

测试:

int arr[] = { 1, 7, 6, 8, 6, 7, 4, 7, 11, 85, 23, 7, 5};
for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
	cout << arr[i]<<' ';
}
cout << endl;
int* arr2 = RemoveValue(arr, sizeof(arr) / sizeof(int), 7);
for (int i = 0; i < 9; i++) {
	cout << arr2[i] << ' ';
}
cout << endl;

经过测试,该功能符合题目要求

3.3元素逆序

问题描述:给定一个数组,将该数组里元素逆序

实现代码:

void Reverse(char str[], int size) {
	char* p = str;
	char* q = str + size - 1;
	while (p < q) {
		char temp = *p;
		*p = *q;
		*q = temp;
		p++;
		q--;
	}
}

问题分析

创建两个指针,p指向首地址,q指向数组尾元素地址,交换二者的值,之后,p向右移动一个元素位置,q向左移动一个元素位置,循环上述过程,直到p越过了q,循环结束,此时完成了逆序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值