函数的csdn博客教程

函数示例:

DELIMITER $$
create function periodtos(kini int)
returns varchar(30)
no sql
deterministic
begin
	declare mout varchar(30);
	case kini
		when 1 then
			set mout='上午';
		when 2 then
			set mout='下午';
		else
			set mout='未知';
	end case;
	return mout;
end$$
DELIMITER ;

函数说明1:

  • When you create a stored function, you must declare either that it is deterministic or that it does not modify data. Otherwise, it may be unsafe for data recovery or replication.
  • By default, for a CREATE FUNCTION statement to be accepted, at least one of DETERMINISTIC, NO SQL, or READS SQL DATA must be specified explicitly. Otherwise an error occurs

函数说明2:

DETERMINISTIC A routine is considered “deterministic” if it always produces the same result for the same input parameters and NOT DETERMINISTIC otherwise. This is mostly used with string or math processing, but not limited to that.

NOT DETERMINISTIC Opposite of “DETERMINISTIC”. “If neither DETERMINISTIC nor NOT DETERMINISTIC is given in the routine definition, the default is NOT DETERMINISTIC. To declare that a function is deterministic, you must specify DETERMINISTIC explicitly.“. So it seems that if no statement is made, MySQl will treat the function as “NOT DETERMINISTIC”. This statement from manual is in contradiction with other statement from another area of manual which tells that: ” When you create a stored function, you must declare either that it is deterministic or that it does not modify data. Otherwise, it may be unsafe for data recovery or replication. By default, for a CREATE FUNCTION statement to be accepted, at least one of DETERMINISTIC, NO SQL, or READS SQL DATA must be specified explicitly. Otherwise an error occurs

I personally got error in MySQL 5.5 if there is no declaration, so i always put at least one declaration of “DETERMINISTIC”, “NOT DETERMINISTIC”, “NO SQL” or “READS SQL DATA” regardless other declarations i may have.

READS SQL DATA This explicitly tells to MySQL that the function will ONLY read data from databases, thus, it does not contain instructions that modify data, but it contains SQL instructions that read data (e.q. SELECT).

MODIFIES SQL DATA This indicates that the routine contains statements that may write data (for example, it contain UPDATE, INSERT, DELETE or ALTER instructions).

NO SQL This indicates that the routine contains no SQL statements.

CONTAINS SQL This indicates that the routine contains SQL instructions, but does not contain statements that read or write data. This is the default if none of these characteristics is given explicitly. Examples of such statements are SELECT NOW(), SELECT 10+@b, SET @x = 1 or DO RELEASE_LOCK(‘abc’), which execute but neither read nor write data.

Note that there are MySQL functions that are not deterministic safe, such as: NOW(), UUID(), etc, which are likely to produce different results on different machines, so a user function that contains such instructions must be declared as NOT DETERMINISTIC. Also, a function that reads data from an unreplicated schema is clearly NONDETERMINISTIC. *


其他:删除函数: drop function f1;

删除过程: drop procedure p1;

记录录路径:开一个pre数组,在每次松弛bai边的时候(就是在执行duif d[j]+cost[k]<d[i] then d[i]:=d[j]+cost[k]的时候),这时如果d[i]被更新了,就将pre[i]:=j,表示当前到zhii点的最短路dao径中,j是i的前驱结点。在做完spfa时,
对于结点i,不断地i:=pre[i]直到i=源点,这途中的点即为路径。

判断负权环:因为用了队列版维护d数组,如果i结点入队次数大于等于n次,则有负权权环

vis的目的其实并不是已经访问过哪些节点,而是记录【[在当前步骤] 或 [之前的步骤]】中已经访问过的状态。因为之前已经访问过了这些状态,而之前那些访问用的步骤更少,因此之后就没必要再次访问这些状态了。

当用bfs用于记录到达某个状态的步骤时,则若某个节点 【曾经访问过】或【通步骤的其他状态已经将这个节点加入队列】,则不用再将这个节点加入队列:

 while (!sourceq.empty()) {
      level_count = sourceq.size();
      while ((level_count--) > 0) {
        auto p = sourceq.front();
        sourceq.pop(); 
        for (int i=0; i<4; i++) {
          int subx = p.first + dx[i];
          int suby = p.second + dy[i];
          if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
            if (A[subx][suby] == 1) {
              return step;
            } else if (A[subx][suby] == 0 && vis2[subx][suby] == 0){
              sourceq.push({subx,suby});
              vis2[subx][suby]=1;
            }
          }
        }
      }

或者:

while (!sourceq.empty()) {
      level_count = sourceq.size();
      while ((level_count--) > 0) {
        auto p = sourceq.front();
        sourceq.pop();
        if (vis2[p.first][p.second] == 1) {
          continue;
        }
        vis2[p.first][p.second] = 1;
        for (int i=0; i<4; i++) {
          int subx = p.first + dx[i];
          int suby = p.second + dy[i];
          if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
            if (A[subx][suby] == 1) {
              return step;
            } else if (A[subx][suby] == 0){
              sourceq.push({subx,suby});
            }
          }
        }
      }
      step++;
    }

但不能这样:

 while (!sourceq.empty()) {
      level_count = sourceq.size();
      while ((level_count--) > 0) {
        auto p = sourceq.front();
        sourceq.pop();
        // 1:
        if (vis2[p.first][p.second] == 1) {
          continue;
        }
        vis2[p.first][p.second] = 1;
        for (int i=0; i<4; i++) {
          int subx = p.first + dx[i];
          int suby = p.second + dy[i];
          if (subx >= 0 && suby >= 0 && subx < m && suby < n) {
            if (A[subx][suby] == 1) {
              return step;
            } else if (A[subx][suby] == 0 && vis2[subx][suby] == 0){
              // 2:
              sourceq.push({subx,suby});
              vis2[subx][suby]=1;
            }
          }
        }
      }

这样做的话,因为2处已经将vis2[subx][suby]设置为1,则访问这个节点时,因为1处代码的存在,会直接跳过访问这个节点。

另外,若有多个起始状态的bfs出现了tle,可能的原因是:队列中的起始状态有重复的,不妨试试没有重复时可不可以度过难关。做leetcode::934::最短的桥时就因为这种原因tle了

dfs时传入了第一个参数。这时就像下棋选择了走的第一步。接着dfs会遍历所有可能的情况。就像只确定下棋的第一步时,之后不同走法可能会走到同一位置一样,dfs也会多次到达同一位置。

因此若只需要到达某个位置一次,则用于一个dfs函数外的数组vis记录访问过的,访问过的就vis[x][y]=1。就算某次递归栈到达了某个地方,但因为这个地方曾经被访问过,进而从这个地方开始的所有其他可能也都曾被访问过,那么就无需再次访问这个地方,这次dfs直接return。

若并非只需要到达某个位置,而是想要知道有多少种到达目标位置的方式。那么标记的方式应该是:在进入dfs函数时令vis[x][y]=1, 在退出dfs时令vis[x][y]=0,通过这种方式避免dfs在一次访问中重复访问某个点。


对bfs进行思考时,用一个长宽为2的地图进行思考。

  1. github上下载Google Test。并放到工程文件夹下。
工程目录结构如下:
☺  tree -L 1                                                                                               master ✗
.
├── CMakeLists.txt
├── CMakeLists.txt.user
├── cmake-build-debug
├── googletest
├── main.cpp
└── src

googletest是之前从github上下载下来Google Test的仓库,并重命名后的。
src中的test目录是测试目录。
src下放【测试目录】和 自己的工程源码们:
☺  tree src                                                                                                master ✗
src
├── include
│   └── Config.h
├── test
│   └── utility
│       └── CellGameCoreTest.cpp
├── ui
│   ├── widget
│   │   └── game
│   │       ├── GameWidget.cpp
│   │       └── GameWidget.h
│   └── window
│       └── mainwindow
│           ├── MainWindow.cpp
│           ├── MainWindow.h
│           └── mainwindow.ui
└── utility
    ├── CellGameCore.cpp
    ├── CellGameCore.h
    └── Rand_int.h

2. 项目的CmakeList.txt中需要引入GoogleTest。如下,引入了gtest和gmock

add_subdirectory(googletest)
include_directories(googletest/googletest/include)
include_directories(googletest/googlemock/include)
target_link_libraries(CellGame gtest gtest_main)
target_link_libraries(CellGame gmock gmock_main)

3. 接着开始写测试文件。可以看到test中采取了与工程类似的目录架构,这种架构风格还不错。

☺  tree src/test -L 3                                                                                      master ✗
src/test
└── utility
    └── CellGameCoreTest.cpp

TEST宏是gtest中的,第一个参数是Test Suit Name, 第二个参数是 Test Name。这两个Name之前有层级关系。在TEST中可以使用ASSERT_EQ等宏。

//
// Created by perci on 2020/5/21.
//

#include <src/utility/CellGameCore.h>
#include <vector>
#include "gtest/gtest.h"
TEST(CellGameCoreTest, SampleTest) {
    CellGameCore core;
    std::vector<std::vector<int>> vs;
    vs.push_back(std::vector<int> {1,1,1});
    vs.push_back(std::vector<int> {0,0,0});
    vs.push_back(std::vector<int> {0,0,0});
    std::vector<std::vector<int>> vs2 = core.process(vs);

    ASSERT_EQ(vs2[0][0], 0);
    ASSERT_EQ(vs2[0][1], 1);
    ASSERT_EQ(vs2[0][2], 0);
    ASSERT_EQ(vs2[1][1], 1);

    return;
}

TEST(CellGameCoreTest, SampleTest2) {
    CellGameCore core;
    std::vector<std::vector<int>> vs;
    vs.push_back(std::vector<int> {1,0,0});
    vs.push_back(std::vector<int> {0,1,0});
    vs.push_back(std::vector<int> {0,0,1});
    std::vector<std::vector<int>> vs2 = core.process(vs);

    ASSERT_EQ(vs2[0][0], 0);
    ASSERT_EQ(vs2[0][1], 0);
    ASSERT_EQ(vs2[0][2], 0);
    ASSERT_EQ(vs2[1][1], 1);
}

4. 需要在CmakeList.txt中将测试文件添加到工程中。这里add_executable中新增了一个mytest的。

add_executable(mytest src/test/utility/CellGameCoreTest.cpp src/utility/CellGameCore.cpp)
target_link_libraries(mytest gtest gtest_main)

同时因为CellGameCoreTest.cpp中使用CellGameCore这个类,就引入了CellGameCore.cpp。(CellGameCore.cpp中引入了CellGameCore.h, 这样就相当于把这两个文件都引入了。光引入.h是不行的。)

5. 接着reload CmakeList.txt后,就会发现项目的Configuration

中有了mytest,接着就可以跑起测试了

java: 可用java.awt.Robot类,这个类可以截屏,可以模拟键盘输入、移动鼠标。

c++: Qt5的QScreen类,可截整个屏幕(但在ios下会因为安全、沙箱之类的原因不可截应用外的屏幕)

    // c++ qt5, 截取整个屏幕作为 当前窗口 的背景图
    QScreen *screen = QGuiApplication::primaryScreen(); 
    if (screen) {
         QPixmap bkgnd = screen->grabWindow(0);
         bkgnd = bkgnd.scaled(this->size(), Qt::IgnoreAspectRatio);
         QPalette palette;
         palette.setBrush(QPalette::Background, bkgnd);
         this->setPalette(palette);
    }
    // qt5官方的截屏软件例子:https://doc.qt.io/qt-5/qtwidgets-desktop-screenshot-example.html

  1. 可以放松眼睛
  2. 10min时可以阶段性思考、总结,思考接下来45min码的方向。在刷算法题时尤其应该如此,若不如此,就一直在那里盲目的改改改,但休息10min时,思考算法问题、思考接下怎么解决之类的,就不至于一直在那里碌碌无为。在码其他东西,如写工程时,也是这样,可以思考怎么实现,而不至于随便码一些,发现错了又改这种。