C++ 随笔杂记

目录

  • STL
    • 二维vector
    • map
    • unordered_map
    • stack
    • queue
  • 结构体
    • 构造函数
    • 分配空间
  • 字符串
    • String 类
  • 链表
    • 反转链表
    • 合并两个有序链表
  • 二叉树
    • 中序遍历(递归+栈)
    • 层序遍历(队列)
  • 动态规划
    • 最长公共子序列
    • 最长回文串(非动态规划)
  • 排序
    • 快速排序
    • 冒泡排序
    • 归并排序
  • 查找
    • 二分查找

STL

  • 使用 auto 代替迭代器声明时,需要在编译时添加 -std=c++11,即 g++ main.cpp -o main -std=c++11。

二维vector

  • 定义方式。
vector<vector<int> > res(n, vector<int>(m)); // 固定数组长度为 m
vector<vector<int> > res(n);
for(int i=0; i<n; i++)
{
	res[i].reszie(i+1); 
	// 使用 resize 自适应改变数组长度
}
  • 赋值方式。
vector<vector<int> > res;
vector<int> temp;
temp.push_back(1);
temp.push_back(2);
res.push_back(temp);

for(int i=0; i<n; i++)
{
	for(int j=0; j<m; j++)
	{
		res[i][j]=i*j;
	}
}
  • 属性相关。
vector<vector<int> > res(n, vector<int>(m));
int n=res.size();
int m=res[i].size();
  • 常用操作
vector<int> v;
vector<int> v {1, 2 , 5};
vector<int> v(n); //n为长度
vector<int> v(n, val); //val为值
int arr[] = {1, 5, 7};
vector<int> v1(arr, arr+n); // 拷贝数组长度n
vector<int> v2(v.begin(), v.begin()+v.size()); //拷贝一个vector
v.push_back(x);//向数组尾部添加元素x
v.pop_back();//删除数组尾部元素
v.at(i);//返回索引i处的元素
v.begin();//返回数组起始元素迭代器
v.end();//返回数组末尾元素迭代器
v.size();//返回数组元素个数
v.resize(n);//重新设置数组大小
v.clear();//清空数组
v.empty();//判断数组是否为空

map

  • map底层是红黑树,一种非严格平衡二叉树。
map<int, int> m;
for(int i=0; i<n ;i++){
{
	m.insert(make_pair(i,1));
	// 插入的数据需要转换成键值对 pair 类型
}
for(auto index=m.begin(); index!=m.end(); index++)
{
	cout<< index->first << ": " << index->second <<endl;
	cout<< (*index).first << ": " << (*index).second <<endl;
}

unordered_map

  • unordered_map底层是哈希表,可以数组形式访问。
unordered_map<int, int> m;
for(int i=0; i<n ;i++){
{
	m[i]=1;
}
for(int index=0; index<=m.size(); index++)
{
	cout<< index << ": " << m[index] <<endl;
}

stack

  • 常用函数
stack<int> s;
s.top();//返回栈顶元素,但不删除
s.pop();//删除栈顶元素,但不返回
s.size();//返回栈中元素个数
s.empty();//判断栈是否为空
s.push(x);//将x压入栈中

queue

  • 常用函数
queue<int> q;
q.front();//返回第一个元素的引用
q.back();//返回最后一个元素的引用
q.pop();//删除第一个元素,但不返回
q.size();//返回队列中元素个数
q.empty();//判断队列是否为空
q.push(x);//在队列尾部添加元素x

结构体

构造函数

  • 默认构造函数,一般不可见。
struct ListNode{
	int val;
	struct ListNode *next;
	ListNoide(){};
};
  • 自定义构造函数,初始化变量。
struct ListNode{
	int val;
	struct ListNode *next;
	ListNoide(x): val(x), next(nullptr){};
};

分配空间

  • 使用new关键字。
ListNode *node1 = new ListNode();//默认构造
ListNode *node2 = new ListNode(1);//自定义构造

字符串

String 类

  • 构建方式
string s1; 				// 构造空的string类对象s1
string s2("giturtle"); 	// 用C格式字符串构造string类对象s2
string s3(10, 'a');	    // 用10个字符'a'构造string类对象s3
string s4(s2); 			// 拷贝构造s4
string s5(s3, 5); 		// 用s3中前5个字符构造string对象s5

链表

反转链表

  • 对链表进行反转,采用多指针逐步反转指针方向。
ListNode *ReverseList(ListNode *L)
{
	ListNode *pre = nullptr;
	ListNode *cur = L;
	ListNode *next= L->next;
	while(pre!=nullptr)
	{
		cur->next = pre;
		pre = cur;
		cur = next;
		if(next!=nullptr)
		{
			next = next->next;
		}			
	}
	return pre;
}

合并两个有序链表

  • 对2个有序链表进行合并。
ListNode *MergeLIst(ListNode *L1, ListNode *L2)
{
	ListNode *L= new ListNode(0);
	ListNode *h = L;
	//处理空链表
	if(l1==nullptr && l2==nullptr)
	{
		return l1;
	}
	else if(l1==nullptr)
	{
		return l2;
	}
	else if(l2==nullptr)
	{
		return l1;
	}
	
	while(L1!=nullptr && L2!=nullptr)
	{
		if(L1->val < L2->val)
		{
			L->next = L1;
			L1 = L1->next;
		}
		else
		{
			L->next = L2;
			L2 = L2->next;
		}
		L = L->next;
	}
	if(L1!=nullptr)
	{
		L->next = L1;
	}
	if(L2!=nullptr)
	{
		L->next = L2;
	}
	return h->next;
}

二叉树

中序遍历(递归+栈)

  • 二叉树的中序遍历是先左子树,再根节点,最后右子树。
void MidOrder(TreeNode *tree)
{
	if(tree!=nullptr)
	{
		MidOrder(tree->left);
		cout<<tree->val;
		MidOrder(tree->right);
	}
}
  • 使用栈实现非递归的中序遍历。
void MidOrder_stack(TreeNode *tree)
{
	stack<TreeNode*> s;
	vector<int> res;
	while(tree!=nullptr || !s.empty())
	{
		while(tree!=nullptr)
		{
			s.push(tree);
			tree = tree.left;
		}
		tree = s.top();
		s.pop();
		res.push_back(tree->val);
		tree = tree->right;
	}
	for(auto index = res.begin(); index!=res.end(); index++)
	{
		cout<<*index<<" ";
	}
}

层序遍历(队列)

  • 使用队列,按照层的顺序从左到右遍历二叉树。
void RowOrder(TreeNode *tree)
{
	queue<TreeNode*> q;
	vector<int> res;
	q.push(tree);
	while(!q.empty())
	{
		tree = q.front();
		q.pop();
		res.push_back(tree->val);
		if(tree->left!=nullptr)
		{
			q.push(tree->left);
		}
		if(tree->right!=nullptr)
		{
			q.push(tree->right);
		}
	}
	for(auto index = res.begin(); index!=res.end(); index++)
	{
		cout<<*index<<" ";
	}
}


动态规划

最长公共子序列

  • 对于字符串str1和str2,查找它们的最长公共子序列。如果遍历到的该位两个字符相等,则此时长度等于两个前一位长度+1,如果遍历到该位时两个字符不相等,则置为0.
void LongSubStr(string &str1, string &str2)
{
	int len1 = str1.size();
	int len2 = str2.size();
	// num[i][j]表示分别以i和j结尾str1和str2的最长公共子序列
	vector<vector<int> > num(len1, vector<int>(len2));
	//初始化num
	for(int i=0; i<len1; i++)
	{
		if(str1[i] == str2[0])
		{
			num[i][0] = 1;
		}
		else
		{
			num[i][0] = 0;
		}
	}
	for(int i=0; i<len2; i++)
	{
		if(str1[0] == str2[i])
		{
			num[0][i] = 1;
		}
		else
		{
			num[0][i] = 0;
		}
	}
	//迭代更新num
	for(int i=1; i<len1; i++)
	{
		for(int j=1; j<len2; j++)
		{
			if(str1[i] == str2[j])
			{
				num[i][j] = num[i-1][j-1] + 1;
			}
			else
			{
				num[i][j] = 0;
			}
		}
	}
	//查找最长公共子序列
	int index=0, n=0;
	for(int i=0; i<len1; i++)
	{
		for(int j=0; j<len2; j++)
		{
			if(n < num[i][j])
			{
				n = num[i][j];
				index = i;
			}
		}
	}
	//打印最长公共子序列
	for(int i=index-n+1; i<=index; i++)
	{
		cout<<str1[i];
	}
	
}

最长回文串(非动态规划)

  • 找到字符串str中的最长回文串。以每一个字符为中心,向两边扩散,区分奇偶。
void LongStr(string &str)
{
	int len = str.size();
	int res=0, res_1 = 1, res_2 = 2;
	for(int i=0; i<len; i++)
	{
		int l, r;
		//奇数情况,以i为中心
		for(l=i,r=i; l>=0 && r<len; l--, r++)
		{
			if(str[l]!=str[r])
			{
				break;
			}	
		}
		res_1 = r-l-1;
		//偶数情况,以i和i+1为中心
		for(l=i,r=i+1; l>=0 && r<len; l--, r++)
		{
			if(str[l]!=str[r])
			{
				break;
			}	
		}
		res_2 = r-l-1;
		res = max(res,max(res_1, res_2));
	}
}

排序

快速排序

  • 交换类,不稳定,时间复杂度O(nlogn),空间复杂度O(logn)的递归栈。
// 划分
int Part(vector<int> &data, int l, int r)
{
	int tmp = data[l]; 
	while(l<r)
	{
		while(l<r && tmp<data[r])
		{
			r--;
		}
		if(l<r)
		{
			data[l++] = data[r];
		}
		while(l<r && tmp>data[l])
		{
			l++
		}
		if(l<r)
		{
			data[r--] = data[l];
		}
	}
	data[l] = tmp;
	return l;
}
//迭代
void QuickSort(vector<int> &data, int l, int r)
{
	if(l<r)
	{
		int m = Part(data, l, r);
		QuickSort(data, l, m-1);
		QUickSort(data, m+1, r);
	}
}


冒泡排序

  • 交换类,稳定,时间复杂度O(n2),空间复杂度O(1)。
void BubbleSort(vector<int> &data, int n)
{
	for(int i=0; i<n-1; i++)
	{
		for(int j=i+1; j<n; j++)
		{
			if(data[i]>data[j])
			{
				int tmp = data[i];
				data[i] = data[j];
				data[j] = tmp;
			}
		}
	}
}

归并排序

  • 2路归并,稳定,时间复杂度O(nlogn),空间复杂度O(nlogn)的递归栈和过渡数组。
//合并
void Merge(vector<int> &data, int l, int m, int r)
{
	vector<int> tmp(data.begin(), data.begin() + data.size());
	int i, j, k;
	for(i=l, j=m+1, k=l; i<=m&&j<=r;)
	{
		if(tmp[i] < tmp[j])
		{
			data[k++] = tmp[i++];
		}
		else
		{
			data[k++] = tmp[j++];
		}
	}
	while(i<=m)
	{
		data[k++] = tmp[i++];
	}
	while(j<=r)
	{
		data[k++] = tmp[j++];
	}
}
//迭代
void MergeSort(vector<int> &data, int l, int r)
{
	if(l<r)
	{
		int m = (l+r)/2;
		MergeSort(data, l, m);
		MergeSort(data, m+1, r);
		Merge(data, l, m, r);
	}
}

查找

二分查找

  • 给定已经排序好的序列,查找指定数值的索引。
int BinarySearch(vector<int> &data, int val)
{
	int index = -1;
	int l = 0;
	int r = data.size();
	while(data.size())
	{
		index = (l+r)/2;
		if(data[index] == val)
		{
			break;
		}
		else if(data[index] < val)
		{
			l = index+1;
		}
		else
		{
			r = index-1;
		}
		if(l>r)
		{
			index = -1;
			break;
		}
	}
	return index;
}


你可能感兴趣的:(后端学习,c++,算法,数据结构)