选修课程复习(ICPC)

选修课重难点

(个人观点)

1.快排(递归思想)

void quickSort(int *array, int left, int right)
{
    
    
	if(left < right)
	{
    
    
		int pivot = array[left];
		int low = left, high = right;
		while(low < high)
		{
    
    
			while(array[high] >= pivot && low < high)
				high--;
			array[low] = array[high];
			
			while(array[low] <= pivot && low < high)
				low++;
			array[high] = array[low];
		}
		array[low] = pivot;
		
		quickSort(array, left, low - 1);
		quickSort(array, low + 1, right);
	}
}

2.栈

主要操作:
主要操作
栈的基本题型:(进制转换)——利用倒序输出的性质

#include<iostream>
#include<stack>

using namespace std;

long long n;
stack<int> s;

void read(long long n);
void output();

int main()
{
    
    
    cin >> n;
    read(n);
    output();

}

void read(long long n)
{
    
    
    long  div, mod;
    if(n >= 8)
        {
    
    
            mod = n % 8;	//求出八进制的当前位是多少
            div = n / 8;     //先除以八
            s.push(mod);     
            /*重点:将最后一位先输入栈中,一位最后一位最后输出*/
            read(div);		//计算八进制的下一位
        }
    else{
    
    
        s.push(n);
        return;
    }
   
}

void output(){
    
    
    while(!s.empty()){
    
    
        cout << s.top();
        s.pop();
    }
    putchar('\n');
}

3.穷竭搜索

深度优先搜索(递归思想)

:很粗略的讲就是,多次用一个方式一直搜索到不能用这个方法搜索,然后退一步再用另一个方式找到底,找不到就再退一步,重复这个步骤直到找到要找的值

例:(部分和问题)

void dfs(int x, int y)
{
    
    
    field[x][y] = '.';	//将此点替换成'.',表示搜索过
    for (int dx = -1; dx <= 1; dx++) 	//x循环遍历移动的8个方向
        for (int dy = -1; dy <= 1; dy++)
        {
    
    
            int nx = x + dx ,ny = y + dy;	// x,y 移动dx,dy 后成为(nx,ny)
            if(0 <= nx && nx < N && 0 <= ny && ny < M && field[nx][ny] == 'W') 	//判断这个点是否在院子里,以及是否有其它积水
                dfs(nx, ny);	//如果是积水,就将它变成'.'
        }
}

全解链接:https://blog.csdn.net/m0_46182401/article/details/105545389

Dfs典型例题 链接:https://blog.csdn.net/MaxLykoS/article/details/73555329

广度优先搜索(队列的应用)
粗略地讲,按照开始状态——>只需1次转移就可以到达所有状态——>只需2次转业就可以达到所有状态……按此顺序进行搜索。

例:白骑士的移动

void bfs()
{
    
    
    queue<P> que;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++)
			d[i][j] = INF;
   que.push(P(sx, sy));  //输入起点
	d[sx][sy] = 0;	  

    while (que.size())  
	{
    
    
		P p = que.front(); que.pop();
		int i;
		for (i = 0; i < 8; i++)		
		{
    
    
			int nx = p.first + dx[i];
			int ny = p.second + dy[i];
			if (0 <= nx&&nx < N
				&& 0 <= ny&&ny < M
				&& MAP[nx][ny] != 'x'
                && MAP[nx][ny] != 'B'
                && MAP[nx][ny] != 'R'
				&& d[nx][ny] == INF)
			{
    
    
				que.push(P(nx, ny));
				d[nx][ny] = d[p.first][p.second] + 1; 
				if(nx==ex && ny==ey) break; 
 
            }
		}
		if(i!=8) break;
	}
 
}

全解链接:
https://blog.csdn.net/m0_46182401/article/details/105716791

4.队列&&优先队列

队列:
(1)队列中的数据元素遵循“先进先出”(First In First Out)的原则,简称FIFO结构;
(2)在队尾添加元素,在队头删除元素。
a、栈空: 队首标志=队尾标志时,表示栈空。
b、栈满 : 队尾+1 = 队首时,表示栈满。

q.empty()               如果队列为空返回true,否则返回false
q.size()                返回队列中元素的个数
q.pop()                 删除队列首元素但不返回其值
q.front()               返回队首元素的值,但不删除该元素
q.push()                在队尾压入新元素
q.back()                返回队列尾元素的值,但不删除该元素

priority_queue
是“优先队列”。它和普通队列的区别在于,优先队列的队头元素总是最大的——即执行 pop 操作时,删除的总是最大的元素;执行 top 操作时,返回的是最大元素的引用。
注:优先队列没有back()操作!!!!!
可高效完成这些操作:
(1)查找最大值(或最小值),O(1)
(2)插入一个新值,或者删除最大值(最小值),时间复杂度为O(log2n)

priority_queue<int,vector<int>,greater<int> >l;  //<整型数据,顺序存储,小根堆>

5.贪心算法

贪心算法顾名思义就是用计算机来模拟一个“贪心”的人做出决策的过程。
这个人每一步行动总是按某种指标选取最优的操作,他总是 只看眼前,并不考虑以后可能造成的影响 。

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
int main(){
    
    
    priority_queue<int,vector<int>,greater<int> >l;
    int n,a;
    cin>>n;
    for (int i=0;i<n;i++){
    
    
        cin>>a;
        l.push(a);
    }
    int sum=0;
    while(l.size()!=1){
    
    
        int x=l.top();
        l.pop();
        int y=l.top();
        l.pop();
        sum+=x+y;
        l.push(x+y);
    }
    printf("%d\n",sum);
    return 0;
}

6.存储并操作数据的数据结构

线性表:

静态查找;由于表采用折半查找

树表:

动态查找;查找后做插入删除操作;采用平衡二叉树、堆(查最小最大值效率比较高)等

散列表:

静动均可;主要采用散列技术

7. 二叉搜索树BST

二又搜索树(binary search tree)或者是一棵空树,或者是具有下列性质的二又树:
  (1)每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。
  (2)左子树(如果存在)上所有结点的关键码都小于根结点的关键码。
  (3)右子树(如果存在)上所有结点的关键码都大于根结点的关键码。
  (4)左子树和右子树也是二又搜索树。
中序遍历二叉排序树可以得到一个按关键码有序的序列
平衡二叉搜索树AVL
-或者是一棵空的二叉排序树,
-或者是具有下列性质的二叉搜索树:
⑴ 根结点的左子树和右子树的深度最多相差1;
⑵ 根结点的左子树和右子树也都是平衡二叉树
平衡因子:结点的平衡因子是该结点的左子树的深度与右子树的深度之差。

例:

写一个算法来确定一个数字是否“快乐”。
快乐的数量是一个数字定义为以下过程:从任何正整数,取代数的平方和的位数,并重复这个过程,直到数= 1(它将保持),或者它无休止地循环周期,不包括1。这个过程以1结束的数是快乐数。

bool ishappy(int n){
    
    
    set<int> s;    set:动态查找结构
    int N = n;
    while(s.find(n) == s.end()) 
    //括号里表示 find(n)没找到这个数 就返回和end()一样的值
    {
    
    
        s.insert(n);       //
        n = digits_sum(n);
    }
    return n == 1;
}

8.哈希表

在这里插入图片描述
在这里插入图片描述

幸福数

public class Solution {
    
    
    public boolean isHappy(int n) {
    
    
      if(n < 0 ){
    
    return false;}
      HashSet<Integer> set = new HashSet<Integer>();//构建一个哈希表
      while(n!=1&&!set.contains(n)){
    
    <span style="white-space:pre">	</span>//终止条件,新出现的数为1,同时新数不在增加
          set.add(n);
          int m = 0;
          while(n>0){
    
    <span style="white-space:pre">			</span>//计算各位数的平方和
            m+=(n%10)*(n%10);
            n=n/10;    
          }
          n=m;
      }
      if(n==1){
    
    return true;}
      return false;
    }
}

全文链接: https://leetcode-cn.com/problems/happy-number/
C++之哈希表的使用:https://blog.csdn.net/Huang_JinXin/article/details/95785544
C++ STL中哈希表
hash_map从头到尾详细介绍:https://blog.csdn.net/yousss/article/details/79541543?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

猜你喜欢

转载自blog.csdn.net/m0_46182401/article/details/106812608