Jokers's Blog

高尚是高尚者的墓志铭 卑鄙是卑鄙者的通行证


  • 首页

  • 分类

  • 归档

  • 标签

数据结构--查找

发表于 2018-11-05 | 分类于 Data Structure |

二分查找 && 利用二分查找插入

#include <stdio.h>

#define MAX 100

typedef struct{
    int key;
}Node;

typedef Node SeqList[MAX+1];

//递归二分查找
int binSearch1(SeqList R, int k, int low, int high){
    int mid;
    if(low <= high){
        mid = (low+high)/2;
        if(R[mid].key == k)
            return mid;
        if(R[mid].key > k)
            return binSearch1(R, k, low, mid-1);
        else
            return binSearch1(R, k, mid+1, high);
    }
    return 0;
}

//非递归查找
int binSearch2(SeqList R, int k, int low, int high){
    int mid;
    while(low <= high){
        mid = (low+high)/2;
        if(R[mid].key == k)
            return mid;
        if(R[mid].key > k)
            high = mid-1;
        else
            low = mid+1;
    }
    return 0;
}

//插入
void binInsert(SeqList R, int n, int k){
    int low=1, high=n,find=0, mid;
    while(low<=high && !find){
        mid = (low+high)/2;
        if(R[mid].key == k){
            find = mid;
            break;
        }
        if(R[mid].key > k)
            high = mid - 1;
        else
            low = mid + 1;
    }
    if(!find)
        find = low;
    for(int i=n; i>=find; i--){
        R[i+1] = R[i];
    }
    R[find].key = k;
}

int main(){
    SeqList R;
    int t;
    int n = 0;
    int i;
    while (1==1) {
        scanf("%d", &t);
        if(t == -9999)
            break;
        n++;
        R[n].key = t;
    }
    i = binSearch1(R, 5, 1, n);
    printf("%d\n", i);
    binInsert(R, n, 5);
    for(int j=1; j<=n+1; j++){
        printf("%d->", R[j].key);
    }
    return 0;
}

二叉排序树

#include <stdio.h>
#include <stdlib.h>

typedef struct Node{
    int data;
    struct Node \*lchild;
    struct Node \*rchild;
}BSNode;

typedef BSNode \*BSTree;


BSTree insertBSTree(BSTree bst, int k){
    if(bst == NULL){
        bst = (BSNode \*)malloc(sizeof(BSNode));
        bst->data = k;
        bst->lchild = NULL;
        bst->rchild = NULL;
    }
    BSTree lc;
    BSTree rc;
    if(k < bst->data){
        lc = insertBSTree(bst->lchild, k);
        bst->lchild = lc;
    }
    else if(k > bst->data){
        rc = insertBSTree(bst->rchild, k);
        bst->rchild = rc;
    }
    return bst;
}

void interOder(BSTree bst){
    if(bst){
        interOder(bst->lchild);
        printf("%d->", bst->data);
        interOder(bst->rchild);
    }
}

int main(){
    BSTree bst = NULL;
    int t;
    scanf("%d", &t);
    while (t != -9999) {
        bst = insertBSTree(bst, t);
        scanf("%d", &t);
    }
    interOder(bst);
    printf("\n");
    return 0;
}

并判断第n个整数在前(n-1)个整数中出现的次数

#include<stdio.h>
#define MAX 100

int main(){
    int a[MAX];
    int i=0, n, t;
    while(1==1){
        scanf("%d ", &t);
        if(t == -9999){
            break;
        }
        i++;
        a[i] = t;
    };
    for(int j=1; j<i; j++){
        if(a[j] == a[i])
            n++;
    }
    printf("第n个整数在前n-1个数中出现的次数为:%d\n", n);
    return 0;
}

数据结构--二叉树

发表于 2018-11-05 | 分类于 Data Structure |

前序序列构建二叉树

#include <stdio.h>

#define MAX 100

typedef struct Node{
    char data;
    struct Node \*lChild;
    struct Node \*rChild;
}BinTNode;

typedef BintNode \*BinTree;

int mkTree(BinTree bt, char \*str, int i){
    bt->lChild = NULL;
    bt->rChild = NULL;
    bt->data = str[i];
    printf("%c\n", bt->data);
    if(i<strlen(str)-1 && str[i+1]!='.'){
        bt->lchild = (BinTNode \*)malloc(sizeof(BinTNode));
        i = mkTree(bt->lchild, str, i+1);
    }
    i++;
    if(i<strlen(str)-1 && str[i+1]!='.'){
        bt->rchild = (BinTNode \*)malloc(sizeof(BinTNode));
        i = mkTree(bt->rchild, str, i+1);
    }
    return i;
}

<!-- 前序遍历 -->
void preSort(BintTree bt){
    if(bt){
        printf("%c->", bt->data);
        preSort(bt->lchild);
        preSort(bt->rchild);
    }
}

int main(){
    BintTree bt = (BinTNode \*)malloc(sizeof(BinTNode));
    char str[MAX];
    scanf("%s", str);
    printf("%s", str);
    mkTree(bt, str, 0);
    preSort(bt);
    return 0;
}

中后序列构建二叉树

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node{
    char data;
    struct Node \*lchild;
    struct Node \*rchild;
}BinTNode;

typedef BinTNode \*BinTree;

#define MAX 100

void mkBinTree(BinTree bt, char \*inter, int ii, int ij, char \*post, int pi, int pj){
    bt->lchild = NULL;
    bt->rchild = NULL;
    bt->data = post[pj];
    int n = 0;
    for(int i=ii; i<=ij; i++){
        if(post[pj] == inter[i]){
            n = i-ii;
            if(i>ii){
                bt->lchild = (BinTNode \*)malloc(sizeof(BinTNode));
                mkBinTree(bt->lchild, inter, ii, i-1, post, pi, pi+n-1);
            }
            if(i<ij){
                bt->rchild = (BinTNode \*)malloc(sizeof(BinTNode));
                mkBinTree(bt->rchild, inter, i+1, ij, post, pi+n, pj-1);
            }
        }
    }
}

void preOrder(BinTree bt){
    if(bt){
        printf("%c", bt->data);
        preOrder(bt->lchild);
        preOrder(bt->rchild);
    }
}

int btDepth(BinTree bt){
    if(bt == NULL)
        return 0;
    int ldepth = 0;
    int rdepth = 0;
    ldepth = btDepth(bt->lchild);
    rdepth = btDepth(bt->rchild);
    if(ldepth>rdepth)
        return ldepth+1;
    else
        return rdepth+1;
}

int main(){
    BinTree bt = (BinTNode \*)malloc(sizeof(BinTNode));
    char inter[MAX];//前序序列
    char post[MAX];//后序序列
    scanf("%s", inter);
    scanf("%s", post);
    mkBinTree(bt, inter, 0, strlen(inter)-1, post, 0, strlen(post)-1);
    preOrder(bt);
    printf("\n");
    int depth;
    depth = btDepth(bt);
    printf("%d\n", depth);
    return 0;
}

数据结构--排序

发表于 2018-11-05 | 分类于 Data Structure |

直接插入排序

#include <stdio.h>

#define MAX 1000

typedef struct{
    int key;
}Node;

typedef Node SeqList[MAX+1];

void insertSort(SeqList R, int n){
    for(int i=2; i<=n ; i++){
        R[0].key = R[i].key;
        int j;
        for(j=i-1; j>=0; j--){
            if(R[j].key <= R[i].key)
                break;
        }
        if(j < i-1){
            for(int k=i-1; k>j; k--){
                R[k+1].key = R[k].key;
            }
            R[j+1].key = R[0].key;
        }
    }
}

int main(){
    SeqList R;
    int t;
    int n = 0;
    while (1==1) {
        scanf("%d", &t);
        if(t == -9999)
            break;
        n++;
        R[n].key = t;
    }
    insertSort(R, n);
    for(int i=1; i<=n; i++){
        printf("%d->", R[i].key);
    }
    printf("\n");
    return 0;
}

冒泡排序

#include <stdio.h>

#define MAX 1000

typedef struct{
    int v;
}Seq;

typedef Seq seqList[MAX+1]

int bubbleSort(seqList R, int n){
    for(int i=2; i<=n; i++){
        int flag = 0;
        for(int j=n; i>=i; j--){
            if(R[j].v < R[j-1].v){
                R[0].v = R[j-1].v;
                R[j-1].v = R[j].v;
                R[j].v = R[0].v;
                flag = 1;
            }
        }
        if(flag == 0){
            break;
        }
    }
    return 0;
}

int main(){
    seqList R;
    int t;
    int n = 0;
    while(true){
        scanf('%d', &t);
        if(t == -9999)
            break;
        n++;
        R[n].v = t;
    }
    bubbleSort(R, n);
}

直接选择排序

#include <stdio>

#define MAX 1000

typedef struct{
    int v;
}seq;

typedef seq seqList[MAX+1];

void selectSort(seqList R, n){
    for(int i=1, i<n; i++){
        int t = i;
        for(int j=i+1; j<=n; j++){
            if(R[j].v < t){
                t = j;
            }
            if(t != i){
                R[0].v = R[i].v;
                R[i].v = R[t].v;
                R[t].v = R[0].v;
            }
        }
    }
}

int main(){
    seqList R;
    int n = 0;
    int t = 0;
    while(true){
        scanf('%d', &t);
        if(t == -9999){
            break;
        }
        n++;
        R[n].v = t;
    }
    selectSort(R, n);
    return 0;
}

数据结构--图

发表于 2018-11-05 | 分类于 Data Structure |

构建图及深度优先遍历

#include <stdio.h>

#define MAX 99

typedef struct{
    int n;
    int arcs[MAX][MAX];
}Graph;

int visited[MAX];

void DFS(Graph g, int i, int n){
    visited[i] = 1;
    printf("V%d->", i);
    for(int j=0; j<n; j++){
        if(g.arcs[i][j]==1 && visited[j]==0){
            DFS(g, j, n);
        }
    }
}

int main(){
    Graph g;
    int n;
    int i, j;
    scanf("%d", &n);
    for(i=0; i<n; i++){
        for(j=0; j<n; j++){
            g.arcs[i][j] = 0;
        }
    }
    while(true){
        scanf("%d %d", &i, &j);
        if(i==-1 && j==-1)
            break;
        g.arcs[i][j] = 1;
    }
    for(i=0; i<n; i++){
        for(j=0; j<n; j++){
            printf("%d ", g.arcs[i][j]);
        }
        printf("\n");
    }
    for(i=0; i<n; i++){
        if(!visited[i])
            DFS(g, i, n);
    }
    return 0;
}

数据结构

发表于 2018-11-05 | 分类于 Data Structure |

线性表

逻辑结构

n个数据元素构成的有限序列。有且仅有一个开始结点a(1),它没有直接前趋,仅有一直接后继。有且仅有一个终端点a(n),它没有直接后继,仅有一个直接前趋。其余结点都仅有一个直接前趋和直接后继。
数据运算定义在逻辑结构,而具体实现在存储结构上。

线性表的顺序存储结构

把线性表的结点按逻辑次序依次存放在一组连续的存储单元里。简称顺序表。
高级语言中向量或一维数组采用顺序存储,可用来描述顺序表。

# define ListSize 100
typedef int DataType;
typedef struct {
    DataType data[ListSize];
    int length;
}SeqList;
  • 插入

    void InsertList(SeqList * L, DataType x, int i){
        if(i<1 || i>L->length+1)
            Error("Position Error");
        if(L->length>=ListSize)
            Error("Overflow");
        for(int j=L->length; j>=i; j--){
            L->data[j] = L->data[j-1];
        }
        L[i-1] = x;
        L->length ++;
    }
    
  • 删除

    void DeleteList(SeqList * L, int i){
        if(i<1 || i>L->length-1){
            Error("Position Error");
        }
        for(int j=i; j<L->length; j++){
            L->data[j-1] = L->data[j];
        }
        L->length --;
    }
    

线性表的链式存储结构

顺序存储结构的插入和删除操作会移动大量结点,为避免大量结点的移动,可使用链式存储结构。链式存储还可用于各种非线形的逻辑结构。
物理存储单元的地址可以不连续,单链表每个结点除了存储值以外还要存储后继结点的地址。
c语言描述如下:

typedef char DataType;
typedef struct node{
    DataType value;
    struct node * next;
}ListNode;
typedef ListNode * LinkList;
LinkList head;
ListNode * p;

ListNode * 和 LinkList 是同一个指针类型,命名不同的目的是概念上更明确。head表示单链表的头指针,p表示结点指针。
p的值是某一节点地址,程序执行过程中生成属于动态变量,通过标准函数生成,即:

p = (ListNode * )malloc(sizeof(ListNode))
  • 头插法创建单链表

    LinkList CreateListF(){
        LinkList head;
        head = NULL;
        ListNode * s;
        char ch = getchar();
        while(ch != '\n'){
            s = (ListNode * )malloc(sieof(ListNode));
            s -> value = ch;
            s -> next = head;
            head = s;
            ch = getchar();
        }
        return head;
    }
    
  • 尾插法创建单链表

    LinkList CreateListT(){
        LinkList head;
        head = NULL;
        LinkList tail;
        tail = NULL;
        ListNode * s;
        char ch = getchar();
        while(ch != '\n'){
            s = (ListNode * )malloc(sieof(ListNode));
            s -> value = ch;
            tail -> next = s;
            tail = s;
            ch = getchar();
            if(head == NULL)
                head = s
        }
        if(r != NULL)
            r -> next = NULL;  //尾节点置空
        return head;
    }
    
  • 查找

    //按位置查找
    ListNode * GetNode(LinkList head, int i){
        int j = 0;
        ListNode p = head;
        while(j<i && p->next){
            p = p->next;
            j++;
        }
        if(j == i)
            return p;
        else
            return NULL;
    }
    
    //按值查找
    ListNode * LocateNode(LinkList head, DataType key){
        ListNode * p;
        p = head->next;
        while(p){
            if(key == p->value)
                return p;
            p = p->next;
        }
        return NULL;
    }
    
  • 插入

    void InsertList(LinkList head, DataType x, int i){
        ListNode * p = GetNode(head, i-1);
        if(p == NULL)
            Error("Position Error");
        ListNode * s = (ListNode * )malloc(sizeof(ListNode));
        s -> value = x;
        s -> next = p -> next;
        p -> next = s;
    }
    
    void DeleteList(LinkList head, int i){
        ListNode * p = GetNode(head, i-1);
        if(p == NULL || p->next==NULL)
            Error("Position Error");
        r = p->next;
        p -> next = r->next;
        free(r);
    }
    

栈和队列

逻辑结构与线性表相同,又称为运算受限的线性表。

栈

顺序栈的定义

# define StackSize 100
typedef char DataType;
typedef struct{
    DataType data[StackSize];
    int top; # 指示当前栈顶位置,又称栈顶指针
}SeqStack;

队列

顺序队列

顺序队列,分别设置队头front指针和队尾rear指针。初值均为0。当插入元素时,插入rear所指位置,rear加1。当删除元素时,删除front所指位置,front加1。可见当front==rear时,队列为空。为防止假上溢现象,将向量空间想像为首尾相接的循环向量称为循环队列。
加1操作可描述为模运算

i = (i+1)%QueueSize;

注意,循环队列front==rear时,可能是队列满
循环队列定义

# define QueueSize 100
typedef char DataType;
typedef struct{
    DataType data[QueueSize];
    int front;
    int rear;
    int count; # 区分队列空或满
} CirQueue;
  • 队列初始化

    void InitQueue(CirQueue * Q){
        Q->front = Q->rear = 0;
        Q->count = 0;
    }
    

栈和队列应用实例

  • 十进制整数N转换为B进制数

    void MultiBaseOutput(int N, int B){
        SeqStack S;
        int i;
        while(N != 0){
            push(&S, N%B);
            N = N/B #整除
        }
        while(!StackEmpty(S)){
            i = pop(&S);
            printf("%d", i);
        }
    }
    

时间复杂度为O(log(B)N)

  • 递归

递归设计步骤:1、分解为类似原问题特性的子问题。2、保证有限次递归后满足终止条件

树

树的基本概念

  • 树是一种非常重要的非线性结构
  • 一个结点拥有的子树称为该结点的度,树的度为结点最大度数。度为零的结点称为叶子结点。
  • 结点的层数从根算起,最大层数称为树的高度或深度

二叉树

  • 二叉树第i层的结点个数最多是2^(i-1)
  • 深度为k的二叉树至多有2^k-1个结点
  • 终端结点即度数为0的结点个数为n0,度数为2的结点个树是n2,有n0=n2+1
  • 满二叉树,深度位k且有2^k-1个结点
  • 完全二叉树,最底层的结点集中在左边

二叉树的链式存储

typedef char DataType;
typedef struct node{
    DataType data;
    struct node * left;
    struct node * right;
}BinTNode;
typedef BinTNode * BinTree;

二叉树的遍历

前序遍历,中序遍历,后序遍历

# 中序遍历
void Inorder(BinTree * T){
    if(T){
        Iorder(T->lchild);
        print("%c", T->data)
        Iorder(T->rchild);
    }
}

二叉树的构建

# 先序序列构建二叉树
void createBinTree(BinTree T){
    char c;
    c = getchar();
    if(c == ' '){
        T = NULL;
    }else{
        T = (BinTNode * )malloc(sizeof(BinTNode));
        T -> data = c;
        createBinTree(T -> lchild);
        createBinTree(T -> rchild);
    }   
}

层次遍历

求叶子和结点个数

图

图的基本概念

  • G = (V, E)
  • 有n(n-1)/2条边的图称为完全无向图
  • 有n(n-1)条边的图称为完全有向图
  • 无向图顶点v的度是关于该顶点边的数目,记为D(v)
  • 有向图为入度和出度
  • 边数 = (1/2)度数和
  • 无向图,若任意顶点连通,称G为连通图

图的存储结构

  • 邻接矩阵表示法

    # define MaxVertexNum 100
    typedef char VertexType;
    typedef int EdgeType;
    typedef struct{
        VertexType vexs[MaxVertexNum];
        EdgeType edges[MaxVertexNum][MaxVertexNum];
        int n, e;
    }MGraph;
    
  • 邻接矩阵无向图创建

    void createMGraph(MGraph * g){
        int i, j, k, w;
        scanf("%d%d", &g->n, &g->e);
        for(i=0; i<g->n; i++){
            g->vexs[i] = getchar();
        }
        for(i=0; i<g->e; i++){
            for(j=0; j<g->e; j++){
                g->edges[i][j] = 0;
            }
        }
        for(k=0; k<G->e; k++){
            scanf("%d%d%d", &i, &j, &w);
            g->edges[i][j] = w;
            g->edges[j][i] = w;
        }
    }
    
  • 邻接表表示法及其创建算法

    typedef struct node{
        int adjvex;
        struct node * next;
    }EdgeNode;
    
    typedef struct vnode{
        VertexType vertex;
        EdgeNode * firstdege;
    }VertexNode;
    
    typedef VertexNode AdjList[MaxVertexNum];
    
    typedef struct{
        AdjList adjList;
        int n, e;
    }ALGraph;
    
    void createALGraph(ALGraph * G){
        int i, j, k;
        scanf("%d %d", &G->n, &G->e);
        EdgeNode * s;
        for(i=0; i<G->n; i++){
            G->adjList[i].vertex = getchar();
            G->adjList[i].firstdege = NULL:
        }
        for(k=0; i<G->e; k++){
            scanf("%d %d", &i, &j);
            s = (EdgeNode * )malloc(sizeof(EdgeNode));
            s -> adjvex = i;
            s -> next = G->adjList[j].firstdege;
            G->adjList[j].firstdege = s;
            s = (EdgeNode * )malloc(sizeof(EdgeNode));
            s -> adjvex = j;
            s -> next = G->adjList[i].firstdege;
            G->adjList[i].firstdege = s;
        }
    }
    

图遍历

  • 深度优先遍历–邻接表

    Boolean visited[MaxVertexNum];
    
    void DFSTraverse(ALGraph * G){
        for(int i=0; i<G->n; i++)
            visited[i] = FALSE;
        for(int j=0; j<G->n; j++){
            if(!visited[j])
                DFS(G, j);
        }
    }
    
    void DFS(ALGraph * G, int i){
        printf("%c", G->adjList[i].vertex);
        visited[i] = TRUE;
        EdgeNode * p = G->adjList[i].firstdege;    
        while(p){
            if(!visited(p->adjvex)){
                DFS(G, p->adjvex);
            }
            p = p->next;
        }
    }
    
  • 深度优先遍历–邻接矩阵

    int visited[MaxVertexNum];
    void DFTraversal(MGraph * g){
        int i;
        for(i=0; i<g->n; i++){
            visited[i] = 0;
        }
        for(i=0; i<g->n; i++){
            if(visited[i] == 0){
                DFS(g, i);
            }
        }
    }
    void DFS(MGraph * g, i){
        int j;
        printf("%c", g->vexs[i]);
        visited[i] = 1;
        for(j=1; j<g->n, j++){
            if(g->edges[i][j] != 0 && visited[i] == 0){
                DFS(g, j);
            }
        }
    }
    
  • 广度优先遍历–邻接表

    Boolean visited[MaxVertexNum];
    
    void DFSTraverse(ALGraph * G){
        for(int i=0; i<G->n; i++)
            visited[i] = FALSE;
        for(int j=0; j<G->n; j++){
            if(!visited[j])
                DFS(G, j);
        }
    }
    
    void DFS(ALGraph * G, int i){
        printf("%c", G->adjList[i].vertex);
        visited[i] = TRUE;
        EnQueue(&Q, i);
        EdgeNode * p;
        while(!QueueEmpty(&Q)){
            i = DeQueue(&Q);
            p = G->adjList[i].firstdege;
            while(p){
                if(!visited(p->adjvex)){
                    printf("%c", G->adjList[p->adjvex].vertex);
                    visited[p->adjvex] = TRUE;
                    EnQueue(&Q, i);
                }
                p = p->next;
            }
        }
    }
    
  • 广度优先遍历–邻接矩阵

    int visited[MaxVertexNum];
    void DFTraversal(MGraph * g){
        int i;
        for(i=0; i<g->n; i++){
            visited[i] = 0;
        }
        for(i=0; i<g->n; i++){
            if(visited[i] == 0){
                BFS(g, i);
            }
        }
    }
    void BFS(MGraph * g, i){
        int j;
        printf("%c", g->vexs[i]);
        visited[i] = 1;
        EnQueue(i); //队列,先进先出
        while(!QueueEmpty()){
            i = DeQueue();
            for(j=1; j<g->n, j++){
                if(g->edges[i][j] != 0 && visited[i] == 0){
                    printf("%c", g->vexs[j]);
                    EnQueue(j);
                }
            }
        }
    }
    

排序

插入排序

  • 直接插入排序

    # define n 100
    typedef struct{
        int key;
    }RecType;
    
    typedef RecType SeqList[n+1];
    
    void insertSort(SeqList R){
        int i, j, k;
        // 循环
        for(i=2; i<=n; i++){
            R[0].key = R[i].key;
            for(j=i-1; j>=0; j--){
                if(R[j].key <= R[i].key){
                    break;
                }
            }
            if(j < i-1){
                for(k=i-1; k>j; k--){
                    R[k+1].key = R[k].key;
                }
                R[j+1].key = R[0].key;
            }
        }
    }
    
  • 希尔排序

交换排序

  • 冒泡

    void BubbleSort(SeqList R){
        int i, j;
        Boolean exchange;
        for(i=1; i<n; i++){
            exchange = FALSE;
            for(j=n; j>i; j--){
                if(R[j]<R[j-1]){
                    R[0] = R[j-1];
                    R[j-1] = R[j];
                    R[j] = R[0];
                    exchange = TRUE;
                }
            }
            if(!exchange)
                break;
        }
    }
    
  • 快速排序

    void QuickSort(SeqList R, int low, int high){
        int pivotpos;
        if(low < high){
            pivotpos = Partition(R, low, high);
            QuickSort(R, low, pivotpos-1);
            QuickSort(R, pivotpos+1, high)
        }
    }
    
    void Partition(SeqList R, int i, int j){
        RecType pivot = R[i];
        while(i<j){
            while(i<j && R[j]>=pivot){
                j--;
            }
            if(i<j){
                R[i] = R[j];
                i++;
            }
            while(i<j && R[i]<=pivot){
                i++;
            }
            if(i<j){
                R[j] = R[i];
                j--;
            }
        }
        R[i] = pivot;
        return i;
    }
    

选择排序

  • 直接选择排序

    void selectSort(SeqList R){
        int i, j, k;
        for(i=1; i<n; i++){
            k = i;
            for(j=i+1; j<=n; j++){
                if(R[j] < R[k]){
                    k = j;
                }
            }
            if(k != i){
                R[0] = R[i];
                R[i] = R[k];
                R[k] = R[0];
            }
        }
    }
    
  • 堆排序

    void HeapSort(SeqList R){
        int i;
        BuidHeap(R);
        for(i=n; i>1; i--){
            R[0] = R[1];
            R[1] = R[i]
            R[i] = R[0];
            Heapify(R, 1, i-1);
        }
    }
    
    void Heapify(SeqList R, int low, int high){
        while(low <= high){
            tmp = 2*low;
            if(R[low]>=R[tmp] && R[low]>=R[tmp+1])
                break;
            if(tmp+1<=high && R[tmp]<R[tmp+1])
                tmp ++;
            t = R[low];
            R[low] = R[tmp];
            R[tmp] = t;
            low = tmp;
        }
    }
    
    void BuidHeap(SeqList R){
        for(int i=n/2; i>=1; i--)
            Heapify(R, i, n)
    }
    

归并排序

void Merge(SeqList R, int low, int m, int high){
    // R[low...m]和R[m+1...high]为有序序列
    RecType * R1 = (RecType * )malloc((high-low+1)* sizeof(RecType));
    int i = low;
    int j = m+1;
    int p = 0;
    while(i<=m && j<=high)
        R1[p++] = (R[i]<=R[j]):R[i++]?R[j++];
    while(i<=m)
        R1[p++] = R[i++];
    while(j<=high)
        R1[p++] = R[j++];
    for(p=0,i=low; i<=high; i++, p++){
        R[i] = R1[p];   
    }
}

// 自顶向下
void MergeSortDC(SeqList R, int low, int high){
    int mid;
    if(low < high){
        mid = (low + high)/2;
        MergeSortDC(R, low, mid);
        MergeSortDC(R, mid+1, high);
        Merge(R, low, mid, high);
    }
}

数据结构--多维数组

发表于 2018-11-05 | 分类于 Data Structure |

三角矩阵 && 矩阵乘积

#include <stdio.h>

#define MAX 1000

void matMulti(int \*A, int \*B, int n){
    int C[n][n];
    int i, j, s;
    int index_A = 0, index_B = 0;
    for(i=0; i<n; i++){
        for(j=0; j<n; j++){
            C[i][j] = 0;
        }
    }
    for(i=0; i<n; i++){
        for(j=0; j<n; j++){
            s=0;
            for(int k=0; k<n; k++){
                if(i<k || j<k)
                    continue;
                index_A = i*(i+1)/2 + k;
                index_B = k*(2*n-k+1)/2 + j -k;
                printf("A:%d B:%d\n", A[index_A], B[index_B]);
                s += A[index_A]\*B[index_B];
            }
            C[i][j] = s;
        }
    }
    for(i=0; i<n; i++){
        for(j=0; j<n; j++){
            printf("%d ", C[i][j]);
        }
        printf("\n");
    }
}

int main(){
    // 上三角矩阵A, 下三角矩阵
    int A[MAX], B[MAX];
    // 矩阵数据长度
    int i=0, j=0;
    // 矩阵阶数
    int n1=0, n2=0;
    int flag1=1, flag2=1;
    int tmp;
    while (1 == 1) {
        scanf("%d", &tmp);
        if(tmp == -9999)
            break;
        A[i] = tmp;
        i++;
        flag1--;
        if(flag1 == 0){
            n1++;
            flag1=n1+1;
        }
    }
    while (1 == 1) {
        scanf("%d", &tmp);
        if(tmp == -9999)
            break;
        B[j] = tmp;
        j++;
        flag2--;
        if(flag2 == 0){
            n2++;
            flag2=n2+1;
        }
    }
    printf("%d %d\n", i, n1);
    printf("%d %d\n", j, n2);
    matMulti(A, B, n1);
}

计算机网络原理

发表于 2018-10-21 | 分类于 基础知识 |

第三章 传输层

TCP拥塞控制

TCP拥塞控制不基于拥塞状态反馈(丢弃分组,警告位),是与网络层拥塞控制的区别。TCP拥塞控制通过超时和三次重复确认推断拥塞。拥塞控制算法有慢启动、拥塞避免、快速恢复和快速重传。涉及到发送端的一个变量拥塞窗口CongWin。在慢启动阶段,每接收到一个ACK,CongWin加一个MSS数值,在一个RTT后翻倍。CongWin超过初始阈值Threshold进入在拥塞避免阶段,每个RTT,ConWin加1。一旦推断拥塞,Threshold=CongWin/2,CongWin=1,进入慢启动。反映了加性增加和乘性减小。后期引入快送重传和快速恢复算法,快速重传就是发生三次重复确认,重传报文段。快速恢复区别对待超时和三次重复确认,对发生三次重复确认,只是从新的阈值开始进入拥塞避免阶段。

第四章 网络层

网络层服务

  • 转发
  • 路由选择
    路由选择算法计算路由,将路由信息存储到路由转发表,转发分组时查询转发表并转发分组。
  • 连接建立

数据报网络和虚电路网络

  • 是否面向连接
  • 虚电路网络又分为永久型和交换型(更具需要临时建立)
  • 数据报网络和虚电路网络的主要区别是顺序控制、流量控制和差错控制是由网络完成还是端系统完成。

网络互联与网络互联设备

异构网络互联的方式

  • 协议转换
  • 构建虚拟互联网络,使用虚拟互联网络设备转发分组。
    IP网络就是虚拟互联网络,Internet是最大的IP网络,网络层协议–IP,网络询址–IP地址,网络互联设备–路由器

    路由器

  • 每个输入端口都有路由转发表的副本和缓存功能
  • 输入端口到输出端口分组的转发,由交换结构完成

    交换结构的实现方式:

  • 基于内存交换,性能低,便宜
  • 基于总线交换,无需处理器介入,总线具有独占特性
  • 基于网络交换,可以并行交换,但是对同一输出端口的交换是串行的

    路由转发转发原则

    路由转发时,有多条路由项匹配成功,选择网络前缀匹配成功最长的路由项,最长前缀匹配优先原则

网络层拥塞控制

拥塞控制和流量控制的区别

流量控制是发送方根据接受方的缓存和数据处理的能力调整数据发送速率和发送量。拥塞控制是根据网络通过能力或拥挤程度调节速率和发送量。

几种常用的网络层的拥塞控制措施

  • 流量感知路由,拥塞预防措施
  • 准入控制,是否允许构建虚电路
  • 流量调节,通过抑制分组,直接告知发送方。背压,在发往发送方的路径中,每一跳都抑制输出,优点是快速缓解拥塞,缺点是每一跳都需要更大的缓存。
  • 负载脱落,选择丢弃数据包,丢弃哪些数据包取决于上层应用

Internet网络层

IP数据报分片与重组

  • 不同链路层协议MTU不同,因此需要对数据报进行分片。
  • 重组是,根据标识字段判断是否属于同一数据报,标志字段的MF判断是否最后一个分片,偏移字段表示顺序,长度字段判断是否有分片丢失。

IPv4编址,32位

基于IP子网的概念将IP地址划分为两部分,前缀即网络部分,后缀即主机部分。

  • 分类地址
    前缀长度 前缀
    A 8 0XXXXXXXX
    B 16 10XXXXXXXXXXXXXXXX
    C 24 110XXXXXXXXXXXXXXXXXXXXXXXX
    D 1110XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    E 11110XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  • 无类地址
    只有给出子网地址、子往前缀或子网掩码才能准确描述子网规模
    给定子网内某地址,与子网掩码做按位与运算获得子网地址,与子网掩码的反码按位或运算可得直接广播地址
    子网的可用IP地址总数要减去子网地址和广播地址

    路由聚合

    路由聚合技术缩减路由表项,有效提高查询效率

    动态主机配置协议DHCP

    动态分配IP地址,应用层实现,传输层使用UDP
    分配过程
  • DHCP发现,目的IP,255.255.255.255,源IP,0.0.0.0
  • DHCP服务器提供,广播发送
  • DHCP请求,广播发送,因为可能存在多个DHCP服务器
  • DHCP确认

    网络地址转换NAT

  • NAT通过替换进出内部似有网络的IP数据包的IP地址和端口号,实现使用私有地址的主机与互联网通信。NAT运行在边缘路由器,维护NAT转换表。
  • 私有地址主机如果希望被动接受外网主机访问,需要NAT穿透

    ICMP,网络控制报文协议

    封装在IP数据报中,实现主机和路由器之间的差错报告和网络探测。分为差错报告报文和询问报文两大类。Ping,Traceroute

    IPv4到IPv6的迁移

  • 双协议栈,同时支持两种协议,使用DNS查询返回地址区分服务端支持的协议
  • 隧道,客户服务器都使用IPv6但中间路由器不支持怎么办,在进入隧道前的最后一个IPv6路由器上封装称IPv4数据报,目的地址是隧道出口第一个IPv6路由器。

    路由选择算法

  • 全局式路由选择算法,LS(链路状态)
  • 分布式路由选择算法,DV(距离向量)
  • 层次化路由选择

    Internet路由选择协议

  • RIP(路由信息协议)
    内部外观协议,DV
  • OSPF(开放式最短路径优先协议)
    内部外观协议,LS
  • BGP(边界网关协议)
    外部网关协议,DV

第五章 数据链路层与局域网

差错控制

噪声分类

  • 随机噪声引起差错
  • 冲击噪声引起突发差错

差错控制基本方式

  • 检错重发,停等协议和滑动窗口协议
  • 前向纠错FEC
  • 反馈校验,将发送端的数据再发回去
  • 检错丢弃,允许一定差错存在

差错编码

信息位后附加冗余位,信息位与冗余码符合一定关系式

检错和纠错能力

分类

  • 奇偶校验码
  • 汉明码
    信息位k 校验位r
    2^r >= k+r+1
  • CRC

多路访问控制协议

链路信道分为单播和广播信道,广播信道被所有结点共享,必须采用MAC控制结点信息发送

信道划分MAC协议

多路复用技术
  • 频分多路复用
  • 时分多路复用
    同步时分多路复用。异步时分多路复用又称统计时分多路复用,大多用于现代计算机广域传输。
  • 波分多路复用
    在光纤通信上的频分多路复用
  • 码分多路复用

    随机访问MAC协议

  • 纯ALOHA协议
    无线信道共享接入,任一站点有发送信息的需要立即发送,监听一段时间,没有接收站的回应则表示发送成功,否则等待随机时间后重发。
  • 时隙ALOHA协议
    信道时间划分离散的时隙,每个时隙等于发送一帧所需要的时间,在每个时隙开始阶段发送,出现冲突后下一个时隙以概率P重发该帧
  • CSMA,载波监听多路访问协议
    利用载波监听装置在数据发送之前监听其它站点是否在发送数据。又分为非坚持CSMA(信道忙等待随机时间再监听),1-坚持CSMA(信道忙继续监听直到空闲立即发送数据),P-坚持CSMA(分割时隙,信道空闲以概率P在时隙开始时间发送)
  • CSMA/CD,带冲突检测的载波监听多路访问协议
    发送数据的同时,监听信道,一旦发生冲突立即停止发送,并发出冲突强化信号,使得所有站点都知道冲突发生。L是数据帧最小长度,R是传输速率,D是两站最远距离,V是传播速度,则L/R>=2D/V。

    受控接入MAC

  • 集中式控制
    轮叫轮询,传递轮询。主机一旦故障,网络瘫痪
  • 分散式控制
    令牌环网

    受控接入MAC协议

局域网

数据链路层寻址

MAC地址
  • 交换机接口没有MAC地址
  • 帧的转发由交换机查找交换表转发相应端口,如果目的MAC地址是接收端口则丢弃。
  • MAC地址是6个字节,第一个字节的倒数第二位是G/L位,为1时表示本地管理,位0时表示全球管理。
  • 广播MAC地址全为1
    ARP,地址解析协议
  • 每台主机有ARP高速缓存,存储MAC地址和IP地址的映射关系。
  • 每个主机和路由器都有ARP模块,通过广播ARP查询报文可以得到IP地址对应MAC地址
  • 如果主机和目的主机不在同一个子网,ARP解析默认网关MAC地址,作为目的MAC地址
  • ARP查询分组是广播帧发送,响应分组是单播帧
    ARP与DNS的区别
  • ARP是IP地址与MAC地址的映射关系,DNS是域名和IP地址的映射关系
  • ARP是为子网内主机解析IP地址,DNS是为整个互联网解析主机域名
  • DNS是在域名服务器间查询,ARP是在局域网内广播ARP查询

    以太网

    802.3协议,第一个广泛部署的告诉局域网,CSMA/CD,曼策斯特编码,提供无连接不可靠服务
  • 10Base-5 经典的同轴电缆总线型以太网
  • 10Base-T 非屏蔽双绞线UTP
  • 100Base-T 快速以太网
  • 100Base-TX 5类UTP
  • 100Base-T4 3、4、5类UTP
  • 100Base-TF 光缆
  • 1000Base-SX/LX 千兆以太网,光纤传输介质
  • 1000Base-T 5类UTP
  • 万兆以太网 扩展了传输速率和距离,开始应用于城域网和广域网

    交换机

  • 交换机就是多端口的网桥。依据目的MAC地址,选择性的转发端口,这就是转发与过滤功能
  • 交换机的选择性转发,实现了冲突域的分割。10M以太网,10个用户使用,若使用交换机连接,交换机的总容量相当于100M
  • 交换机的交换表是通过逆向学习逐步构建的
  • 交换机是一种即插即用的设备,采用专用的交换结构芯片,其转发速率比软件转发的网桥快得多
  • 交换机的优点,消除冲突、支持异质链路和网络管理(可以检测到异常适配器并切断

    虚拟局域网 VLAN

    为限制广播域的规模,抑制广播风暴,可以使用路由器分割子网,或则构建虚拟局域网,基于交换机的逻辑分割,通过软件方式实现
    主要方法
  • 基于交换机的端口
  • 基于MAC地址划分
  • 基于上层协议类型或地址划分,有利于组成基于应用的VLAN

物理层

无线网

网络安全

ngrok

发表于 2018-09-20 | 分类于 Tools |

Intro

The plan is to create a pair of executables (ngrok and ngrokd) that are connected with a self-signed SSL cert. Since the client and server executables are paired, you won’t be able to use any other ngrok to connect to this ngrokd, and vice versa.

DNS

Add two DNS records: one for the base domain and one for the wildcard domain. For example, if your base domain is domain.com, you’ll need a record for that and for *.domain.com.

Different Operating Systems

If the OS on which you’ll be compiling ngrok (that’s the server section below) is different than the OS on which you’ll be running the client, then you will need to set the GOOS and GOARCH env variables. I run Linux everywhere, so I don’t know how to do that. Please Google it or see the discussion here. If you know how to do this and want to add GOOS/GOARCH instructions here, please let me know.

On Server

MAKE SURE YOU SET NGROK_DOMAIN BELOW. Set it to the base domain, not the wildcard domain.

NGROK_DOMAIN="my.domain.com"
git clone https://github.com/inconshreveable/ngrok.git
cd ngrok

openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csr
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000

cp rootCA.pem assets/client/tls/ngrokroot.crt
# make clean
make release-server release-client

Copy bin/ngrok to whatever computer you want to connect from. Then start the server:

bin/ngrokd -tlsKey=device.key -tlsCrt=device.crt -domain="$NGROK_DOMAIN" -httpAddr=":8000" -httpsAddr=":8001"

On Client

MAKE SURE YOU SET NGROK_DOMAIN BELOW. Set it to the base domain, not the wildcard domain.

NGROK_DOMAIN="my.domain.com"
echo -e "server_addr: $NGROK_DOMAIN:4443\ntrust_host_root_certs: false" > ngrok-config
./ngrok -config=ngrok-config 80

Or for SSH forwarding: ./ngrok -config=ngrok-config –proto=tcp 22

Define a fixed TCP listen port

Set port number to the remote_port args. Be sure to pay attention to the format

tunnels:
  mysql:
    proto:
      tcp:3306
    remote_port: 36799

Run ngrok client with -config

Create an ngrok configuration file, “debug.yml” with the following contents:

server_addr: ngrok.domain.com:4443
trust_host_root_certs: false
tunnels:
  ssh:
    proto:
      http: 22
    subdomain: 22
  mysql:
    proto:
      tcp: 3306
    remote_port: 36799

Then run ngrok

./bin/ngrok -config=debug.yml -log=stdout start-all

Linux 安装 Chrome

发表于 2018-09-10 | 分类于 Linux |

添加仓库来源

  • 在 /etc/yum.repos.d/ 目录新建 repo file

    vi /etc/yum.repos.d/google-chrome.repo
    
  • 复制以下仓库信息

    [google-chrome]
    name=google-chrome
    baseurl=http://dl.google.com/linux/chrome/rpm/stable/x86_64
    enabled=1
    gpgcheck=1
    gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
    
  • 没有翻墙代理无法访问gpgkey怎么办

    # 找一台能翻墙的电脑下载 linux_signing_key.pub
    gpgkey=file:///dir/linux_signing_key.pub
    

安装

yum install -y google-chrome-stable
or
yum install -y google-chrome-beta

踩到的坑

测试运行 google-chrome -version 报错

/usr/bin/google-chrome-stable: symbol lookup error: /lib64/libpango-1.0.so.0: undefined symbol: g_log_structured_standard

解决

yum install pango-devel

Flask使用

发表于 2018-08-28 | 分类于 Flask |

前言

所有Web框架的使用都有自己的套路,作为一个框架本质就是一个工具。

安装

pip install Flask

自动安装的依赖

  • Werkzeug 应用及服务间的标准接口
  • Jinja 模板
  • MarkupSafe Jinja附带,防止注入攻击
  • ItsDangerous 数据完整性,保护 session cookie 安全
  • Click 命令行应用框架

可选安装的依赖

  • Blinker provides support for Signals
  • SimpleJSON fast JSON
  • python-dotenv
  • Watchdog

Virtual environments

  • 创建
    $ mkdir myproject
    $ cd myproject
    $ python3 -m venv venv
  • 激活
    $ . venv/bin/activate

简单示例

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
return 'Hello, World!'
  • 运行,设置环境变量 FLASK_APP
    $ FLASK_APP=hello.py flask run
    
  • 监听公共 IP ,确保 debugger 模式已关
    flask run --host=0.0.0.0
    

Debug Mode

export FLASK_ENV=development
or FLASK_APP=hello.py FLASK_ENV=development flask run

Variable Rules

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    # show the subpath after /path/
    return 'Subpath %s' % subpath

URL 结尾斜线

  • 不带斜线访问,会 redirects 到带斜线的 URL
    @app.route('/projects/')
    def projects():
        return 'The project page'
    
  • 带斜线访问,会返回404,避免搜索引擎索引同一个页面两次
    @app.route('/about')
    def about():
        return 'The about page'
    

HTTP Methods

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
    return do_the_login()
else:
    return show_the_login_form()

URL 构建

from flask import Flask, url_for

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

@app.route('/login')
def login():
    return 'login'

@app.route('/user/<username>')
def profile(username):
    return '{}\'s profile'.format(username)

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))

/
/login
/login?next=/
/user/John%20Doe

Static Files

在项目下创建 static 目录,存放 static files ,对于 url_for ,static 是保留字,用于生成指向 static 目录下的 URL

url_for('static', filename='style.css')

Rendering Templates

Flask 自动配置Jinja2 template engine. Flask 自动去 templates 目录查找 template

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)

The Request Object

from flask import request

@app.route('/login', methods=['POST', 'GET'])
def login():
    error = None
    if request.method == 'POST':
        if valid_login(request.form['username'],
                       request.form['password']):
            return log_the_user_in(request.form['username'])
        else:
            error = 'Invalid username/password'
    # the code below is executed if the request method
    # was GET or the credentials were invalid
    return render_template('login.html', error=error)
  • 获取 form data, 使用 form 属性
  • 获取 parameters submitted in the URL (?key=value), request.args.get(‘key’, ‘’)

File Uploads

enctype=”multipart/form-data”

from flask import request

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
    f = request.files['the_file']
    f.save('/var/www/uploads/uploaded_file.txt')
...
  • 使用客户端的文件名存储在服务端,可以使用 secure_filename() 获取文件名

    from flask import request
    from werkzeug.utils import secure_filename
    
    @app.route('/upload', methods=['GET', 'POST'])
        def upload_file():
        if request.method == 'POST':
        f = request.files['the_file']
        f.save('/var/www/uploads/' + secure_filename(f.filename))
    

Cookies

  • 读

    from flask import request
    
    @app.route('/')
    def index():
        username = request.cookies.get('username')
        # use cookies.get(key) instead of cookies[key] to not get a
        # KeyError if the cookie is missing.
    
  • 写

    from flask import make_response

    @app.route(‘/‘)
    def index():

    resp = make_response(render_template(...))
    resp.set_cookie('username', 'the username')
    return resp
    
  • 通常 Flask 自动转换返回值为 response objects ,如果自己想明确的指定 response 需要使用 make_response()

redirect() abort()

from flask import abort, redirect, url_for

@app.route('/')
def index():
    return redirect(url_for('login'))

@app.route('/login')
def login():
    abort(401)
    this_is_never_executed()
  • 使用 errorhandler() decorator 自定义 error page

    from flask import render_template
    
    @app.errorhandler(404)
    def page_not_found(error):
        return render_template('page_not_found.html'), 404
    

Sessions

  • set a secret key

    from flask import Flask, session, redirect, url_for, escape, request
    
    app = Flask(__name__)
    
    # Set the secret key to some random bytes. Keep this really secret!
    app.secret_key = b'\_5#y2L"F4Q8z\n\xec]/'
    
    @app.route('/')
    def index():
        if 'username' in session:
            return 'Logged in as %s' % escape(session['username'])
        return 'You are not logged in'
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            session['username'] = request.form['username']
            return redirect(url_for('index'))
        return '''
            <form method="post">
                <p><input type=text name=username>
                <p><input type=submit value=Login>
            </form>
        '''
    
    @app.route('/logout')
    def logout():
        # remove the username from the session if it's there
        session.pop('username', None)
        return redirect(url_for('index'))
    
  • escape(), 如果不使用模板引擎,escape 可转换 html 特殊字符

  • generate good secret keys, os.urandom(16)

Logging

app.logger.debug('A value for debugging')
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')

部署

  • Flask 自带 wsgi 扩展性能不好,仅适用于开发环境
  • WSGI HTTP Server 可选的有 Gunicorn 和 uWSGI
  • Nginx 作为静态文件访问容器和反向代理、分布式环境下作负载均衡

Gunicorn

  • 安装

    $ pip install gunicorn
    
  • Async Workers
    Gunicorn 默认同步 Workers ,通常我们还需要安装 Eventlet 或则 Gevent ,实现异步 Workers 。greenlet 是默认安装的。eventlet 和 gevent 性能差不多,可以选一个安装。

    $ pip install greenlet            # Required for both
    $ pip install eventlet            # For eventlet workers
    $ pip install gunicorn[eventlet]  # Or, using extra
    $ pip install gevent              # For gevent workers
    $ pip install gunicorn[gevent]    # Or, using extra
    
  • 运行

    gunicorn --workers=2 --worker-class=eventlet hello:app
    
  • 其它参数

    -c CONFIG, --config=CONFIG  Specify a config file in the form $(PATH), file:$(PATH), or python:$(MODULE_NAME).
    -b BIND, --bind=BIND - Specify a server socket to bind. Server sockets can be any of $(HOST), $(HOST):$(PORT), or unix:$(PATH). An IP is a valid $(HOST).
    -n APP_NAME, --name=APP_NAME - If setproctitle is installed you can adjust the name of Gunicorn process as they appear in the process system table (which affects tools like ps and top).
    

布署 Gunicorn

12345
Jokers

Jokers

hlxstc680@gmail.com

49 日志
13 分类
6 标签
© 2019 Jokers
由 Hexo 强力驱动
主题 - NexT.Muse