排序算法+DFS+BFS

这里是引用 各类算法模板

不稳定:快选堆希
在这里插入图片描述

排序

冒泡排序

思路:
从小到大,依次选择相邻两数进行比较,前大后小,换位;一趟下列,最大的排在最后
时间复杂度O(n2)
空间复杂度O(1)

选择排序

每趟从待排序中找到最小值放在排好序末尾

for (int i = 0; i < n-1; i++) {
		int min = i;
		for (int j = i; j < n; j++) {
			if (arr[min] > arr[j]) {
				min = j;
			}
		}
		if (min != i) {
			swap(arr[i], arr[min]);
		}
	}

插入排序

在有序数列中插入元素
假设前面已排好序,i直接从1开始遍历到结束;i和0-i依次比较

int arr[10] = {9,2,3,0,9,4,7,5,4,2};
int n = sizeof(arr)/4;

for (int i = 1; i < n; i++) {
		for (int j = i; j > 0; j--) {
			if (arr[j] < arr[j-1]) {
				swap(arr[j], arr[j - 1]);
			}
		}
	}

这里是引用高级排序

希尔排序

插入排序改进;缩小增量法,分段插入

1.设置步长,按步长分组,步长 5 2 1;
5 即{9,4}{2,7}{3,5}{0,4}{9,2}
组内排序后{4,9}{2,7}{3,5}{0,4}{2,9}
2即{4,9,2,7,3}{5,0,4,2,9}
组内排序后{2,3,4,7,9}{0,2,4,5,9}
1

int arr[10] = {9,2,3,0,9,4,7,5,4,2};
int n = sizeof(arr)/4;

int main(){
	for(int gap  = n /2; gap > 0; gap = gap/2 ){//分组,步长依次为5,2,1
		for (int i = gap; i < n; i++) {//步长为5时,希望比较第15,取5;26,取6;假设arr[gap]=arr[5]=4 有序,
			for (int j = i; j > 0; j=j-gap) {//步长为5时,希望比较第15,取1;26,取2;
				if (arr[j] < arr[j-gap]) {
				swap(arr[j], arr[j - gap]);			
				}
			}
		
		}
	
	}

时间复杂度大概在O(n^1.3) 左右;比传统要快,但不稳定,比快排、堆排慢

快排

选择一个中心轴,小于它的放右边,大于它的放左边;重复以上三个步骤

int midIndex(int begin, int end);

int arr[] = {5,6,8,8,2,6,4,9,5,7};
int pivot;
int lenth = sizeof(arr)/4;
//int findprivot();

int findprivot(int begin, int end){
	pivot = arr[begin];
	while(begin < end){
		while(begin < end){

			if(arr[end] < pivot){
				arr[begin] = arr[end];
				begin++;
				break;
		
			}
			else end--;	
		}
		while(begin < end){
			if(arr[begin] > pivot){
				arr[end] = arr[begin];
				end--;
				break;		
			}
			else begin++;	
		}	
	}
	swap(arr[begin],pivot);
	return begin;//返回值是基轴
}

void sortquick(int begin, int end){

	if(end-begin<=1)return;
	int mid = findprivot(begin,end);
	sortquick(begin ,mid);
	sortquick(mid +1 , end);
	
}

优化

不稳定,平均复杂度O(nlogn),空间复杂度O(logn)
越有序,时间复杂度越大,所以优化方法之一是随机选取基轴

二分查找

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();
        int left = 0;
        int right = n; // 我们定义target在左闭右开的区间里,[left, right)  
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,因为是左闭右开的区间,nums[middle]一定不是我们的目标值,所以right = middle,在[left, middle)中继续寻找目标值
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在 [middle+1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值的情况,直接返回下标
            }
        }
        return right;
    }
};


二叉树定义

struct TreeNode{
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x): val(x),left(NULL),right(NULL){};

}

DFS深度优先算法(递归)

前序遍历

void pretraver(TreeNode *root, vector<int> & rs){
	if(root == nullptr)return;
	rs.push_back(root->val);
	pretraver(root->left);
	pretraver(root->right);
	
}

BFS广度优先遍历(队列)

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);//队列插入push
        vector<vector<int>> result;
        while (!que.empty()) {
            int size = que.size();
            vector<int> vec;
            // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();//队列的头front
                que.pop();
                vec.push_back(node->val);
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            result.push_back(vec);
        }
        return result;
    }
};

二叉树的深度

int countDeepth(TreeNode *node){
	if(node == nullptr)return 0;
	int left = countDeepth(node->left);
	int right = countDeepth(node->right);
	return 1+max(left,right);

}

二叉树的节点数

int countnodes(TreeNode *node){
	if(node == nullptr)return 0;
	int left = countnodes(node->left);
	int right = countnodes(node->right);
	return left+right;

}

二分查找

回溯算法

KMP

这里是引用 数据结构

数据结构

二叉搜索树

一个节点最多只允许两个子节点,任何节点的键值一定大于其左子树中的每个节点的键值,并小于其右子树中每个结点的键值。从左可以搜索到最小元素,从右可以搜索到最大元素。

二叉排序树BST

左节点的值比根节点小,右比根大

平衡二叉树AVL

每个节点的左右子树深度差不大于1

红黑树

是一个平衡二叉查找树,只不过在每个结点上增加了结点的颜色标志,它能确保没有一条路径会比其它路径长出两倍。主要用来存储有序的数据,如STL中的set,map,效率非常高。
1.每个节点为黑或红,根为黑,子为黑,子(null的地方),(2.5个黑)
2.红节子必黑, (红爸黑子)
3.一节点到所有子孙节点的路径上,黑个数相同(一样的黑
在这里插入图片描述

B树(多路查找)

每个节点至少两个子节点,每个节点上可以多个关键字,包含键和值

这里是引用

B+树

叶子节点互通,内部节点直含键,叶子节点包含全部信息

hashtable

多线程中哈希表保证线程安全,哈希表特别大,桶多的时候怎么加锁

通过哈希函数,将一组数据散列地存储在数组中,每个key 和它的存储位置都有个映射关系,除留取余法
为解决哈希冲突,存储方式一般为数组+链表或者数组加二叉树(红黑树)
哈希表扩容:当装填因子大于0.75时(元素个数/总长度),重新申请长度为原来数组两倍大小的新空间,将旧数据以rehash拷贝过来,

数组实现队列

这里是引用

实现功能
创建,销毁,增删,判空,判满,遍历显示

首first 尾end
1.判空
first == -1
2.判满两种
first = 0 和 end = size-1是满
已经出队,end = first-1
3.入队
三种情况
满则不入
end = size - 1 或 -1 时,再入一个,直接放arr[0],end = 0;
其他end++
4.出队
四种情况
空则不出
只有一个first = end时, 出完置为-1
first = size -1时,出完,将first置为0
其他first++

#define Size 5
template<typename T >
class Queue{
public:
	Queue(){
		first = end = -1;
	}
	//~Queue();
	

	bool isempty(){
		return first == -1;
		
	}

	bool isfull(){
		return (first == 0 && end == Size -1 || end == first -1);
	
	}

	//template<typename T>
	void addmember(T num){//处理数组,成员变量,或者函数传进来
		if(isfull()){cout<<"满了,不能加了"<<endl;}
		else{
			if(end == Size -1 || end==-1){
				arr[0] = num;
				end = 0;
				if(first == -1)first = 0;
				
			}
			else{
				arr[++end] = num;
				
			}
			cout<<"添加  "<<num<<endl;
		
		}
	}

	int deletemember(){
		if(isempty()){cout<<"空了,不能删了"<<endl;exit(0);}
		else{
			int d = arr[first];
			if(first == end){
				first = -1;
				end = -1;
			}
			else if(first ==Size -1){
				first = 0;
			}
			else{
				first++;
			}
			cout<<"删除  "<<d<<endl;
			return d;
		
		}
		
		
	}


private:
	T arr[Size];
	int first;
	int end;

};


void main(){
	//int arr[] = {1,5,6};
	Queue<int> q;
	q.addmember(1);
	q.addmember(2);
	q.addmember(3);
	q.addmember(4);
	q.addmember(5);
	q.deletemember();
	q.addmember(6);
	q.deletemember();
	q.deletemember();
	q.deletemember();
	q.deletemember();
	q.deletemember();
	q.deletemember();
	
	/*Queue<char> q;
	q.addmember('a');
	q.addmember('b');
	q.addmember('c');
	*/
	

	
}

常用的sort排序

bool cmp(int a, int b){
return a>b;

}

sort(s,s+3,cmp);

比如成绩排序

#include<algorithm>;
using namespace std;

struct student{
	int id;
	char name[10];
	float Y;
	float S;
	float E;
	float sum;


};
bool cmp(student a, student b){
	if(a.sum > b.sum)return true;
	else if(a.sum == b.sum){
		if(a.Y > b.Y)return true;
		else if(a.Y == b.Y){
			if(a.S > b.S)return true;
			else if(a.S == b.S){
				if(a.E > b.E)return true;
				else if(a.E == b.E){
					if(a.name < b.name)return true;
				
				}
			
			}
		}

	
	}
	
	return false;

}

int main(){
	int n = 3;
	student s[3];

	for(int i = 0; i< 3;i++){
		cin>>s[i].id>>s[i].name>>s[i].Y >>s[i].S>>s[i].E;
		s[i].sum = s[i].Y + s[i].S + s[i].E;
		cout<<s[i].sum<<endl;
	
	}
	sort(s,s+3,cmp);
	for(int i = 0; i< 3;i++){
		
		cout<<s[i].id<<" "<< s[i].name<<"  "<<s[i].sum <<endl;
	
	}

	return 0;
	

	
	

}

这里是引用

map自定义类型排序

map <key ,value>
当key为自定义类型 key 为 学生信息,id name ; value是成绩
头文件包含map
map 第三个模板参数指定了用来比较元素的函数对象的对象,使用仿函数需要在类外创建一个结构体或者类对象

1.使用仿函数实现,

#include<map>

class student{
public:
	int id;
	string name;
	

};
/*
operator ()仿函数,函数对象
*/
struct cmp{
	bool operator ()(student const &a, student const &b){ // operator ()为什么写这个 后面还必须有const,
		if(a.id == b.id){
			return a.name < b.name;
		
		}
		else return a.id < b.id;

	}
};


int main(){

	map<student,int,cmp> information;// map 第三个模板参数指定了用来比较元素的函数对象的对象

	student st1;
	st1.id = 1;
	st1.name = "abc";	
	
	information.insert(pair<student,int>(st1,100));

	student st2;
	st2.id = 1;
	st2.name = "aac";	
	
	information.insert(pair<student,int>(st2,102));

	student st3;
	st3.id = 2;
	st3.name = "abc";	
	
	information.insert(pair<student,int>(st3,103));

	//遍历
	map<student,int>::iterator it;
	for(it = information.begin(); it != information.end();it++){
		cout<<(*it).first.id << "  " <<(*it).first.name << "  "<< (*it).second <<endl; 
	
	}
	
	
	


}

补充仿函数

#include<string>
//函数调用运算符重载 仿函数 operator()
class print{
public:
	void operator()(string test){cout<<test;}
};
int main(){
	print p;
	p("sf");
	print()("lixdjif");// 类 + ()是 匿名对象,临时对象,使用完直接释放
	
}

2.类内重载<, 只能重载< ,改变顺序通过改变判断条件

#include<map>
class student{
public:
	int id;
	string name;

	bool operator< ( student const &a)const{
		if(this->id == a.id){
			return this->name < a.name;
		}
		else return this->id < a.id;
	
	}
};
int main(){
	map<student,int> information;// map 第三个模板参数指定了用来比较元素的函数对象的对象

	student st1;
	st1.id = 1;
	st1.name = "abc";	
	
	information.insert(pair<student,int>(st1,100));

	student st2;
	st2.id = 1;
	st2.name = "aac";	
	information.insert(pair<student,int>(st2,102));

	student st3;
	st3.id = 2;
	st3.name = "abc";	
	
	information.insert(pair<student,int>(st3,103));

	//遍历
	map<student,int>::iterator it;//map vector 是类模板
	for(it = information.begin(); it  != information.end();it++ ){
		cout<<it->first.id <<"  "<< it->first.name<< " "<<it->second<<endl;
	}
}
  1. 以上是两种方法对key排序,对value排序思路,将map中的数压入vector,对vector 使用sort,使用的时候为了保证key有序,写一下cmp

#include<map>
# include<algorithm>

class student{
public:
	int id;
	string name;
};
//map输入时,必定会比较key,若key是自定义,必须三参加判断条件对象
struct Cmp{
	bool operator ()(student const &a, student const &b){ // operator ()为什么写这个 后面还必须有const,
		if(a.id == b.id){
			return a.name < b.name;
		
		}
		else return a.id < b.id;

	}
};

/*
bool cmp(pair<student,int> &a,pair<student,int> &b){
	if(a.second == b.second){
		if(a.first.id = b.first.id){
			return a.first.name < b.first.name;
		}
		else return a.first.id < b.first.id;
	
	}
	else return a.second > b.second;
}
*/
//key 有序下,再对value排序
bool cmp(pair<student,int> &a,pair<student,int> &b){
	if(a.first.id == b.first.id){
		if(a.first.name == b.first.name){
			return a.second > b.second;
		}
		else return a.first.name < b.first.name;
	
	}
	else return a.first.id < b.first.id;
}


int main(){
	multimap<student,int,Cmp> information;// map 第三个模板参数指定了用来比较元素的函数对象的对象

	student st1;
	st1.id = 3;
	st1.name = "abc";	
	
	information.insert(pair<student,int>(st1,60));

	student st2;
	st2.id = 1;
	st2.name = "abc";	
	information.insert(pair<student,int>(st2,90));

	student st3;
	st3.id = 1;
	st3.name = "abc";	
	information.insert(pair<student,int>(st3,103));

	multimap<student,int>::iterator it;//map vector 是类模板
	for(it = information.begin(); it  != information.end();it++ ){
		cout<<it->first.id <<"  "<< it->first.name<< " "<<it->second<<endl;
	}
	//把map中数据压入vector
	vector<pair<student,int>> vec(information.begin(),information.end());
	sort(vec.begin(),vec.end(),cmp);

	int size=vec.size();
    for(int i=0;i<size;i++)
        cout<<vec[i].first.id<<" "<<vec[i].first.name<<" "<<vec[i].second<<endl;
	return 0;
}

在这里插入图片描述

key值可重复,用multimap ,在key有序上,对value排序用以上
如果不管key值,只排value 将cmp更改一下 return a.second > b.second;
ps key 若是内置类型,直接将map装入vector,sort重写cmp
key为自定义,多一个key排序的过程,可以用仿函数 或者 类内重载<,不然map无法插入

4.需要用到const的地方
补充

const 修饰
常量指针和指针常量
“左定值,右定向,const修饰不变量”

const参数传递和函数返回值

传进来的参数在函数体不能被修改;
扩大函数参数接收范围,如果不加,就只能接受非const的实参。

函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载
以避免在函数调用时对实参的一次拷贝,提高了效率

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值