Vector相关函数及其实现

Vector的构造函数

我们选取其中最常用的来进行相关介绍与实现

 vector(const allocater_type& alloc=allocator_type());

最朴素的vector默认构造函数,形参是一个模板引用变量,可以是任何类型的变量,如int,char等内置类型,也可以是自定义类型,它给了一个缺省值allocator_type(),是一个无参的默认构造函数,我们可能以为只有自定义类型才有构造函数,但其实内置类型也有,所以此处放置内置类型变量也是可以的

具体使用

vector<int> va;//不传参
vector<int> va1(99);//传一个int类型的变量
vector<string> va2("hauci");//传一个string类型的变量

 vector(size_type n,const value_type&val)

一种可以植入n个有效数据,且值为val的构造函数,n为数据的有效个数,val为变量的值

具体使用

vector<int>va(10,90)//存储十个值为90的int类型数据

 代码实现

vector(size_t n, const T& val = T())
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

vector(int n, const T& val = T())
		{
			reserve(n);
			for (int i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

这两个都是vector的代码实现,区别在于第二个中n的数据类型为int,是为了迎合一些特殊情况而另外建立的重载构造函数。

template <class InputIterator>

vector(Inputlterator first,inputlterator last);

运用迭代器构造vector,就是用两个指针构造vector,因为Inputlterator是模板,我们可以用任意类型指针来构造vector,只要是指针就可以

 具体使用

vector<int>va(20,10);//先创建一个vector的变量
vector<int>vb(va.begin(),va.end());//用va的迭代器去创建vb

代码实现

template <class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

 vector(InputIterator first, InputIterator last)中的first和last的类型都是模板,它们的数据类型是任意的,但函数体中的代码是将这两个变量当做指针去使用的,所以传的数据类型也应该是变量,但也存在某些尴尬的情况

template <class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
vector(size_t n, const T& val = T())
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

 如vector<int>va(10,10);

我们的本意是创建一个存储了十个10的vector的变量va,但实际编译器遇到这个代码会将其与迭代器构造函数相匹配,因为10与10的数据类型都是int,而first和last的数据类型也是相同的,而下面的构造函数中,n与val的数据类型不同,故这个构造会进行迭代器构造,而不是用下面的构造函数构造,因为迭代器构造函数的适配度高于下面的构造函数

这时我们就需要在定义一个构造函数,并使其适配度高于构造器构造函数,故我们选择新的构造函数,n的数据类型为int,val的类型为之前的模板,因为n是int类型变量的缘故,与10的数据类型契合,且不是模板,故它的适配度高于迭代器构造函数

vector(int n, const T& val = T())
		{
			reserve(n);
			for (int i = 0; i < n; i++)
			{
				push_back(val);
			}
		}

Vertor的数据植入操作 

我们简单的介绍并实现其中两个

void push_back (const value_type& val);

向vector的尾部插入一个val变量,使用起来很简单,传一个符合当前vector存储数据类型的值即可.

代码实现

void push_back(const T& x)
		{
			if (_finish == _endofstorage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			
			*_finish = x;
			++_finish;
	
		}

iterator insert (const_iterator position, const value_type& val);

形参中,position为一个指针变量,代表要插入数据的位置;val是要插入的数据变量

insert是向指定位置插入一个变量val,它涉及数据的挪动和扩容,其中因为异地扩容与指针指向位置的改变的原因,实现起来会出现很多问题

void insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;
		}

 insert的时候,如果vector满了,会进行扩充容量的操作,实际操作中,不会原地扩容,一律进行的是异地扩容,也就是说,vector数据存储的空间不是原来的空间,而是另一处的空间,而迭代器position仍指向的是原本的空间,它原本的空间会在数据复制后本释放,也代表跌迭代器position成为了野指针,失去了作用。

但想继续实现insert的操作也是可以做到的,我们需要保存position与头部指针的差值,即

size_t len = pos - _start;

在异地扩容后,用新的头部指针加上这个差值,就是新的position的位置了

pos=_start+len;

在用这个新的指针进行插入操作,这样就解决了迭代器失效的问题。

 Vector的扩容

void reserve (size_type n);

reserve的作用是将vector的容量扩充到n的大小,但是否真的进行扩充操作,取决于n的大小

1. n>capacity():进行扩容操作,将capacity的大小扩充到n的大小,扩容是申请新的大小为n的空间,将原本存储空间中的值复制到新的空间中,是异地扩容

2. n<=capacity():不进行任何操作

代码实现

void reserve(size_t n)
		{
			if (n > capacity())
			{
				T* tmp = new T[n];
				size_t sz = size();

				if (_start)
				{

					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _start[i];
					}

					delete[] _start;
				}

				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			}
		}

void resize (size_type n,const T&val=T());

 resize的作用同resver一样,但它的操作具有强制性,提现在无论n的大小是否比capacity大还是小,都会进行相关操作

注意:resize会改变

1.n<capacity():将capaity的大小缩减到n,只保留前n个数据,将后面的所有数据都删除掉

2.n==capacity():相安无事

3.n>capacity():将capacity的大小扩充到n,并将多余的值赋值为val

代码实现

void resize(size_t n, const T& val = T())
		{
			if (n <= size())
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n);
				while (_finish < _start+n)
				{
					*_finish = val;
					++_finish;
				}
			}
		}

迭代器

迭代器是一种作用类似于指针的数据类型 ,表示为iterator

迭代器类型为指针,它可以模板化为所有数据类型的指针

 遍历vector的方法有三种,其中用到迭代器的方式有两种

vector<int>pa;//仅举例子,不做实际处理
//正常遍历
int j=0;
int n=pa.size();
for(j=0;j<n;j++)
{
  cout<<pa[j]<<endl;
}
//迭代器遍历
auto a = pa.begin();
while (a < pa.end())
{
	cout << *a << " ";
	a++;
}
cout << endl;
//范围for遍历
for (auto e : pa)
{
	cout << e << " ";
}
cout << endl;
return 0;

  范围for遍历是建立在有迭代器基础上的,有了迭代器才能使用范围for,范围for是一个功能及其强大且方便的遍历方式,在后续当中经常使用。

  由迭代器遍历可以看出,迭代器其实是一种作用类似于指针的变量,它存储的是地址,对它解引用,可以找到相应地址存储的值。 

 Vector的数据删除操作

vector常用的数据删除函数有:

pop_back();

erase(iterator position);

其中pop_back()是尾删,删除最后一个位置的数据,使用很简单,引用即可

erase(iterator position)是依靠迭代器,对指定位置进行删除的操作,其中涉及数据元素的挪移

erase(iterator first,iterator end);是靠迭代器设定指定的一个删除区间,删除这两个迭代器中间的数据。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
时间片轮转算法是一种常用的调度算法,其基本原理已经在前面的回答中进行了介绍。下面是一个简单的C++代码实现: ```C++ #include <iostream> #include <queue> #include <vector> using namespace std; // 进程结构体 struct Process { int id; // 进程ID int priority; // 进程优先级 int arrival_time; // 进程到达时间 int burst_time; // 进程需要执行的时间 int remaining_time; // 进程剩余执行时间 int turnaround_time; // 进程周转时间 int waiting_time; // 进程等待时间 int response_time; // 进程响应时间 int finish_time; // 进程完成时间 }; // 时间片轮转调度算法 void RR(vector<Process>& processes, int time_slice) { queue<Process> ready_queue; // 就绪队列 int n = processes.size(); int current_time = 0; // 当前时间 int completed = 0; // 已完成进程数 int index = 0; // 进程索引 // 将所有进程按照到达时间加入就绪队列 while (index < n && processes[index].arrival_time <= current_time) { ready_queue.push(processes[index]); index++; } // 时间片轮转调度 while (completed < n) { if (!ready_queue.empty()) { Process current_process = ready_queue.front(); ready_queue.pop(); // 更新响应时间 if (current_process.remaining_time == current_process.burst_time) { current_process.response_time = current_time - current_process.arrival_time; } // 执行时间片 int execution_time = min(time_slice, current_process.remaining_time); current_process.remaining_time -= execution_time; current_time += execution_time; // 将剩余执行时间不为0的进程加入就绪队列 while (index < n && processes[index].arrival_time <= current_time) { ready_queue.push(processes[index]); index++; } // 将已执行完毕的进程加入完成队列 if (current_process.remaining_time == 0) { current_process.finish_time = current_time; current_process.turnaround_time = current_process.finish_time - current_process.arrival_time; current_process.waiting_time = current_process.turnaround_time - current_process.burst_time; completed++; } else { ready_queue.push(current_process); } } else { current_time++; } } } int main() { // 示例进程列表 vector<Process> processes = { {1, 2, 0, 5}, {2, 1, 1, 3}, {3, 3, 2, 8}, {4, 4, 3, 6}, {5, 5, 4, 4} }; // 调用时间片轮转算法 RR(processes, 2); // 输出每个进程的周转时间和等待时间 cout << "Process ID\tTurnaround Time\tWaiting Time" << endl; for (const auto& process : processes) { cout << process.id << "\t\t" << process.turnaround_time << "\t\t" << process.waiting_time << endl; } return 0; } ``` 这段代码中,我们定义了一个进程结构体,并使用队列来模拟就绪队列。在 RR 函数中,我们按照进程的到达时间将所有进程加入就绪队列,然后进行时间片轮转调度,每次从队列头取出一个进程,执行一个时间片,并将剩余时间不为0的进程放回队列尾部。当一个进程的剩余时间为0时,将其加入完成队列,并更新其周转时间和等待时间。最后,我们输出每个进程的周转时间和等待时间。 请注意,这段代码只是一个简单的示例,实际上,时间片轮转算法的实现可能会更加复杂。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值