防止表单重复提交的几种策略

防止表单重复提交的几种策略

表单重复提交是在多用户Web应用中最常见、带来很多麻烦的一个问题。有很多的应用场景都会遇到重复提交问题,比如:

  • 点击提交按钮两次。
  • 点击刷新按钮。
  • 使用浏览器后退按钮重复之前的操作,导致重复提交表单。
  • 使用浏览器历史记录重复提交表单。
  • 浏览器重复的HTTP请求。
  • 几种防止表单重复提交的方法

      禁掉提交按钮。表单提交后使用Javascript使提交按钮disable。这种方法防止心急的用户多次点击按钮。但有个问题,如果客户端把Javascript给禁止掉,这种方法就无效了。

      我之前的文章曾说过用一些Jquery插件效果不错。

      Post/Redirect/Get模式。在提交后执行页面重定向,这就是所谓的Post-Redirect-Get (PRG)模式。简言之,当用户提交了表单后,你去执行一个客户端的重定向,转到提交成功信息页面。

      这能避免用户按F5导致的重复提交,而其也不会出现浏览器表单重复提交的警告,也能消除按浏览器前进和后退按导致的同样问题。

      在session中存放一个特殊标志。当表单页面被请求时,生成一个特殊的字符标志串,存在session中,同时放在表单的隐藏域里。接受处理表单数据时,检查标识字串是否存在,并立即从session中删除它,然后正常处理数据。

      如果发现表单提交里没有有效的标志串,这说明表单已经被提交过了,忽略这次提交。

      这使你的web应用有了更高级的XSRF保护。

      在数据库里添加约束。在数据库里添加唯一约束或创建唯一索引,防止出现重复数据。这是最有效的防止重复提交数据的方法。

      你是如何克服数据重复提交问题的?你遇到过什么重复提交数据的现实例子吗?

      英文原文:Prevent Duplicate Form Submission

    二叉树遍历

     

    行文结构

    1. 递归方法
    2. 非递归方法
    3. 微软面试题

    二叉树遍历根据“根节点”遍历时相对的次序分为前序、中序、后序。图示为相对于根节点的次序,左右子树也是一样的规则。

                         前序遍历                                             中序遍历                                                后续遍历

    1. 递归方法

    前序遍历

    复制代码
    void PreorderTraversal(BiTree T)
    {
        if(T)
        {
            cout << T->data << endl;
            PreorderTraversal(T->left);
            PreorderTraversal(T->right);
        }
    }
    复制代码

    中序遍历

    复制代码
    void InorderTraversal(BiTree T)
    {
        if(T)
        {
            InorderTraversal(T->left);
            cout << T->data << endl;
            InorderTraversal(T->right);
        }
    }
    复制代码

    后续遍历

    复制代码
    void PostorderTraversal(BiTree T)
    {
        if(T)
        {
            PostorderTraversal(T->left);
            PostorderTraversal(T->right);
            cout << T->data << endl;
        }
    }
    复制代码

    整合参考程序

     View Code

    #include<iostream>
    #include<vector>
    using namespace std;

    typedef struct BiTNode
    {
    int data;
    BiTNode *left;
    BiTNode *right;
    }BiTNode, *BiTree;

    bool SearchBST(BiTree T, int val, BiTree f, BiTree &p)
    {
    if(!T)
    {
    p = f;
    return false;
    }
    else if(val == T->data)
    {
    p = T;
    return true;
    }
    else if(val < T->data)
    SearchBST(T->left, val, T, p);
    else
    SearchBST(T->right, val, T, p);
    }

    bool InsertBST(BiTree &T, int val)
    {
    BiTree p;
    if(!SearchBST(T, val, NULL, p))
    {
    BiTree node = new BiTNode;
    node->data = val;
    node->left = node->right = NULL;
    if(!p)
    T = node;
    else if(val < p->data)
    p->left = node;
    else
    p->right = node;
    return true;
    }
    return false;
    }

    void PreorderTraversal(BiTree T)
    {
    if(T)
    {
    cout << T->data << endl;
    PreorderTraversal(T->left);
    PreorderTraversal(T->right);
    }
    }

    void InorderTraversal(BiTree T)
    {
    if(T)
    {
    InorderTraversal(T->left);
    cout << T->data << endl;
    InorderTraversal(T->right);
    }
    }

    void PostorderTraversal(BiTree T)
    {
    if(T)
    {
    PostorderTraversal(T->left);
    PostorderTraversal(T->right);
    cout << T->data << endl;
    }
    }

    int main()
    {
    int array[] = {5, 1, 0, 45, 10, 3, 8, 5};
    int len_array = sizeof(array) / sizeof(*array);
    BiTree root = NULL;
    for(int i = 0; i< len_array; ++i)
    InsertBST(root, array[i]);
    cout << "PreorderTraversal" << endl;
    PreorderTraversal(root);
    cout << "----------------------" << endl;

    cout << "InorderTraversal" << endl;
    InorderTraversal(root);
    cout << "----------------------" << endl;

    cout << "PostorderTraversal" << endl;
    PostorderTraversal(root);
    cout << "----------------------" << endl;
    }

    结果

    2. 非递归方法

    非递归方法借助于栈,“记忆”走过的结点。

    前序遍历

    “根-左孩子-右孩子”,对每一个结点看成是根节点,先输出,后入栈(到时返回访问右孩子),然后访问左孩子。当不能在往左走时,查询栈中的记忆,根据栈顶进入右孩子,重复上边的故事。

    复制代码
    void PreorderTraversal(BiTree T)
    {
        stack<BiTree> s;
        while(T || !s.empty())
        {
            while(T)
            {
                cout << T->data << endl;
                s.push(T);
                T = T->left;
            }
            T = s.top();
            T = T->right;
            s.pop();
        }
    }
    复制代码

    中序遍历

    “左孩子-根-右孩子”,对每一个结点看成是根节点,先入栈(到时返回访问自己和右孩子),然后访问左孩子。当不能在往左走时,查询栈中的记忆,根据栈顶访问自己并且进入右孩子,重复上边的故事。

    复制代码
    void InorderTraversal(BiTree T)
    {
        stack<BiTree> s;
        while(T || !s.empty())
        {
            while(T)
            {
                s.push(T);
                T = T->left;
            }
            T = s.top();
            cout << T->data << endl;
            T = T->right;
            s.pop();
        }
    }
    复制代码

    后续遍历

    “左孩子-右孩子-根”,为了达到这个效果,需要把把按“根-->右孩子-->左孩子”的顺序入栈,因为栈的特征是先进后出,所以访问时顺序相反。对于一个结点只有满足以下两个条件时,才访问,否则按“根-->右孩子-->左孩子”顺序入栈。

    • 左右孩子全为NULL
    • 前边访问的结点正好为当前结点的左孩子或右孩子(访问了左孩子必定已经访问了右孩子)
    复制代码
    void PostorderTraversal(BiTree T)
    {
        stack<BiTree> s;
        BiTree cur = NULL, pre = NULL;
        s.push(T);
        while(!s.empty())
        {
            cur = s.top();
            if((!cur->left && !cur->right) ||
                    (pre != NULL && (pre == cur->left || pre == cur->right)))
            {
                cout << cur->data << endl;
                pre = cur;
                s.pop();
            }
            else
            {
                if(cur->right)
                    s.push(cur->right);
                if(cur->left)    
                    s.push(cur->left);
            }
        }
    }
    复制代码

    整合参考程序

     View Code

    #include<iostream>
    #include<stack>

    using namespace std;

    typedef struct BiTNode
    {
    int data;
    BiTNode *left;
    BiTNode *right;
    }BiTNode, *BiTree;

    bool SearchBST(BiTree T, int val, BiTree f, BiTree &p)
    {
    if(!T)
    {
    p = f;
    return false;
    }
    else if(val == T->data)
    {
    p = T;
    return true;
    }
    else if(val < T->data)
    SearchBST(T->left, val, T, p);
    else
    SearchBST(T->right, val, T, p);
    }

    bool InsertBST(BiTree &T, int val)
    {
    BiTree p;
    if(!SearchBST(T, val, NULL, p))
    {
    BiTree node = new BiTNode;
    node->data = val;
    node->left = node->right = NULL;
    if(!p)
    T = node;
    else if(val < p->data)
    p->left = node;
    else
    p->right = node;
    return true;
    }
    return false;
    }

    void PreorderTraversal(BiTree T)
    {
    stack<BiTree> s;
    while(T || !s.empty())
    {
    while(T)
    {
    cout << T->data << endl;
    s.push(T);
    T = T->left;
    }
    T = s.top();
    T = T->right;
    s.pop();
    }
    }

    void InorderTraversal(BiTree T)
    {
    stack<BiTree> s;
    while(T || !s.empty())
    {
    while(T)
    {
    s.push(T);
    T = T->left;
    }
    T = s.top();
    cout << T->data << endl;
    T = T->right;
    s.pop();
    }
    }

    void PostorderTraversal(BiTree T)
    {
    stack<BiTree> s;
    BiTree cur = NULL, pre = NULL;
    s.push(T);
    while(!s.empty())
    {
    cur = s.top();
    if((!cur->left && !cur->right) ||
    (pre != NULL && (pre == cur->left || pre == cur->right)))
    {
    cout << cur->data << endl;
    pre = cur;
    s.pop();
    }
    else
    {
    if(cur->right)
    s.push(cur->right);
    if(cur->left)
    s.push(cur->left);
    }
    }
    }

    int main()
    {
    int array[] = {5, 1, 0, 45, 10, 3, 8, 5};
    int len_array = sizeof(array) / sizeof(*array);
    BiTree root = NULL;
    for(int i = 0; i< len_array; ++i)
    InsertBST(root, array[i]);
    cout << "PreorderTraversal" << endl;
    PreorderTraversal(root);
    cout << "----------------------" << endl;

    cout << "InorderTraversal" << endl;
    InorderTraversal(root);
    cout << "----------------------" << endl;

    cout << "PostorderTraversal" << endl;
    PostorderTraversal(root);
    cout << "----------------------" << endl;
    }

    结果同递归遍历

    3. 微软面试题

    分析:由二叉遍历树变成有序的结构,不用说绝对是中序遍历。中序遍历分为两种方法——递归、非递归。递归不需要额外的空间,非递归需要额外空间(借助与栈)。现在用两种方法实现,其思路都是基本中序遍历的改进。

    方法一(递归方法)

    复制代码
    void BST2BLink(BiTree T, BiTree &pre)  //&地址操作,所有递归使用同一个
    {
        if(T)
        {
            BST2BLink(T->left, pre);
            if(pre)
            {
                pre->right = T;
                T ->left = pre;
            }
            pre = T;
            BST2BLink(T->right, pre);
        }
    }
    复制代码

    执行程序

     View Code

    #include<iostream>
    #include<stack>

    using namespace std;

    typedef struct BiTNode
    {
    int data;
    BiTNode *left;
    BiTNode *right;
    }BiTNode, *BiTree;

    bool SearchBST(BiTree T, int val, BiTree f, BiTree &p)
    {
    if(!T)
    {
    p = f;
    return false;
    }
    else if(val == T->data)
    {
    p = T;
    return true;
    }
    else if(val < T->data)
    SearchBST(T->left, val, T, p);
    else
    SearchBST(T->right, val, T, p);
    }

    bool InsertBST(BiTree &T, int val)
    {
    BiTree p;
    if(!SearchBST(T, val, NULL, p))
    {
    BiTree node = new BiTNode;
    node->data = val;
    node->left = node->right = NULL;
    if(!p)
    T = node;
    else if(val < p->data)
    p->left = node;
    else
    p->right = node;
    return true;
    }
    return false;
    }

    void BST2BLink(BiTree T, BiTree &pre)
    {
    if(T)
    {
    BST2BLink(T->left, pre);
    if(pre)
    {
    pre->right = T;
    T ->left = pre;
    }
    pre = T;
    BST2BLink(T->right, pre);
    }
    }

    int BST2BLink(BiTree &T)
    {
    stack<BiTree> s;
    BiTree cur = T, pre = NULL;
    while(cur || !s.empty())
    {
    while(cur)
    {
    s.push(cur);
    cur = cur->left;
    }

    cur = s.top();
    s.pop();
    cout << cur->data << endl;

    if(!pre)
    T = cur;
    else
    {
    pre->right = cur;
    cur ->left = pre;
    }
    pre = cur;
    cur = cur->right;
    }
    }

    void BLinkTraversal(BiTree root)
    {
    while(root)
    {
    cout << root->data << endl;
    root = root->right;
    }
    }

    int main()
    {
    int array[] = {5, 8, 0, 3, 100, 45};
    int len_array = sizeof(array) / sizeof(*array);
    BiTree root = NULL;
    for(int i = 0; i< len_array; ++i)
    InsertBST(root, array[i]);

    cout << "Recursion" << endl;
    BiTree pre = NULL;
    BST2BLink(root, pre);
    while(root->left)
    root = root->left;
    BLinkTraversal(root);
    /*
    cout << " Not Recursion" << endl;
    BST2BLink(root_copy);
    cout << "----------------------" << endl;
    BLinkTraversal(root);
    */
    }

    方法二(非递归方法)
    复制代码
    int BST2BLink(BiTree &T)
    {
        stack<BiTree> s;
        BiTree cur = T, pre = NULL;
        while(cur || !s.empty())
        {
            while(cur)
            {
                s.push(cur);
                cur = cur->left;
            }
    
            cur = s.top();
            s.pop();
            cout << cur->data << endl;
            if(!pre)
                T = cur;
            else
            {
                pre->right = cur;
                cur ->left = pre;
            }
            pre = cur;
            cur = cur->right;
        }
    }
    复制代码

    执行程序

     View Code

    #include<iostream>
    #include<stack>

    using namespace std;

    typedef struct BiTNode
    {
    int data;
    BiTNode *left;
    BiTNode *right;
    }BiTNode, *BiTree;

    bool SearchBST(BiTree T, int val, BiTree f, BiTree &p)
    {
    if(!T)
    {
    p = f;
    return false;
    }
    else if(val == T->data)
    {
    p = T;
    return true;
    }
    else if(val < T->data)
    SearchBST(T->left, val, T, p);
    else
    SearchBST(T->right, val, T, p);
    }

    bool InsertBST(BiTree &T, int val)
    {
    BiTree p;
    if(!SearchBST(T, val, NULL, p))
    {
    BiTree node = new BiTNode;
    node->data = val;
    node->left = node->right = NULL;
    if(!p)
    T = node;
    else if(val < p->data)
    p->left = node;
    else
    p->right = node;
    return true;
    }
    return false;
    }

    void BST2BLink(BiTree T, BiTree &pre)
    {
    if(T)
    {
    BST2BLink(T->left, pre);
    if(pre)
    {
    pre->right = T;
    T ->left = pre;
    }
    pre = T;
    BST2BLink(T->right, pre);
    }
    }

    int BST2BLink(BiTree &T)
    {
    stack<BiTree> s;
    BiTree cur = T, pre = NULL;
    while(cur || !s.empty())
    {
    while(cur)
    {
    s.push(cur);
    cur = cur->left;
    }

    cur = s.top();
    s.pop();
    // cout << cur->data << endl;

    if(!pre)
    T = cur;
    else
    {
    pre->right = cur;
    cur ->left = pre;
    }
    pre = cur;
    cur = cur->right;
    }
    }

    void BLinkTraversal(BiTree root)
    {
    while(root)
    {
    cout << root->data << endl;
    root = root->right;
    }
    }

    int main()
    {
    int array[] = {5, 8, 0, 3, 100, 45};
    int len_array = sizeof(array) / sizeof(*array);
    BiTree root = NULL;
    for(int i = 0; i< len_array; ++i)
    InsertBST(root, array[i]);
    /*
    cout << "Recursion" << endl;
    BiTree pre = NULL;
    BST2BLink(root, pre);
    while(root->left)
    root = root->left;
    BLinkTraversal(root);
    */
    cout << " Not Recursion" << endl;
    BST2BLink(root);
    cout << "----------------------" << endl;
    BLinkTraversal(root);

    }

     
     
原文地址:https://www.cnblogs.com/Leo_wl/p/3432434.html