自学C++ day06 string & list

string
#include <iostream> 
#include <string> 

#if 0
using std::string;
using std::cout;
using std::endl;

// string :
// 1.string 是表示字符串的字符串类
// 2.该类的接口于常规容器的接口基本相同,在添加了一些专门用来操作string的常规操作!
// 3.string 在底层实际是:basic_string 模板类的别名,typedef basic_string<char,char_traits,allocator> string;
// 4.不能错做多字节或变长字符的序列

// string 类的常用接口
// constructor 
// string() ; 构造空的string类对象
// string(const char* s) ; 用C-string来构造string类对象
// string(size_t n,char c); string类对象中包含 n个字符c
// string(const string& s); 拷贝构造函数

void TestString() {
	string s1;
	string s2("hello");
	string s3(s2);
}

// string 类对象容量操作
// size : 返回字符串有效字符长度
// length : 返回字符串有效字符长度
// capacity : 返回空间大小
// empty : 检测字符串是否未空串
// clear : 清空有效字符
// reserve : 重置空间大小
// resize : 将有效字符的个数改成n个,多出的空间用字符c填充

// size / clear / resize 
void TestString1() {
	string s("hello zdz !");
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;

	// 将s中的内容清空 
	s.clear();
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;

	// 将有效字符的个数增加到15个,多出来的位置用 'a'填充;
	s.resize(15, 'a');
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;

	// 将 s 中有效字符的个数增加到 20 个,多出的位置用缺省值 \0 进行填充
	s.resize(15);
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
	
	// 将s中有效字符的个数缩小到 5个
	s.resize(5);
	cout << s.size() << endl;
	cout << s.length() << endl;
	cout << s.capacity() << endl;
	cout << s << endl;
}

void TestString2() {
	string s;

	s.reserve(100);
	cout << s.size() << endl;
	cout << s.capacity() << endl;

	s.reserve(50);
	cout << s.size() << endl;
	cout << s.capacity() << endl;
}


void TestPushBack() {
	string s;
	size_t sz = s.capacity();
	cout << sz << endl;
	cout << "making s grow :" << endl;
	for (size_t i = 0; i < 100; i++) {
		s.push_back((i + '0'));
		if (sz != s.capacity()) {
			sz = s.capacity();
			cout << "capacity changed: " << sz << endl;
		}
	}
}

void TestPushBackReserve() {
	string s;
	s.reserve(100);
	size_t sz = s.capacity();
	cout << sz << endl;
	cout << "making s grow: \n";
	for (size_t i = 0; i < 100; i++) {
		s.push_back((i + '0'));
		if (sz != s.capacity()) {
			sz = s.capacity();
			cout << "capacity changed : " << sz << endl;
		}
	}
}

#if 0
int main() {
	//TestString1();
	//TestString2();
	//TestPushBack();
	//TestPushBackReserve();
	return 0;
}
#endif
 

// string 的迭代
// operator[] : 返回pos位置的字符 const string 类对象调用
// begin + end : begin : 获取一个字符的迭代器, + end 获取最后一个字符的下一个位置的迭代器
// rbegin + rend : 获取最后一个字符的迭代器,获取第一字符的迭代器

void TestString3() {
	string s1("zdz handsome");
	const string s2("zdz handsome");
	cout << s1 << " " << s2 << endl;
	cout << s1[0] << " " << s2[0] << endl;

	s1[0] = 'Z';
	cout << s1 << endl;
}

void TestString4() {
	string s("zdz handsome");
	for (size_t i = 0; i < s.size(); i++) {
		cout << s[i];
	}
	cout << endl;
	string::iterator it = s.begin();
	while (it != s.end()) {
		cout << *it;
		it++;
	}
	cout << endl;

	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend()) {
		cout << *rit;
		rit++;
	}
	cout << endl;

	for (auto c : s) {
		cout << c;
	}
	cout << endl;
}

#if 0
int main() {
	TestString3();
	TestString4();
	return 0;
}
#endif 

// string 类对象的修改操作 
// push_back : 追加字符c
// append : 在字符串后面追加一个字符串
// operator+= : 在字符串后面追加一个字符串
// c_str : 返回C格式字符串
// find + npos :从字符串pos位置开始向后找c,返回c在字符串中的位置
// rfind + pos :从字符串的pos位置开始向前找c,返回c在字符串中的位置
// substr : 在string从pos开始截取n个字符

void TestString5() {
	string str;
	str.push_back(' ');
	str.append("hello");
	str += 'a';
	str += "ab";

	cout << str << endl;
	cout << str.c_str() << endl;

	string file1("string.cc");
	size_t pos = file1.rfind('.');
	string suffix(file1.substr(pos, file1.size() - pos));
	cout << suffix << endl;

	// npos 是string中的一个静态成员变量
	// static const size_t npos = -1;
	string url("http://zdz-it.top/learnJava/zdz/niub/");
	cout << url << endl;
	
	size_t start = url.find("://");
	if (start == string::npos) {
		cout << "invalid url" << endl;
		return;
	}
	start += 3;
	size_t finish = url.find('/', start);
	string address = url.substr(start, finish - start);
	cout << address << endl;

	// 删除url前缀协议
	pos = url.find("://");
	url.erase(0, pos + 3);
	cout << url << endl;
}

#if 0
int main() {
	TestString5();
	return 0;
}
#endif 

// string 类非成员函数 
// operator+ 拼接运算
// operator>> 输入运算符重载
// operator<< 输出运算符重载
// getline 以\n作为结尾读入
// relational operators 大小比较



// 深浅拷贝 

// 1. 浅拷贝: 也称位拷贝,编译器只是将对象中的值拷贝过来,如果对象中管理资源,最后就会导致多个对象
// 共享同一份资源,当前一个对象的资源被销毁时,就会将该资源释放掉,而此时另一个对象不知道该资源已经被释放
// 认为该资源还有效,就会发生异常访问!

// 2. 深拷贝,如果一个类中设计到资源的管理,其拷贝构造函数、赋值运算重载以及修稿函数必须显示个给出!

// 写时拷贝,是在浅拷贝基础之上增加引用计数的方式来实现的
// 引用计数: 用来记录资源使用者个数. 在构造时,将资源的计数赋值1,每增加一个对象使用该资源就++,销毁时--;


// string 类的模拟实现
#if 0
namespace pz {
	class string {
	public:typedef char* iterator;
	public:
		string(const char* str = "") {
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		
		string(const string& s):_str(nullptr),_size(0),_capacity(0) {
			string tmp(s._str);
			this->swap(tmp);
		}

		string& operator=(string s) {
			this->swap(s);
			return *this;
		}

		~string() {
			if (_str) {
				delete[] _str;
				_str = nullptr;
			}
		}

		iterator begin() { return _str; }
		iterator end() { return _str + _size; }

		void push_back(char c) {
			if (_size == _capacity) {
				Reserve(_capacity * 2);
			}
			_str[_size++] = c;
			_str[_size] = 0;
		}

		string& operator+= (char c) {
			push_back(c);
			return *this;
		}

		void clear() {
			_size = 0;
			_str[_size] = 0;
		}

		void swap(string& s) {
			swap(_str, &s._str);
			swap(_size, &s._size);
			swap(_capacity, &s._capacity);
		}

		const char* c_str() const {
			return _str;
		}

		void resize(size_t newSize, char c = 0) {
			if (newSize > _size) {
				if (newSize > _capacity) {
					reserve(newSize);
				}
				memset(_str + _size, c, newSize - _size);
			}
			_size = newSize;
			_str[newSize] = 0;
		}

		void reserve(size_t newCapacity) {
			if (newCapacity > _capacity) {
				char* str = new char[newCapacity + 1];
				strcpy(str, _str);
				delete[] _str;
				_str = str;
				_capacity = newCapacity;
			}
		}


	private:
		size_t _size;
		size_t _capacity;
		char* _str;
	};
}
#endif 
#endif 
lsit
#include <iostream> 
#include <list>
#include <vector>
using std::cout;
using std::endl;

// list : 类似于java中的LinkedList ,底层是双向链表
// list 于forward_list 非常相似,最主要的不同在于 forward_list 是单链表只能朝前迭代

// list 的使用
// constructor 
// list() : 构造空的list
// list(size_t n,const value_type& val = value_type()) : 构造list包含n个值位val的元素
// list(const list& x) : 拷贝构造函数
// list(InputIterator first,InputIterator last) 用[first,last) 区间中的元素构造list

#if 0
int main() {
	std::list<int> l1;
	std::list<int> l2(4, 100);
	std::list<int> l3(l2.begin(), l2.end()); 
	std::list<int> l4(l3);

	// 以数组为迭代器区间构造
	int arr[] = { 16,2,77,19 };
	std::list<int> l5(arr, arr + sizeof(arr) / sizeof(int));

	// 用迭代器方式打印l5中的元素
	for (std::list<int>::iterator it = l5.begin(); it != l5.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	// 范围for 
	for (auto& e : l5) {
		cout << e << " ";
	}
	return 0;
}
#endif 

// list 中的迭代器:
// 与STL其他的一样不过多介绍!

void print_list(const std::list<int>& list) {
	for (std::list<int>::const_iterator it = list.begin(); it != list.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

#if 0
int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	std::list<int> list(arr, arr + sizeof(arr) / sizeof(arr[0]));
	for (std::list<int>::iterator it = list.begin(); it != list.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
	// 反向迭代器
	for (std::list<int>::reverse_iterator it = list.rbegin(); it != list.rend(); it++) {
		cout << *it << " ";
	}
	cout << endl;
	return 0;
}
#endif 

// list capacity:
// empty : 检测list 是否为空
// size: 返回list 中有效节点的个数

// list element access 
// front : 返回list的第一个节点中值的引用
// back : 返回list的最后一个节点中值的引用

// list modifiles 
// push_front  : 在list首元素前面插入值为val的元素
// pop_front  : 删除list中第一个元素
// push_back  : 在list的尾部插入值为 val的元素
// pop_back   : 删除list中最后1一个元素
// insert     : 在list position 位置中插入val
// erase      : 删除lsit position 位置元素
// swap   : 交换两个list中的元素
// clear   : 清空list 中的有效元素

// push_back / pop_back / push_front / pop_front 
void TestList1() {
	int arr[] = { 1,2,3,4 };
	std::list<int> list(arr, arr + sizeof(arr) / sizeof(arr[0]));

	list.push_back(5);
	list.push_front(0);
	print_list(list);

	list.pop_back();
	list.pop_front();
	print_list(list);
}

// insert / erase 
void TestList2() {
	int arr[] = { 1,2,3,4 };
	std::list<int> list(arr, arr + sizeof(arr) / sizeof(arr[0]));

	// 获取链表中第2个节点
	auto pos = ++list.begin();
	cout << *pos << endl;

	// 在 pos前插入值为4的元素
	list.insert(pos, 4);
	print_list(list);

	// 在pos前插入5个值为22的元素
	list.insert(pos, 5, 22);

	// 在 pos 前插入 [v.begin(),v.end())区间中的元素
	std::vector<int> v{ 8,3,5,7,9 };
	list.insert(pos, v.begin(), v.end());
	print_list(list);

	// 删除pos位置上的元素
	list.erase(pos);
	print_list(list);

	// 删除list中[begin,end) 区间中的元素,即是删除lisy中的所有元素
	list.erase(list.begin(), list.end());
	print_list(list);
}

void TestList3() {
	int arr[] = { 1,2,3,4 };
	std::list<int> l1(arr, arr + sizeof(arr) / sizeof(arr[0]));
	std::list<int> l2;
	print_list(l1);

	l2.swap(l1);
	print_list(l1);
	print_list(l2);

	l2.clear();
	cout << l2.size() << endl;

}

#if 0
int main() {
	TestList1();
	TestList2();
	TestList3();
	return 0;
}
#endif 

// list 迭代器失效:
// 迭代器失效即迭代器所指向的节点是无效的,即该节点被删除了. 因为list的底层结构为带头节点的双向循环链表,因此在list中进行插入
// 时时不会倒是list迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响!

void TestListIterator1() {
	int arr[] = { 1,2,3,4 };
	std::list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));

	auto it = l.begin();
	while (it != l.end()) {
		//l.erase(it);// erase 函数执行后,it所指向的节点已经被删除,因此it失效,在下一次使用it时,必须先给其赋值
		++it;
	}
}

void TestListIterator2() {
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	std::list<int> l(arr, arr + sizeof(arr) / sizeof(arr[0]));
	auto it = l.begin();
	while (it != l.end()) {
		l.erase(it++);
	}
}

#if 0
int main() {
	TestListIterator1(); // 失效版本
	TestListIterator2(); // 修正版本
	return 0;
}
#endif 

// 模拟实现list
#if 0
namespace pz {
	template<class T>
	struct ListNode {
		ListNode(const T& val = T()) :_pPre(nullptr),_pNext(nullptr),_val(val){}
		ListNode<T>* _pPre;
		ListNode<T>* _pNext;
		T _val;
	};

	/*
		list 的迭代器:
		迭代器有两种实现方式,具体应根据容器底层数据解构实现:
		 1. 原生态指针,例如 vector ,string;
		 2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现一下方法:
			1.指针可以解引用,迭代器的类中必须重载 operator* ();
			2.指针可以通过 -> 访问其所指空间成员,迭代器中必须重载operator->();
			3. 指针可以进行左右移动 ++,-- 操作,要重载operator++(),operator--();
			4. 迭代器需要进行是否相等的比较,因此还需要重载 operator==(),opeartor!=()
	*/
	
	template<class T,class Ref,class Ptr>
	class ListIterator {
		typedef ListNode<T>* PNode;
		typedef ListIterator<T, Ref, Ptr> Self;
	public:
		ListIterator(PNode pNode = nullptr) :_pNode(pNode){}

		ListIterator(const Self& l):_pNode(l._pNode){}

		T& operator*() { return _pNode->_val; }
		T* operator->() { return &(operator*()); }

		Self& operator++() {
			_pNode = _pNode->_pNext;
			return *this;
		}
		// 前置“++”不接受任何参数,而后置“++”接受一个int类型的参数,尽管没什么实际用途,
		// 但是却为编译器确定重载对象提供了帮助
		Self& operator++(int) {
			Self tmp(*this);
			_pNode = _pNode->_pNext;
			return tmp;
		}

		Self& operator--();
		Self& operator--(int);

		bool operator!=(const Self& l) { return _pNode != l._pNode; }
		bool operator==(const Self& l) { return _pNode == l._pNode; }
		
		PNode _pNode;
	};

	template<class T>
	class list {
		typedef ListNode<T> Node;
		typedef Node* PNode;
	public:
		typedef ListItreator<T, T&, T*> iterator;
		typeder ListIterator<T, const T&, const T&> const_iterator;

	public:
		list() {
			CreateHead();
		}
		list(int n,const T& value = T()) {
			CreateHead();
			for (int i = 0; i < n; i++) {
				push_back(value);
			}
		}

		template<class Iterator>
		list(Iterator first, Iterator last) {
			CreateHead();
			while (first != last) {
				push_back(*first);
				++first;
			}
		}

		list(const list<T>& l) {
			CreateHead();
			list<T> tmp(l.begin(), l.end());
			this->swap(tmp);
		}

		list<T>& operator=(const list<T> l) {
			this->swap(l);
			return *this;
		}

		~list() {
			clear();
			delete _pHead;
			_pHead = nullptr;
		}

		iterator begin() { return iterator(_pHead->pNext); }
		iterator end() { return iterator(_pHead); }
		const_iterator begin() { return const_iterator(_pHead->_pNext); }
		const_iterator end() { return const_iterator(_pHead); }

		size_t size()const;
		bool empty() const;

		T& front();
		const T& front() const;
		T& back();
		const T& back() const;

		void push_back(const T& val) { insert(begin(), val); }
		void pop_back() { erase(--end()); }
		void push_front(const T& val) { insert(begin(), val); }
		void pop_front() { erase(begin()); }

		iterator insert(iterator pos, const T& val) {
			PNode pNewNode = new Node(val);
			PNode pCur = pos._pNode;

			pNewNode->_pPre = pCur->_pPre;
			pNewNode->_pNext = pCur;
			pNewNode->_pPre->_pNext = pNewNode;
			pCur->_pPre = pNewNode;
			return iterator(pNewNode);
		}

		iterator erase(iterator pos) {
			PNode pDel = pos._pNode;
			PNode pRet = pDel->_pNext;

			pDel->_pPre->_pNext = pDel->_pNext;
			pDel->_pNext->_pPre = pDel->_pPre;
			delete pDel;
			return iterator(pRet);
		}
		void clear();
		void swap(List<T>& l);
	private:
		void CreateHead() {
			_pHead = new Node;
			_pHead->_pPre = _pHead;
			_pHead->_pNext = _pHead;
		}
	private:
		PNode _pHead;
	};

}
#endif 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值