rbtree.h

#ifndef _RED_BLACK_TREE_H_
#define _RED_BLACK_TREE_H_ #define RED 0 // 红色节点
#define BLACK 1 // 黑色节点 typedef int Type; // 红黑树的节点
typedef struct RBTreeNode{
unsigned char color; // 颜色(RED 或 BLACK)
Type key; // 关键字(键值)
struct RBTreeNode *left; // 左孩子
struct RBTreeNode *right; // 右孩子
struct RBTreeNode *parent; // 父结点
}Node, *RBTree; // 红黑树的根
typedef struct rb_root{
Node *node;
}RBRoot; // 创建红黑树,返回"红黑树的根"!
RBRoot* create_rbtree(); // 销毁红黑树
void destroy_rbtree(RBRoot *root); // 将结点插入到红黑树中。插入成功,返回0;失败返回-1。
int insert_rbtree(RBRoot *root, Type key); // 删除结点(key为节点的值)
void delete_rbtree(RBRoot *root, Type key); // 前序遍历"红黑树"
void preorder_rbtree(RBRoot *root);
// 中序遍历"红黑树"
void inorder_rbtree(RBRoot *root);
// 后序遍历"红黑树"
void postorder_rbtree(RBRoot *root); // (递归实现)查找"红黑树"中键值为key的节点。找到的话,返回0;否则,返回-1。
int rbtree_search(RBRoot *root, Type key);
// (非递归实现)查找"红黑树"中键值为key的节点。找到的话,返回0;否则,返回-1。
int iterative_rbtree_search(RBRoot *root, Type key); // 返回最小结点的值(将值保存到val中)。找到的话,返回0;否则返回-1。
int rbtree_minimum(RBRoot *root, int *val);
// 返回最大结点的值(将值保存到val中)。找到的话,返回0;否则返回-1。
int rbtree_maximum(RBRoot *root, int *val); // 打印红黑树
void print_rbtree(RBRoot *root); #endif

  

main.c

/**
* C语言实现的红黑树(Red Black Tree)
*
* @author skywang
* @date 2013/11/18
*/ #include <stdio.h>
#include <stdlib.h>
#include "rbtree.h" #define rb_parent(r) ((r)->parent)
#define rb_color(r) ((r)->color)
#define rb_is_red(r) ((r)->color==RED)
#define rb_is_black(r) ((r)->color==BLACK)
#define rb_set_black(r) do { (r)->color = BLACK; } while (0)
#define rb_set_red(r) do { (r)->color = RED; } while (0)
#define rb_set_parent(r,p) do { (r)->parent = (p); } while (0)
#define rb_set_color(r,c) do { (r)->color = (c); } while (0) /*
* 创建红黑树,返回"红黑树的根"!
*/
RBRoot* create_rbtree()
{
RBRoot *root = (RBRoot *)malloc(sizeof(RBRoot));
root->node = NULL; return root;
} /*
* 前序遍历"红黑树"
*/
static void preorder(RBTree tree)
{
if(tree != NULL)
{
printf("%d ", tree->key);
preorder(tree->left);
preorder(tree->right);
}
}
void preorder_rbtree(RBRoot *root)
{
if (root)
preorder(root->node);
} /*
* 中序遍历"红黑树"
*/
static void inorder(RBTree tree)
{
if(tree != NULL)
{
inorder(tree->left);
printf("%d ", tree->key);
inorder(tree->right);
}
} void inorder_rbtree(RBRoot *root)
{
if (root)
inorder(root->node);
} /*
* 后序遍历"红黑树"
*/
static void postorder(RBTree tree)
{
if(tree != NULL)
{
postorder(tree->left);
postorder(tree->right);
printf("%d ", tree->key);
}
} void postorder_rbtree(RBRoot *root)
{
if (root)
postorder(root->node);
} /*
* (递归实现)查找"红黑树x"中键值为key的节点
*/
static Node* search(RBTree x, Type key)
{
if (x==NULL || x->key==key)
return x; if (key < x->key)
return search(x->left, key);
else
return search(x->right, key);
}
int rbtree_search(RBRoot *root, Type key)
{
if (root)
return search(root->node, key)? 0 : -1;
} /*
* (非递归实现)查找"红黑树x"中键值为key的节点
*/
static Node* iterative_search(RBTree x, Type key)
{
while ((x!=NULL) && (x->key!=key))
{
if (key < x->key)
x = x->left;
else
x = x->right;
} return x;
}
int iterative_rbtree_search(RBRoot *root, Type key)
{
if (root)
return iterative_search(root->node, key) ? 0 : -1;
} /*
* 查找最小结点:返回tree为根结点的红黑树的最小结点。
*/
static Node* minimum(RBTree tree)
{
if (tree == NULL)
return NULL; while(tree->left != NULL)
tree = tree->left;
return tree;
} int rbtree_minimum(RBRoot *root, int *val)
{
Node *node; if (root)
node = minimum(root->node); if (node == NULL)
return -1; *val = node->key;
return 0;
} /*
* 查找最大结点:返回tree为根结点的红黑树的最大结点。
*/
static Node* maximum(RBTree tree)
{
if (tree == NULL)
return NULL; while(tree->right != NULL)
tree = tree->right;
return tree;
} int rbtree_maximum(RBRoot *root, int *val)
{
Node *node; if (root)
node = maximum(root->node); if (node == NULL)
return -1; *val = node->key;
return 0;
} /*
* 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。
*/
static Node* rbtree_successor(RBTree x)
{
// 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
if (x->right != NULL)
return minimum(x->right); // 如果x没有右孩子。则x有以下两种可能:
// (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
// (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。
Node* y = x->parent;
while ((y!=NULL) && (x==y->right))
{
x = y;
y = y->parent;
} return y;
} /*
* 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。
*/
static Node* rbtree_predecessor(RBTree x)
{
// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
if (x->left != NULL)
return maximum(x->left); // 如果x没有左孩子。则x有以下两种可能:
// (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
// (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。
Node* y = x->parent;
while ((y!=NULL) && (x==y->left))
{
x = y;
y = y->parent;
} return y;
} /*
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点x进行左旋):
* px px
* / /
* x y
* / \ --(左旋)--> / \ #
* lx y x ry
* / \ / \
* ly ry lx ly
*
*
*/
static void rbtree_left_rotate(RBRoot *root, Node *x)
{
// 设置x的右孩子为y
Node *y = x->right; // 将 “y的左孩子” 设为 “x的右孩子”;
// 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲”
x->right = y->left;
if (y->left != NULL)
y->left->parent = x; // 将 “x的父亲” 设为 “y的父亲”
y->parent = x->parent; if (x->parent == NULL)//修改红黑树的根节点
{
//tree = y; // 如果 “x的父亲” 是空节点,则将y设为根节点
root->node = y; // 如果 “x的父亲” 是空节点,则将y设为根节点
}
else
{
if (x->parent->left == x)
x->parent->left = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”
else
x->parent->right = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”
} // 将 “x” 设为 “y的左孩子”
y->left = x;
// 将 “x的父节点” 设为 “y”
x->parent = y;
} /*
* 对红黑树的节点(y)进行右旋转
*
* 右旋示意图(对节点y进行左旋):
* py py
* / /
* y x
* / \ --(右旋)--> / \ #
* x ry lx y
* / \ / \ #
* lx rx rx ry
*
*/
static void rbtree_right_rotate(RBRoot *root, Node *y)
{
// 设置x是当前节点的左孩子。
Node *x = y->left; // 将 “x的右孩子” 设为 “y的左孩子”;
// 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”
y->left = x->right;
if (x->right != NULL)
x->right->parent = y; // 将 “y的父亲” 设为 “x的父亲”
x->parent = y->parent; if (y->parent == NULL)
{
//tree = x; // 如果 “y的父亲” 是空节点,则将x设为根节点
root->node = x; // 如果 “y的父亲” 是空节点,则将x设为根节点
}
else
{
if (y == y->parent->right)
y->parent->right = x; // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子”
else
y->parent->left = x; // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”
} // 将 “y” 设为 “x的右孩子”
x->right = y; // 将 “y的父节点” 设为 “x”
y->parent = x;
} /*
* 红黑树插入修正函数
*
* 在向红黑树中插入节点之后(失去平衡),再调用该函数;
* 目的是将它重新塑造成一颗红黑树。
*
* 参数说明:
* root 红黑树的根
* node 插入的结点 // 对应《算法导论》中的z
*/
static void rbtree_insert_fixup(RBRoot *root, Node *node)
{
Node *parent, *gparent; // 若“父节点存在,并且父节点的颜色是红色”
while ((parent = rb_parent(node)) && rb_is_red(parent))
{
gparent = rb_parent(parent); //若“父节点”是“祖父节点的左孩子”
if (parent == gparent->left)
{
// Case 1条件:叔叔节点是红色
{
Node *uncle = gparent->right;
if (uncle && rb_is_red(uncle))//没有节点进入该分支,如何构造?
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
} // Case 2条件:叔叔是黑色,且当前节点是右孩子,叔叔不存在,也认为是黑色
if (parent->right == node)//插入80节点时,先左旋,后右旋
{
Node *tmp;
rbtree_left_rotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
} // Case 3条件:叔叔是黑色,且当前节点是左孩子。
rb_set_black(parent);//旋转前设置好颜色
rb_set_red(gparent);//旋转前设置好颜色
rbtree_right_rotate(root, gparent);
}
else//若父节点是祖父节点的右孩子
{
// Case 1条件:叔叔节点是红色
{
Node *uncle = gparent->left;//当插入60时,调整颜色即可,调整颜色后不符合红黑树,递归进行
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;//继续进行调整
}
} // Case 2条件:叔叔是黑色,且当前节点是左孩子,插入30时,先右旋,后左旋
if (parent->left == node)
{
Node *tmp;
rbtree_right_rotate(root, parent);
tmp = parent;
parent = node;
node = tmp;
} // Case 3条件:叔叔是黑色,且当前节点是右孩子。
rb_set_black(parent);//旋转前设置好颜色
rb_set_red(gparent);//旋转前设置好颜色
rbtree_left_rotate(root, gparent);
}
} // 将根节点设为黑色
rb_set_black(root->node);
} /*
* 添加节点:将节点(node)插入到红黑树中
*
* 参数说明:
* root 红黑树的根
* node 插入的结点 // 对应《算法导论》中的z
*/
static void rbtree_insert(RBRoot *root, Node *node)
{
Node *y = NULL;
Node *x = root->node; // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。
while (x != NULL)
{
y = x;
if (node->key < x->key)
x = x->left;
else
x = x->right;
}
rb_parent(node) = y;//找到父节点并把要插入节点的父节点的指针修改
//修改父节点的子节点指针
if (y != NULL)
{
if (node->key < y->key)
y->left = node; // 情况2:若“node所包含的值” < “y所包含的值”,则将node设为“y的左孩子”
else
y->right = node; // 情况3:(“node所包含的值” >= “y所包含的值”)将node设为“y的右孩子”
}
else
{
root->node = node; // 情况1:若y是空节点,则将node设为根
} // 2. 设置节点的颜色为红色
node->color = RED; // 3. 将它重新修正为一颗二叉查找树
rbtree_insert_fixup(root, node);
} /*
* 创建结点
*
* 参数说明:
* key 是键值。
* parent 是父结点。
* left 是左孩子。
* right 是右孩子。
*/
static Node* create_rbtree_node(Type key, Node *parent, Node *left, Node* right)
{
Node* p; if ((p = (Node *)malloc(sizeof(Node))) == NULL)
return NULL;
p->key = key;
p->left = left;
p->right = right;
p->parent = parent;
p->color = BLACK; // 默认为黑色 return p;
} /*
* 新建结点(节点键值为key),并将其插入到红黑树中
*
* 参数说明:
* root 红黑树的根
* key 插入结点的键值
* 返回值:
* 0,插入成功
* -1,插入失败
*/
int insert_rbtree(RBRoot *root, Type key)
{
Node *node; // 新建结点 // 不允许插入相同键值的节点。
// (若想允许插入相同键值的节点,注释掉下面两句话即可!)
if (search(root->node, key) != NULL)
return -1; // 如果新建结点失败,则返回。
if ((node=create_rbtree_node(key, NULL, NULL, NULL)) == NULL)
return -1; rbtree_insert(root, node); return 0;
} /*
* 红黑树删除修正函数
*
* 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数;
* 目的是将它重新塑造成一颗红黑树。
*
* 参数说明:
* root 红黑树的根
* node 待修正的节点
*/
static void rbtree_delete_fixup(RBRoot *root, Node *node, Node *parent)
{
Node *other; while ((!node || rb_is_black(node)) && node != root->node)
{
if (parent->left == node)
{
other = parent->right;
if (rb_is_red(other))
{
// Case 1: x的兄弟w是红色的
rb_set_black(other);
rb_set_red(parent);
rbtree_left_rotate(root, parent);
other = parent->right;
}
if ((!other->left || rb_is_black(other->left)) &&
(!other->right || rb_is_black(other->right)))
{
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->right || rb_is_black(other->right))
{
// Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
rb_set_black(other->left);
rb_set_red(other);
rbtree_right_rotate(root, other);
other = parent->right;
}
// Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->right);
rbtree_left_rotate(root, parent);
node = root->node;
break;
}
}
else
{
other = parent->left;
if (rb_is_red(other))
{
// Case 1: x的兄弟w是红色的
rb_set_black(other);
rb_set_red(parent);
rbtree_right_rotate(root, parent);
other = parent->left;
}
if ((!other->left || rb_is_black(other->left)) &&
(!other->right || rb_is_black(other->right)))
{
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->left || rb_is_black(other->left))
{
// Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
rb_set_black(other->right);
rb_set_red(other);
rbtree_left_rotate(root, other);
other = parent->left;
}
// Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->left);
rbtree_right_rotate(root, parent);
node = root->node;
break;
}
}
}
if (node)
rb_set_black(node);
} /*
* 删除结点
*
* 参数说明:
* tree 红黑树的根结点
* node 删除的结点
*/
void rbtree_delete(RBRoot *root, Node *node)
{
Node *child, *parent;
int color; // 被删除节点的"左右孩子都不为空"的情况。
if ( (node->left!=NULL) && (node->right!=NULL) )
{
// 被删节点的后继节点。(称为"取代节点")
// 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。
Node *replace = node; // 获取后继节点
replace = replace->right;
while (replace->left != NULL)
replace = replace->left; // "node节点"不是根节点(只有根节点不存在父节点)
if (rb_parent(node))
{
if (rb_parent(node)->left == node)
rb_parent(node)->left = replace;
else
rb_parent(node)->right = replace;
}
else
// "node节点"是根节点,更新根节点。
root->node = replace; // child是"取代节点"的右孩子,也是需要"调整的节点"。
// "取代节点"肯定不存在左孩子!因为它是一个后继节点。
child = replace->right;
parent = rb_parent(replace);
// 保存"取代节点"的颜色
color = rb_color(replace); // "被删除节点"是"它的后继节点的父节点"
if (parent == node)
{
parent = replace;
}
else
{
// child不为空
if (child)
rb_set_parent(child, parent);
parent->left = child; replace->right = node->right;
rb_set_parent(node->right, replace);
} replace->parent = node->parent;
replace->color = node->color;
replace->left = node->left;
node->left->parent = replace; if (color == BLACK)
rbtree_delete_fixup(root, child, parent);
free(node); return ;
} if (node->left !=NULL)
child = node->left;
else
child = node->right; parent = node->parent;
// 保存"取代节点"的颜色
color = node->color; if (child)
child->parent = parent; // "node节点"不是根节点
if (parent)
{
if (parent->left == node)
parent->left = child;
else
parent->right = child;
}
else
root->node = child; if (color == BLACK)
rbtree_delete_fixup(root, child, parent);
free(node);
} /*
* 删除键值为key的结点
*
* 参数说明:
* tree 红黑树的根结点
* key 键值
*/
void delete_rbtree(RBRoot *root, Type key)
{
Node *z, *node; if ((z = search(root->node, key)) != NULL)
rbtree_delete(root, z);
} /*
* 销毁红黑树
*/
static void rbtree_destroy(RBTree tree)
{
if (tree==NULL)
return ; if (tree->left != NULL)
rbtree_destroy(tree->left);
if (tree->right != NULL)
rbtree_destroy(tree->right); free(tree);
} void destroy_rbtree(RBRoot *root)
{
if (root != NULL)
rbtree_destroy(root->node); free(root);
} /*
* 打印"红黑树"
*
* tree -- 红黑树的节点
* key -- 节点的键值
* direction -- 0,表示该节点是根节点;
* -1,表示该节点是它的父结点的左孩子;
* 1,表示该节点是它的父结点的右孩子。
*/
static void rbtree_print(RBTree tree, Type key, int direction)
{
if(tree != NULL)
{
if(direction==0) // tree是根节点
printf("%2d(B) is root\n", tree->key);
else // tree是分支节点
printf("%2d(%s) is %2d's %6s child\n", tree->key, rb_is_red(tree)?"R":"B", key, direction==1?"right" : "left"); rbtree_print(tree->left, tree->key, -1);
rbtree_print(tree->right,tree->key, 1);
}
} void print_rbtree(RBRoot *root)
{
if (root!=NULL && root->node!=NULL)
rbtree_print(root->node, root->node->key, 0);
} /**
* C语言实现的红黑树(Red Black Tree)
*
* @author skywang
* @date 2013/11/18
*/ #define CHECK_INSERT 1 // "插入"动作的检测开关(0,关闭;1,打开)
#define CHECK_DELETE 1 // "删除"动作的检测开关(0,关闭;1,打开)
#define LENGTH(a) ( (sizeof(a)) / (sizeof(a[0])) ) void main()
{
int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
int i, ilen=LENGTH(a);
RBRoot *root=NULL; root = create_rbtree();
printf("== 原始数据: ");
for(i=0; i<ilen; i++)
printf("%d ", a[i]);
printf("\n"); for(i=0; i<ilen; i++)
{
insert_rbtree(root, a[i]);
#if CHECK_INSERT
printf("== 添加节点: %d\n", a[i]);
printf("== 树的详细信息: \n");
print_rbtree(root);
printf("\n");
#endif
} printf("== 前序遍历: ");
preorder_rbtree(root); printf("\n== 中序遍历: ");
inorder_rbtree(root); printf("\n== 后序遍历: ");
postorder_rbtree(root);
printf("\n"); if (rbtree_minimum(root, &i)==0)
printf("== 最小值: %d\n", i);
if (rbtree_maximum(root, &i)==0)
printf("== 最大值: %d\n", i);
printf("== 树的详细信息: \n");
print_rbtree(root);
printf("\n"); #if CHECK_DELETE
for(i=0; i<ilen; i++)
{
delete_rbtree(root, a[i]); printf("== 删除节点: %d\n", a[i]);
if (root)
{
printf("== 树的详细信息: \n");
print_rbtree(root);
printf("\n");
}
}
#endif destroy_rbtree(root);
}

  

红黑树的C语言实现的更多相关文章

  1. 算法导论 之 红黑树 - 删除[C语言]【转】

    转自:https://blog.csdn.net/qifengzou/article/details/17608863 作者:邹祁峰 邮箱:Qifeng.zou.job@hotmail.com 博客: ...

  2. 红黑树(四)之 C++的实现

    概要 前面分别介绍红黑树的理论知识和红黑树的C语言实现.本章是红黑树的C++实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章. 目录1. 红黑树的介绍2. 红黑树的C++ ...

  3. 红黑树(二)之 C语言的实现

    概要 红黑树在日常的使用中比较常用,例如Java的TreeMap和TreeSet,C++的STL,以及Linux内核中都有用到.之前写过一篇文章专门介绍红黑树的理论知识,本文将给出红黑数的C语言的实现 ...

  4. 红黑树的删除详解与思路分析——不同于教科书上的算法(dart语言实现)

    对于红黑树的删除,看了数据结构的书,也看了很多网上的讲解和实现,但都不满意.很多讲解都是囫囵吞枣,知其然,不知其所以然,讲的晦涩难懂. 红黑树是平衡二叉树的一种,其删除算法是比较复杂的,因为删除后还要 ...

  5. 【数据结构】红黑树 C语言代码

    连看带写花了三天,中途被指针引用搞得晕晕乎乎的. 插入和删除的调整过程没有看原理,只看了方法,直接照着写的. 看了两份资料,一份是算法导论第12-13章, 另一份是网上的资料http://blog.c ...

  6. 算法导论学习---红黑树具体解释之插入(C语言实现)

    前面我们学习二叉搜索树的时候发如今一些情况下其高度不是非常均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜 ...

  7. 红黑树插入与删除完整代码(dart语言实现)

    之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找.插入.删除等.删除后修复实现了两种算法,均比之前的更为简洁.一种是我自己的实现,代码非常简洁,行数更少:一种是Linux.Java等源码版 ...

  8. 从2-3-4树到红黑树(下) Java与C的实现

    欢迎探讨,如有错误敬请指正 如需转载,请注明出处   http://www.cnblogs.com/nullzx/ 相关博客: 从2-3-4树到红黑树(上) 从2-3-4树到红黑树(中) 1. 实现技 ...

  9. 红黑树(三)之 Linux内核中红黑树的经典实现

    概要 前面分别介绍了红黑树的理论知识 以及 通过C语言实现了红黑树.本章继续会红黑树进行介绍,下面将Linux 内核中的红黑树单独移植出来进行测试验证.若读者对红黑树的理论知识不熟悉,建立先学习红黑树 ...

随机推荐

  1. 一文了解ConfigurationConditon接口

    ConfigurationCondition 接口说明 @Conditional 和 Condition ​ 在了解ConfigurationCondition 接口之前,先通过一个示例来了解一下@C ...

  2. jQuery Validate(一)

    jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单. 但是在学习的过程中,我也遇到了疑惑,网上的很多例子貌似都是依赖jquery.metadata.js这个库, ...

  3. jquery 获取 outerHtml

    在开发过程中,jQuery.html() 是获取当前节点下的html代码,并不包括当前节点本身的代码,然后我们有时候确须要.找遍jQuery api文档也没有不论什么方法能够拿到. 看到有的人通过pa ...

  4. PHP中输出文件,怎么区别什么时候该用readfile() , fread(), file_get_contents(), fgets()

    我在服务器端(Apache环境)上放了一个安卓apk安装包的下载链接,使用readfile()读取apk文件输出下载后,手机安装apk显示解析包错误.但apk本身没问题,下载后文件的大小也是完整的.服 ...

  5. Nginx与Apache的Rewrite规则的区别

    一.Nginx Rewrite规则相关指令 Nginx Rewrite规则相关指令有if.rewrite.set.return.break等,其中rewrite是最关键的指令.一个简单的Nginx R ...

  6. 向oracle中插入date时,持久层sql怎么写???

    public class EmpDao { public void addEmp(Emp emp) throws SQLException { QueryRunner runner = new Que ...

  7. 关于海康视频采集卡的简介---基于pci的插潮采集卡

    vga 640x480 qvga vga的1/4,宽高分别是vga的一半 (1)采集类型 海康威视 DS-2CE16A2P-IT3P 700TVL 1/3" DIS ICR 红外防水筒型摄像 ...

  8. 机器学习三 -- 用Python实现K-近邻算法

    Python语言实现机器学习的K-近邻算法 写在前面 额...最近开始学习机器学习嘛,网上找到一本关于机器学习的书籍,名字叫做<机器学习实战>.很巧的是,这本书里的算法是用Python语言 ...

  9. 总是想把Linux服务器上的重要文件备份到本地,在此转一篇实现windows和linux互传文件的文章

    尝试从windows xp向ubuntu11.10传文件 ubuntu使用的是ssh windows使用的是putty和其附带的pscp 首先配置ubuntu: 1.先使用netstat -tl或se ...

  10. SQL Server里的 ISNULL 与 NULLIF(转)

    SQL Server 中有两个参数,语法:     ISNULL(check_expression, replacement_value) check_expression 与 replacement ...