浙大MOOC_C语言代码

线性表的C代码

typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
 
/* 查找 */
#define ERROR NULL
Position Find(List L, ElementType X)
{
    Position p = L; /* p 指向 L 的第 1 个结点 */
 
    while (p && p->Data!=X )
        p = p->Next;
 
    /* 下列语句可以用 return p; 替换 */
    if (p)
        return p;
    else
        return ERROR;
}
/* 带头结点的插入 */
/* 注意: 在插入位置参数 P 上与课程视频有所不同,课程视频中 i 是序列位序(从 1 开始),这里 P 是链表结点指针,在 P 之前插入新结点 */
bool Insert(List L, ElementType X, Position P)
{ /* 这里默认 L 有头结点 */
    Position tmp, pre;
 
    /* 查找 P 的前一个结点 */        
    for (pre=L; pre&&pre->Next!=P; pre=pre->Next ) ;            
    if (pre==NULL) { /* P 所指的结点不在 L 中 */
        printf("插入位置参数错误 \ n");
        return false;
    }
    else { /* 找到了 P 的前一个结点 pre */
        /* 在 P 前插入新结点 */
        tmp = (Position)malloc(sizeof(struct LNode)); /* 申请、填装结点 */
        tmp->Data = X; 
        tmp->Next = P;
        pre->Next = tmp;
        return true;
    }
}
/* 带头结点的删除 */
/* 注意: 在删除位置参数 P 上与课程视频有所不同,课程视频中 i 是序列位序(从 1 开始),这里 P 是拟删除结点指针 */
bool Delete(List L, Position P)
{ /* 这里默认 L 有头结点 */
    Position tmp, pre;
 
    /* 查找 P 的前一个结点 */        
    for (pre=L; pre&&pre->Next!=P; pre=pre->Next ) ;            
    if (pre==NULL || P==NULL) { /* P 所指的结点不在 L 中 */
        printf("删除位置参数错误 \ n");
        return false;
    }
    else { /* 找到了 P 的前一个结点 pre */
        /* 将 P 位置的结点删除 */
        pre->Next = P->Next;
        free(P);
        return true;
    }
}

栈的C代码

顺序

typedef int Position;
struct SNode {
    ElementType *Data; /* 存储元素的数组 */
    Position Top;      /* 栈顶指针 */
    int MaxSize;       /* 堆栈最大容量 */
};
typedef struct SNode *Stack;
 
Stack CreateStack( int MaxSize )
{
    Stack S = (Stack)malloc(sizeof(struct SNode));
    S->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
    S->Top = -1;
    S->MaxSize = MaxSize;
    return S;
}
 
bool IsFull(Stack S)
{
    return (S->Top == S->MaxSize-1);
}
 
bool Push(Stack S, ElementType X)
{
    if (IsFull(S) ) {
        printf("堆栈满");
        return false;
    }
    else {
        S->Data[++(S->Top)] = X;
        return true;
    }
}
 
bool IsEmpty(Stack S)
{
    return (S->Top == -1);
}
 
ElementType Pop(Stack S)
{
    if (IsEmpty(S) ) {
        printf("堆栈空");
        return ERROR; /* ERROR 是 ElementType 的特殊值,标志错误 */
    }
    else 
        return (S->Data[(S->Top)--] );
}

链表

typedef struct SNode *PtrToSNode;
struct SNode {
    ElementType Data;
    PtrToSNode Next;
};
typedef PtrToSNode Stack;
 
Stack CreateStack( ) 
{ /* 构建一个堆栈的头结点,返回该结点指针 */
    Stack S;
 
    S = malloc(sizeof(struct SNode));
    S->Next = NULL;
    return S;
}
 
bool IsEmpty (Stack S)
{ /* 判断堆栈 S 是否为空,若是返回 true;否则返回 false */
    return (S->Next == NULL );
}
 
bool Push(Stack S, ElementType X)
{ /* 将元素 X 压入堆栈 S */
    PtrToSNode TmpCell;
 
    TmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
    TmpCell->Data = X;
    TmpCell->Next = S->Next;
    S->Next = TmpCell;
    return true;
}
 
ElementType Pop(Stack S)  
{ /* 删除并返回堆栈 S 的栈顶元素 */
    PtrToSNode FirstCell;
    ElementType TopElem;
 
    if(IsEmpty(S) ) {
        printf("堆栈空"); 
        return ERROR;
    }
    else {
        FirstCell = S->Next; 
        TopElem = FirstCell->Data;
        S->Next = FirstCell->Next;
        free(FirstCell);
        return TopElem;
    }
}

队列的C代码

顺序

typedef int Position;
struct QNode {
    ElementType *Data;     /* 存储元素的数组 */
    Position Front, Rear;  /* 队列的头、尾指针 */
    int MaxSize;           /* 队列最大容量 */
};
typedef struct QNode *Queue;
 
Queue CreateQueue( int MaxSize )
{
    Queue Q = (Queue)malloc(sizeof(struct QNode));
    Q->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
    Q->Front = Q->Rear = 0;
    Q->MaxSize = MaxSize;
    return Q;
}
 
bool IsFull(Queue Q)
{
    return ((Q->Rear+1)%Q->MaxSize == Q->Front);
}
 
bool AddQ(Queue Q, ElementType X)
{
    if (IsFull(Q) ) {
        printf("队列满");
        return false;
    }
    else {
        Q->Rear = (Q->Rear+1)%Q->MaxSize;
        Q->Data[Q->Rear] = X;
        return true;
    }
}
 
bool IsEmpty(Queue Q)
{
    return (Q->Front == Q->Rear);
}
 
ElementType DeleteQ(Queue Q)
{
    if (IsEmpty(Q) ) { 
        printf("队列空");
        return ERROR;
    }
    else  {
        Q->Front =(Q->Front+1)%Q->MaxSize;
        return  Q->Data[Q->Front];
    }
}

链表

typedef int Position;
struct QNode {
    ElementType *Data;     /* 存储元素的数组 */
    Position Front, Rear;  /* 队列的头、尾指针 */
    int MaxSize;           /* 队列最大容量 */
};
typedef struct QNode *Queue;
 
Queue CreateQueue( int MaxSize )
{
    Queue Q = (Queue)malloc(sizeof(struct QNode));
    Q->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType));
    Q->Front = Q->Rear = 0;
    Q->MaxSize = MaxSize;
    return Q;
}
 
bool IsFull(Queue Q)
{
    return ((Q->Rear+1)%Q->MaxSize == Q->Front);
}
 
bool AddQ(Queue Q, ElementType X)
{
    if (IsFull(Q) ) {
        printf("队列满");
        return false;
    }
    else {
        Q->Rear = (Q->Rear+1)%Q->MaxSize;
        Q->Data[Q->Rear] = X;
        return true;
    }
}
 
bool IsEmpty(Queue Q)
{
    return (Q->Front == Q->Rear);
}
 
ElementType DeleteQ(Queue Q)
{
    if (IsEmpty(Q) ) { 
        printf("队列空");
        return ERROR;
    }
    else  {
        Q->Front =(Q->Front+1)%Q->MaxSize;
        return  Q->Data[Q->Front];
    }
}

二叉树的结构

typedef struct TNode *Position;
typedef Position BinTree; /* 二叉树类型 */
struct TNode{ /* 树结点定义 */
    ElementType Data; /* 结点数据 */
    BinTree Left;     /* 指向左子树 */
    BinTree Right;    /* 指向右子树 */
};

二叉树的遍历

void InorderTraversal(BinTree BT)
{
    if(BT) {
        InorderTraversal(BT->Left );
        /* 此处假设对 BT 结点的访问就是打印数据 */
        printf("%d", BT->Data); /* 假设数据为整型 */
        InorderTraversal(BT->Right );
    }
}
 
void PreorderTraversal(BinTree BT)
{
    if(BT) {
        printf("%d", BT->Data );
        PreorderTraversal(BT->Left );
        PreorderTraversal(BT->Right );
    }
}
 
void PostorderTraversal(BinTree BT)
{
    if(BT) {
        PostorderTraversal(BT->Left );
        PostorderTraversal(BT->Right );
        printf("%d", BT->Data);
    }
}
 
void LevelorderTraversal (BinTree BT)
{ 
    Queue Q; 
    BinTree T;
 
    if (!BT) return; /* 若是空树则直接返回 */
     
    Q = CreatQueue(); /* 创建空队列 Q */
    AddQ(Q, BT);
    while (!IsEmpty(Q) ) {
        T = DeleteQ(Q);
        printf("%d", T->Data); /* 访问取出队列的结点 */
        if (T->Left )   AddQ(Q, T->Left );
        if (T->Right )  AddQ(Q, T->Right );
    }
}

二叉搜索树的插入与删除

void InorderTraversal(BinTree BT)
{
    if(BT) {
        InorderTraversal(BT->Left );
        /* 此处假设对 BT 结点的访问就是打印数据 */
        printf("%d", BT->Data); /* 假设数据为整型 */
        InorderTraversal(BT->Right );
    }
}
 
void PreorderTraversal(BinTree BT)
{
    if(BT) {
        printf("%d", BT->Data );
        PreorderTraversal(BT->Left );
        PreorderTraversal(BT->Right );
    }
}
 
void PostorderTraversal(BinTree BT)
{
    if(BT) {
        PostorderTraversal(BT->Left );
        PostorderTraversal(BT->Right );
        printf("%d", BT->Data);
    }
}
 
void LevelorderTraversal (BinTree BT)
{ 
    Queue Q; 
    BinTree T;
 
    if (!BT) return; /* 若是空树则直接返回 */
     
    Q = CreatQueue(); /* 创建空队列 Q */
    AddQ(Q, BT);
    while (!IsEmpty(Q) ) {
        T = DeleteQ(Q);
        printf("%d", T->Data); /* 访问取出队列的结点 */
        if (T->Left )   AddQ(Q, T->Left );
        if (T->Right )  AddQ(Q, T->Right );
    }
}

AVL树的旋转与插入

typedef struct AVLNode *Position;
typedef Position AVLTree; /* AVL 树类型 */
typedef struct AVLNode{
    ElementType Data; /* 结点数据 */
    AVLTree Left;     /* 指向左子树 */
    AVLTree Right;    /* 指向右子树 */
    int Height;       /* 树高 */
}
 
int Max ( int a, int b )
{
    return a > b ? a : b;
}
 
AVLTree SingleLeftRotation (AVLTree A)
{ /* 注意:A 必须有一个左子结点 B */
  /* 将 A 与 B 做左单旋,更新 A 与 B 的高度,返回新的根结点 B */     
 
    AVLTree B = A->Left;
    A->Left = B->Right;
    B->Right = A;
    A->Height = Max(GetHeight(A->Left), GetHeight(A->Right) ) + 1;
    B->Height = Max(GetHeight(B->Left), A->Height ) + 1;
  
    return B;
}
 
AVLTree DoubleLeftRightRotation (AVLTree A)
{ /* 注意:A 必须有一个左子结点 B,且 B 必须有一个右子结点 C */
  /* 将 A、B 与 C 做两次单旋,返回新的根结点 C */
     
    /* 将 B 与 C 做右单旋,C 被返回 */
    A->Left = SingleRightRotation(A->Left);
    /* 将 A 与 C 做左单旋,C 被返回 */
    return SingleLeftRotation(A);
}
 
/*************************************/
/* 对称的右单旋与右 - 左双旋请自己实现 */
/*************************************/
 
AVLTree Insert(AVLTree T, ElementType X)
{ /* 将 X 插入 AVL 树 T 中,并且返回调整后的 AVL 树 */
    if (!T) { /* 若插入空树,则新建包含一个结点的树 */
        T = (AVLTree)malloc(sizeof(struct AVLNode));
        T->Data = X;
        T->Height = 0;
        T->Left = T->Right = NULL;
    } /* if (插入空树) 结束 */
 
    else if (X < T->Data ) {
        /* 插入 T 的左子树 */
        T->Left = Insert(T->Left, X);
        /* 如果需要左旋 */
        if (GetHeight(T->Left)-GetHeight(T->Right) == 2 )
            if (X < T->Left->Data ) 
               T = SingleLeftRotation(T);      /* 左单旋 */
            else 
               T = DoubleLeftRightRotation(T); /* 左 - 右双旋 */
    } /* else if (插入左子树) 结束 */
     
    else if (X> T->Data ) {
        /* 插入 T 的右子树 */
        T->Right = Insert(T->Right, X );
        /* 如果需要右旋 */
        if (GetHeight(T->Left)-GetHeight(T->Right) == -2 )
            if (X> T->Right->Data ) 
               T = SingleRightRotation(T);     /* 右单旋 */
            else 
               T = DoubleRightLeftRotation(T); /* 右 - 左双旋 */
    } /* else if (插入右子树) 结束 */
 
    /* else X == T->Data,无须插入 */
 
    /* 别忘了更新树高 */
    T->Height = Max(GetHeight(T->Left), GetHeight(T->Right) ) + 1;
     
    return T;
}

堆的定义与操作

typedef struct HNode *Heap; /* 堆的类型定义 */
struct HNode {
    ElementType *Data; /* 存储元素的数组 */
    int Size;          /* 堆中当前元素个数 */
    int Capacity;      /* 堆的最大容量 */
};
typedef Heap MaxHeap; /* 最大堆 */
typedef Heap MinHeap; /* 最小堆 */
 
#define MAXDATA 1000  /* 该值应根据具体情况定义为大于堆中所有可能元素的值 */
 
MaxHeap CreateHeap( int MaxSize )
{ /* 创建容量为 MaxSize 的空的最大堆 */
 
    MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));
    H->Data = (ElementType *)malloc((MaxSize+1)*sizeof(ElementType));
    H->Size = 0;
    H->Capacity = MaxSize;
    H->Data[0] = MAXDATA; /* 定义 "哨兵" 为大于堆中所有可能元素的值 */
 
    return H;
}
 
bool IsFull(MaxHeap H)
{
    return (H->Size == H->Capacity);
}
 
bool Insert(MaxHeap H, ElementType X)
{ /* 将元素 X 插入最大堆 H,其中 H->Data[0] 已经定义为哨兵 */
    int i;
  
    if (IsFull(H) ) { 
        printf("最大堆已满");
        return false;
    }
    i = ++H->Size; /* i 指向插入后堆中的最后一个元素的位置 */
    for (; H->Data[i/2] Data[i] = H->Data[i/2]; /* 上滤 X */
    H->Data[i] = X; /* 将 X 插入 */
    return true;
}
 
#define ERROR -1 /* 错误标识应根据具体情况定义为堆中不可能出现的元素值 */
 
bool IsEmpty(MaxHeap H)
{
    return (H->Size == 0);
}
 
ElementType DeleteMax(MaxHeap H)
{ /* 从最大堆 H 中取出键值为最大的元素,并删除一个结点 */
    int Parent, Child;
    ElementType MaxItem, X;
 
    if (IsEmpty(H) ) {
        printf("最大堆已为空");
        return ERROR;
    }
 
    MaxItem = H->Data[1]; /* 取出根结点存放的最大值 */
    /* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */
    X = H->Data[H->Size--]; /* 注意当前堆的规模要减小 */
    for(Parent=1; Parent*2<=H->Size; Parent=Child ) {
        Child = Parent * 2;
        if((Child!=H->Size) && (H->Data[Child]Data[Child+1]) )
            Child++;  /* Child 指向左右子结点的较大者 */
        if(X>= H->Data[Child] ) break; /* 找到了合适位置 */
        else  /* 下滤 X */
            H->Data[Parent] = H->Data[Child];
    }
    H->Data[Parent] = X;
 
    return MaxItem;
} 
 
/*----------- 建造最大堆 -----------*/
void PercDown( MaxHeap H, int p )
{ /* 下滤:将 H 中以 H->Data[p] 为根的子堆调整为最大堆 */
    int Parent, Child;
    ElementType X;
 
    X = H->Data[p]; /* 取出根结点存放的值 */
    for(Parent=p; Parent*2<=H->Size; Parent=Child ) {
        Child = Parent * 2;
        if((Child!=H->Size) && (H->Data[Child]Data[Child+1]) )
            Child++;  /* Child 指向左右子结点的较大者 */
        if(X>= H->Data[Child] ) break; /* 找到了合适位置 */
        else  /* 下滤 X */
            H->Data[Parent] = H->Data[Child];
    }
    H->Data[Parent] = X;
}
 
void BuildHeap(MaxHeap H)
{ /* 调整 H->Data[] 中的元素,使满足最大堆的有序性  */
  /* 这里假设所有 H->Size 个元素已经存在 H->Data[] 中 */
 
    int i;
 
    /* 从最后一个结点的父节点开始,到根结点 1 */
    for(i = H->Size/2; i>0; i-- )
        PercDown(H, i);
}

集合

#define MAXN 1000                  /* 集合最大元素个数 */
typedef int ElementType;           /* 默认元素可以用非负整数表示 */
typedef int SetName;               /* 默认用根结点的下标作为集合名称 */
typedef ElementType SetType[MAXN]; /* 假设集合元素下标从 0 开始 */
 
void Union(SetType S, SetName Root1, SetName Root2)
{ /* 这里默认 Root1 和 Root2 是不同集合的根结点 */
    /* 保证小集合并入大集合 */
    if (S[Root2] 

图的邻接矩阵

/* 图的邻接矩阵表示法 */
  
#define MaxVertexNum 100    /* 最大顶点数设为 100 */
#define INFINITY 65535        /* ∞设为双字节无符号整数的最大值 65535*/
typedef int Vertex;         /* 用顶点下标表示顶点, 为整型 */
typedef int WeightType;        /* 边的权值设为整型 */
typedef char DataType;        /* 顶点存储的数据类型设为字符型 */
  
/* 边的定义 */
typedef struct ENode *PtrToENode;
struct ENode{
    Vertex V1, V2;      /* 有向边  */
    WeightType Weight;  /* 权重 */
};
typedef PtrToENode Edge;
         
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 顶点数 */
    int Ne;  /* 边数   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
    DataType Data[MaxVertexNum];      /* 存顶点的数据 */
    /* 注意:很多情况下,顶点无数据,此时 Data[] 可以不用出现 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
  
  
  
MGraph CreateGraph( int VertexNum )
{ /* 初始化一个有 VertexNum 个顶点但没有边的图 */
    Vertex V, W;
    MGraph Graph;
      
    Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立图 */
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    /* 初始化邻接矩阵 */
    /* 注意:这里默认顶点编号从 0 开始,到 (Graph->Nv - 1) */
    for (V=0; VNv; V++)
        for (W=0; WNv; W++)  
            Graph->G[V][W] = INFINITY;
              
    return Graph; 
}
         
void InsertEdge(MGraph Graph, Edge E)
{
     /* 插入边  */
     Graph->G[E->V1][E->V2] = E->Weight;    
     /* 若是无向图,还要插入边  */
     Graph->G[E->V2][E->V1] = E->Weight;
}
  
MGraph BuildGraph()
{
    MGraph Graph;
    Edge E;
    Vertex V;
    int Nv, i;
      
    scanf("%d", &Nv);   /* 读入顶点个数 */
    Graph = CreateGraph(Nv); /* 初始化有 Nv 个顶点但没有边的图 */ 
      
    scanf("%d", &(Graph->Ne));   /* 读入边数 */
    if (Graph->Ne != 0 ) { /* 如果有边 */ 
        E = (Edge)malloc(sizeof(struct ENode)); /* 建立边结点 */ 
        /* 读入边,格式为 "起点 终点 权重",插入邻接矩阵 */
        for (i=0; iNe; i++) {
            scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); 
            /* 注意:如果权重不是整型,Weight 的读入格式要改 */
            InsertEdge(Graph, E);
        }
    } 
  
    /* 如果顶点有数据的话,读入数据 */
    for (V=0; VNv; V++) 
        scanf("%c", &(Graph->Data[V]));
  
    return Graph;
}

图的邻接表

/* 图的邻接矩阵表示法 */
  
#define MaxVertexNum 100    /* 最大顶点数设为 100 */
#define INFINITY 65535        /* ∞设为双字节无符号整数的最大值 65535*/
typedef int Vertex;         /* 用顶点下标表示顶点, 为整型 */
typedef int WeightType;        /* 边的权值设为整型 */
typedef char DataType;        /* 顶点存储的数据类型设为字符型 */
  
/* 边的定义 */
typedef struct ENode *PtrToENode;
struct ENode{
    Vertex V1, V2;      /* 有向边  */
    WeightType Weight;  /* 权重 */
};
typedef PtrToENode Edge;
         
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 顶点数 */
    int Ne;  /* 边数   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
    DataType Data[MaxVertexNum];      /* 存顶点的数据 */
    /* 注意:很多情况下,顶点无数据,此时 Data[] 可以不用出现 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
  
  
  
MGraph CreateGraph( int VertexNum )
{ /* 初始化一个有 VertexNum 个顶点但没有边的图 */
    Vertex V, W;
    MGraph Graph;
      
    Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立图 */
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    /* 初始化邻接矩阵 */
    /* 注意:这里默认顶点编号从 0 开始,到 (Graph->Nv - 1) */
    for (V=0; VNv; V++)
        for (W=0; WNv; W++)  
            Graph->G[V][W] = INFINITY;
              
    return Graph; 
}
         
void InsertEdge(MGraph Graph, Edge E)
{
     /* 插入边  */
     Graph->G[E->V1][E->V2] = E->Weight;    
     /* 若是无向图,还要插入边  */
     Graph->G[E->V2][E->V1] = E->Weight;
}
  
MGraph BuildGraph()
{
    MGraph Graph;
    Edge E;
    Vertex V;
    int Nv, i;
      
    scanf("%d", &Nv);   /* 读入顶点个数 */
    Graph = CreateGraph(Nv); /* 初始化有 Nv 个顶点但没有边的图 */ 
      
    scanf("%d", &(Graph->Ne));   /* 读入边数 */
    if (Graph->Ne != 0 ) { /* 如果有边 */ 
        E = (Edge)malloc(sizeof(struct ENode)); /* 建立边结点 */ 
        /* 读入边,格式为 "起点 终点 权重",插入邻接矩阵 */
        for (i=0; iNe; i++) {
            scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); 
            /* 注意:如果权重不是整型,Weight 的读入格式要改 */
            InsertEdge(Graph, E);
        }
    } 
  
    /* 如果顶点有数据的话,读入数据 */
    for (V=0; VNv; V++) 
        scanf("%c", &(Graph->Data[V]));
  
    return Graph;
}

邻接表深度遍历


/* 邻接表存储的图 - DFS */
  
void Visit(Vertex V)
{
    printf("正在访问顶点 %d\n", V);
}
  
/* Visited[] 为全局变量,已经初始化为 false */
void DFS( LGraph Graph, Vertex V, void (*Visit)(Vertex) )
{   /* 以 V 为出发点对邻接表存储的图 Graph 进行 DFS 搜索 */
    PtrToAdjVNode W;
      
    Visit(V); /* 访问第 V 个顶点 */
    Visited[V] = true; /* 标记 V 已访问 */
  
    for(W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对 V 的每个邻接点 W->AdjV */
        if (!Visited[W->AdjV] )    /* 若 W->AdjV 未被访问 */
            DFS(Graph, W->AdjV, Visit );    /* 则递归访问之 */
}

图的邻接矩阵广度遍历


/* 邻接矩阵存储的图 - BFS */
  
/* IsEdge(Graph, V, W) 检查  是否图 Graph 中的一条边,即 W 是否 V 的邻接点。  */
/* 此函数根据图的不同类型要做不同的实现,关键取决于对不存在的边的表示方法。*/
/* 例如对有权图, 如果不存在的边被初始化为 INFINITY, 则函数实现如下:         */
bool IsEdge(MGraph Graph, Vertex V, Vertex W)
{
    return Graph->G[V][W]Nv; W++ ) /* 对图中的每个顶点 W */
            /* 若 W 是 V 的邻接点并且未访问过 */
            if (!Visited[W] && IsEdge(Graph, V, W) ) {
                /* 访问顶点 W */
                Visit(W);
                Visited[W] = true; /* 标记 W 已访问 */
                AddQ(Q, W); /* W 入队列 */
            }
    } /* while 结束 */
}

邻接表存储 - 无权图的单源最短路算法

/* 邻接表存储 - 无权图的单源最短路算法 */
 
/* dist[] 和 path[] 全部初始化为 - 1 */
void Unweighted ( LGraph Graph, int dist[], int path[], Vertex S)
{
    Queue Q;
    Vertex V;
    PtrToAdjVNode W;
     
    Q = CreateQueue(Graph->Nv ); /* 创建空队列, MaxSize 为外部定义的常数 */
    dist[S] = 0; /* 初始化源点 */
    AddQ (Q, S);
 
    while(!IsEmpty(Q) ){
        V = DeleteQ(Q);
        for (W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对 V 的每个邻接点 W->AdjV */
            if (dist[W->AdjV]==-1 ) { /* 若 W->AdjV 未被访问过 */
                dist[W->AdjV] = dist[V]+1; /* W->AdjV 到 S 的距离更新 */
                path[W->AdjV] = V; /* 将 V 记录在 S 到 W->AdjV 的路径上 */
                AddQ(Q, W->AdjV);
            }
    } /* while 结束 */
}

邻接矩阵存储 - 有权图的单源最短路算法

/* 邻接矩阵存储 - 有权图的单源最短路算法 */
 
Vertex FindMinDist( MGraph Graph, int dist[], int collected[])
{ /* 返回未被收录顶点中 dist 最小者 */
    Vertex MinV, V;
    int MinDist = INFINITY;
 
    for (V=0; VNv; V++) {
        if (collected[V]==false && dist[V]Nv; V++ ) {
        dist[V] = Graph->G[S][V];
        path[V] = -1;
        collected[V] = false;
    }
    /* 先将起点收入集合 */
    dist[S] = 0;
    collected[S] = true;
 
    while (1) {
        /* V = 未被收录顶点中 dist 最小者 */
        V = FindMinDist(Graph, dist, collected);
        if (V==ERROR) /* 若这样的 V 不存在 */
            break;      /* 算法结束 */
        collected[V] = true;  /* 收录 V */
        for(W=0; WNv; W++ ) /* 对图中的每个顶点 W */
            /* 若 W 是 V 的邻接点并且未被收录 */
            if (collected[W]==false && Graph->G[V][W]G[V][W]<0) /* 若有负边 */
                    return false; /* 不能正确解决,返回错误标记 */
                /* 若收录 V 使得 dist[W] 变小 */
                if (dist[V]+Graph->G[V][W] G[V][W]; /* 更新 dist[W] */
                    path[W] = V; /* 更新 S 到 W 的路径 */
                }
            }
    } /* while 结束 */
    return true; /* 算法执行完毕,返回正确标记 */
}

邻接矩阵存储 - 多源最短路算法

/* 邻接矩阵存储 - 多源最短路算法 */
 
bool Floyd(MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[][MaxVertexNum] )
{
    Vertex i, j, k;
 
    /* 初始化 */
    for (i=0; iNv; i++ )
        for(j=0; jNv; j++ ) {
            D[i][j] = Graph->G[i][j];
            path[i][j] = -1;
        }
 
    for(k=0; kNv; k++ )
        for(i=0; iNv; i++ )
            for(j=0; jNv; j++ )
                if(D[i][k] + D[k][j] 

邻接矩阵存储 - Prim 最小生成树算法

/* 邻接矩阵存储 - Prim 最小生成树算法 */
 
Vertex FindMinDist(MGraph Graph, WeightType dist[] )
{ /* 返回未被收录顶点中 dist 最小者 */
    Vertex MinV, V;
    WeightType MinDist = INFINITY;
 
    for (V=0; VNv; V++) {
        if (dist[V]!=0 && dist[V]Nv; V++) {
        /* 这里假设若 V 到 W 没有直接的边,则 Graph->G[V][W] 定义为 INFINITY */
           dist[V] = Graph->G[0][V];
           parent[V] = 0; /* 暂且定义所有顶点的父结点都是初始点 0 */ 
    }
    TotalWeight = 0; /* 初始化权重和     */
    VCount = 0;      /* 初始化收录的顶点数 */
    /* 创建包含所有顶点但没有边的图。注意用邻接表版本 */
    MST = CreateGraph(Graph->Nv);
    E = (Edge)malloc( sizeof(struct ENode) ); /* 建立空的边结点 */
            
    /* 将初始点 0 收录进 MST */
    dist[0] = 0;
    VCount ++;
    parent[0] = -1; /* 当前树根是 0 */
 
    while (1) {
        V = FindMinDist(Graph, dist);
        /* V = 未被收录顶点中 dist 最小者 */
        if (V==ERROR) /* 若这样的 V 不存在 */
            break;   /* 算法结束 */
             
        /* 将 V 及相应的边  收录进 MST */
        E->V1 = parent[V];
        E->V2 = V;
        E->Weight = dist[V];
        InsertEdge(MST, E);
        TotalWeight += dist[V];
        dist[V] = 0;
        VCount++;
         
        for(W=0; WNv; W++ ) /* 对图中的每个顶点 W */
            if (dist[W]!=0 && Graph->G[V][W]G[V][W] G[V][W]; /* 更新 dist[W] */
                    parent[W] = V; /* 更新树 */
                }
            }
    } /* while 结束 */
    if (VCount < Graph->Nv ) /* MST 中收的顶点不到 | V | 个 */
       TotalWeight = ERROR;
    return TotalWeight;   /* 算法执行完毕,返回最小权重和或错误标记 */
}

邻接表存储 - Kruskal 最小生成树算法

/* 邻接表存储 - Kruskal 最小生成树算法 */
 
/*-------------------- 顶点并查集定义 --------------------*/
typedef Vertex ElementType; /* 默认元素可以用非负整数表示 */
typedef Vertex SetName;     /* 默认用根结点的下标作为集合名称 */
typedef ElementType SetType[MaxVertexNum]; /* 假设集合元素下标从 0 开始 */
 
void InitializeVSet( SetType S, int N )
{ /* 初始化并查集 */
    ElementType X;
 
    for (X=0; XESet[Child+1].Weight) )
            Child++;  /* Child 指向左右子结点的较小者 */
        if(X.Weight <= ESet[Child].Weight ) break; /* 找到了合适位置 */
        else  /* 下滤 X */
            ESet[Parent] = ESet[Child];
    }
    ESet[Parent] = X;
}
 
void InitializeESet(LGraph Graph, Edge ESet)
{ /* 将图的边存入数组 ESet,并且初始化为最小堆 */
    Vertex V;
    PtrToAdjVNode W;
    int ECount;
 
    /* 将图的边存入数组 ESet */
    ECount = 0;
    for (V=0; VNv; V++ )
        for (W=Graph->G[V].FirstEdge; W; W=W->Next )
            if (V < W->AdjV ) { /* 避免重复录入无向图的边,只收 V1AdjV;
                ESet[ECount++].Weight = W->Weight;
            }
    /* 初始化为最小堆 */
    for (ECount=Graph->Ne/2; ECount>=0; ECount-- )
        PercDown(ESet, ECount, Graph->Ne );
}
 
int GetEdge( Edge ESet, int CurrentSize )
{ /* 给定当前堆的大小 CurrentSize,将当前最小边位置弹出并调整堆 */
 
    /* 将最小边与当前堆的最后一个位置的边交换 */
    Swap(&ESet[0], &ESet[CurrentSize-1]);
    /* 将剩下的边继续调整成最小堆 */
    PercDown(ESet, 0, CurrentSize-1);
 
    return CurrentSize-1; /* 返回最小边所在位置 */
}
/*-------------------- 最小堆定义结束 --------------------*/
 
 
int Kruskal(LGraph Graph, LGraph MST)
{ /* 将最小生成树保存为邻接表存储的图 MST,返回最小权重和 */
    WeightType TotalWeight;
    int ECount, NextEdge;
    SetType VSet; /* 顶点数组 */
    Edge ESet;    /* 边数组 */
 
    InitializeVSet(VSet, Graph->Nv ); /* 初始化顶点并查集 */
    ESet = (Edge)malloc( sizeof(struct ENode)*Graph->Ne );
    InitializeESet(Graph, ESet); /* 初始化边的最小堆 */
    /* 创建包含所有顶点但没有边的图。注意用邻接表版本 */
    MST = CreateGraph(Graph->Nv);
    TotalWeight = 0; /* 初始化权重和     */
    ECount = 0;      /* 初始化收录的边数 */
 
    NextEdge = Graph->Ne; /* 原始边集的规模 */
    while (ECount < Graph->Nv-1 ) {  /* 当收集的边不足以构成树时 */
        NextEdge = GetEdge(ESet, NextEdge); /* 从边集中得到最小边的位置 */
        if (NextEdge < 0) /* 边集已空 */
            break;
        /* 如果该边的加入不构成回路,即两端结点不属于同一连通集 */
        if (CheckCycle( VSet, ESet[NextEdge].V1, ESet[NextEdge].V2 )==true ) {
            /* 将该边插入 MST */
            InsertEdge(MST, ESet+NextEdge);
            TotalWeight += ESet[NextEdge].Weight; /* 累计权重 */
            ECount++; /* 生成树中边数加 1 */
        }
    }
    if (ECount < Graph->Nv-1 )
        TotalWeight = -1; /* 设置错误标记,表示生成树不存在 */
 
    return TotalWeight;
}

邻接表存储 - 拓扑排序算法

/* 邻接表存储 - 拓扑排序算法 */
 
bool TopSort(LGraph Graph, Vertex TopOrder[] )
{ /* 对 Graph 进行拓扑排序,  TopOrder[] 顺序存储排序后的顶点下标 */
    int Indegree[MaxVertexNum], cnt;
    Vertex V;
    PtrToAdjVNode W;
       Queue Q = CreateQueue(Graph->Nv );
  
    /* 初始化 Indegree[] */
    for (V=0; VNv; V++)
        Indegree[V] = 0;
         
    /* 遍历图,得到 Indegree[] */
    for (V=0; VNv; V++)
        for (W=Graph->G[V].FirstEdge; W; W=W->Next)
            Indegree[W->AdjV]++; /* 对有向边 AdjV > 累计终点的入度 */
             
    /* 将所有入度为 0 的顶点入列 */
    for (V=0; VNv; V++)
        if (Indegree[V]==0 )
            AddQ(Q, V);
             
    /* 下面进入拓扑排序 */ 
    cnt = 0; 
    while(!IsEmpty(Q) ){
        V = DeleteQ(Q); /* 弹出一个入度为 0 的顶点 */
        TopOrder[cnt++] = V; /* 将之存为结果序列的下一个元素 */
        /* 对 V 的每个邻接点 W->AdjV */
        for (W=Graph->G[V].FirstEdge; W; W=W->Next )
            if (--Indegree[W->AdjV] == 0 )/* 若删除 V 使得 W->AdjV 入度为 0 */
                AddQ(Q, W->AdjV); /* 则该顶点入列 */ 
    } /* while 结束 */
     
    if (cnt != Graph->Nv )
        return false; /* 说明图中有回路, 返回不成功标志 */ 
    else
        return true;
}

排序

插入排序

void InsertionSort(ElementType A[], int N )
{ /* 插入排序 */
     int P, i;
     ElementType Tmp;
      
     for (P=1; P0 && A[i-1]>Tmp; i-- )
             A[i] = A[i-1]; /* 依次与已排序序列中元素比较并右移 */
         A[i] = Tmp; /* 放进合适的位置 */
     }
}

希尔排序

void ShellSort(ElementType A[], int N )
{ /* 希尔排序 - 用 Sedgewick 增量序列 */
     int Si, D, P, i;
     ElementType Tmp;
     /* 这里只列出一小部分增量 */
     int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
      
     for (Si=0; Sedgewick[Si]>=N; Si++ ) 
         ; /* 初始的增量 Sedgewick[Si] 不能超过待排序列长度 */
 
     for (D=Sedgewick[Si]; D>0; D=Sedgewick[++Si] )
         for (P=D; P=D && A[i-D]>Tmp; i-=D )
                 A[i] = A[i-D];
             A[i] = Tmp;
         }
}

堆排序

void Swap(ElementType *a, ElementType *b)
{
     ElementType t = *a; *a = *b; *b = t;
}
  
void PercDown(ElementType A[], int p, int N )
{ /* 改编代码 4.24 的 PercDown(MaxHeap H, int p)    */
  /* 将 N 个元素的数组中以 A[p] 为根的子堆调整为最大堆 */
    int Parent, Child;
    ElementType X;
 
    X = A[p]; /* 取出根结点存放的值 */
    for(Parent=p; (Parent*2+1)= A[Child] ) break; /* 找到了合适位置 */
        else  /* 下滤 X */
            A[Parent] = A[Child];
    }
    A[Parent] = X;
}
 
void HeapSort(ElementType A[], int N ) 
{ /* 堆排序 */
     int i;
       
     for (i=N/2-1; i>=0; i-- )/* 建立最大堆 */
         PercDown(A, i, N);
      
     for (i=N-1; i>0; i-- ) {
         /* 删除最大堆顶 */
         Swap(&A[0], &A[i] ); /* 见代码 7.1 */
         PercDown(A, 0, i);
     }
}

归并排序递归实现

/* 归并排序 - 递归实现 */
 
/* L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置 */
void Merge(ElementType A[], ElementType TmpA[], int L, int R, int RightEnd )
{ /* 将有序的 A[L]~A[R-1] 和 A[R]~A[RightEnd] 归并成一个有序序列 */
     int LeftEnd, NumElements, Tmp;
     int i;
      
     LeftEnd = R - 1; /* 左边终点位置 */
     Tmp = L;         /* 有序序列的起始位置 */
     NumElements = RightEnd - L + 1;
      
     while(L <= LeftEnd && R <= RightEnd) {
         if (A[L] <= A[R] )
             TmpA[Tmp++] = A[L++]; /* 将左边元素复制到 TmpA */
         else
             TmpA[Tmp++] = A[R++]; /* 将右边元素复制到 TmpA */
     }
 
     while(L <= LeftEnd)
         TmpA[Tmp++] = A[L++]; /* 直接复制左边剩下的 */
     while(R <= RightEnd)
         TmpA[Tmp++] = A[R++]; /* 直接复制右边剩下的 */
          
     for(i = 0; i < NumElements; i++, RightEnd --)
         A[RightEnd] = TmpA[RightEnd]; /* 将有序的 TmpA[] 复制回 A[] */
}
 
void Msort(ElementType A[], ElementType TmpA[], int L, int RightEnd )
{ /* 核心递归排序函数 */ 
     int Center;
      
     if (L < RightEnd) {
          Center = (L+RightEnd) / 2;
          Msort(A, TmpA, L, Center);              /* 递归解决左边 */ 
          Msort(A, TmpA, Center+1, RightEnd);     /* 递归解决右边 */  
          Merge(A, TmpA, L, Center+1, RightEnd);  /* 合并两段有序序列 */ 
     }
}
 
void MergeSort(ElementType A[], int N )
{ /* 归并排序 */
     ElementType *TmpA;
     TmpA = (ElementType *)malloc(N*sizeof(ElementType));
      
     if (TmpA != NULL) {
          Msort(A, TmpA, 0, N-1);
          free(TmpA);
     }
     else printf( "空间不足" );
}

归并排序循环实现

/* 归并排序 - 循环实现 */
/* 这里 Merge 函数在递归版本中给出 */
 
/* length = 当前有序子列的长度 */
void Merge_pass(ElementType A[], ElementType TmpA[], int N, int length )
{ /* 两两归并相邻有序子列 */
     int i, j;
       
     for (i=0; i <= N-2*length; i += 2*length)
         Merge(A, TmpA, i, i+length, i+2*length-1);
     if (i+length < N) /* 归并最后 2 个子列 */
         Merge(A, TmpA, i, i+length, N-1);
     else /* 最后只剩 1 个子列 */
         for (j = i; j < N; j++) TmpA[j] = A[j];
}
 
void Merge_Sort(ElementType A[], int N )
{ 
     int length; 
     ElementType *TmpA;
      
     length = 1; /* 初始化子序列长度 */
     TmpA = malloc( N * sizeof(ElementType) );
     if (TmpA != NULL) {
          while(length < N) {
              Merge_pass(A, TmpA, N, length);
              length *= 2;
              Merge_pass(TmpA, A, N, length);
              length *= 2;
          }
          free(TmpA);
     }
     else printf( "空间不足" );
}

快速排序直接调用库函数

/* 快速排序 - 直接调用库函数 */
 
#include 
 
/*--------------- 简单整数排序 --------------------*/
int compare(const void *a, const void *b)
{ /* 比较两整数。非降序排列 */
    return (*(int*)a - *(int*)b);
}
/* 调用接口 */ 
qsort(A, N, sizeof(int), compare);
/*--------------- 简单整数排序 --------------------*/
 
 
/*--------------- 一般情况下,对结构体 Node 中的某键值 key 排序 ---------------*/
struct Node {
    int key1, key2;
} A[MAXN];
  
int compare2keys(const void *a, const void *b)
{ /* 比较两种键值:按 key1 非升序排列;如果 key1 相等,则按 key2 非降序排列 */
    int k;
    if ( ((const struct Node*)a)->key1 < ((const struct Node*)b)->key1 )
        k = 1;
    else if ( ((const struct Node*)a)->key1 > ((const struct Node*)b)->key1 )
        k = -1;
    else { /* 如果 key1 相等 */
        if ( ((const struct Node*)a)->key2 < ((const struct Node*)b)->key2 )
            k = -1;
        else
            k = 1;
    }
    return k;
}
/* 调用接口 */ 
qsort(A, N, sizeof(struct Node), compare2keys);
/*--------------- 一般情况下,对结构体 Node 中的某键值 key 排序 ---------------*/

快速排序

/* 快速排序 */
 
ElementType Median3(ElementType A[], int Left, int Right )
{ 
    int Center = (Left+Right) / 2;
    if (A[Left] > A[Center] )
        Swap(&A[Left], &A[Center] );
    if (A[Left] > A[Right] )
        Swap(&A[Left], &A[Right] );
    if (A[Center] > A[Right] )
        Swap(&A[Center], &A[Right] );
    /* 此时 A[Left] <= A[Center] <= A[Right] */
    Swap(&A[Center], &A[Right-1] ); /* 将基准 Pivot 藏到右边 */
    /* 只需要考虑 A[Left+1] … A[Right-2] */
    return  A[Right-1];  /* 返回基准 Pivot */
}
 
void Qsort(ElementType A[], int Left, int Right )
{ /* 核心递归函数 */ 
     int Pivot, Cutoff, Low, High;
       
     if (Cutoff <= Right-Left) { /* 如果序列元素充分多,进入快排 */
          Pivot = Median3(A, Left, Right); /* 选基准 */ 
          Low = Left; High = Right-1;
          while (1) { /* 将序列中比基准小的移到基准左边,大的移到右边 */
               while (A[++Low]  Pivot ) ;
               if (Low < High) Swap(&A[Low], &A[High] );
               else break;
          }
          Swap(&A[Low], &A[Right-1] );   /* 将基准换到正确的位置 */ 
          Qsort(A, Left, Low-1);    /* 递归解决左边 */ 
          Qsort(A, Low+1, Right);   /* 递归解决右边 */  
     }
     else InsertionSort(A+Left, Right-Left+1); /* 元素太少,用简单排序 */ 
}
 
void QuickSort(ElementType A[], int N )
{ /* 统一接口 */
     Qsort(A, 0, N-1);
}

基数排序次位优先

/* 基数排序 - 次位优先 */
 
/* 假设元素最多有 MaxDigit 个关键字,基数全是同样的 Radix */
#define MaxDigit 4
#define Radix 10
 
/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node {
    int key;
    PtrToNode next;
};
 
/* 桶头结点 */
struct HeadNode {
    PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
  
int GetDigit ( int X, int D )
{ /* 默认次位 D=1, 主位 D<=MaxDigit */
    int d, i;
     
    for (i=1; i<=D; i++) {
        d = X % Radix;
        X /= Radix;
    }
    return d;
}
 
void LSDRadixSort(ElementType A[], int N )
{ /* 基数排序 - 次位优先 */
     int D, Di, i;
     Bucket B;
     PtrToNode tmp, p, List = NULL; 
      
     for (i=0; ikey = A[i];
         tmp->next = List;
         List = tmp;
     }
     /* 下面开始排序 */ 
     for (D=1; D<=MaxDigit; D++) { /* 对数据的每一位循环处理 */
         /* 下面是分配的过程 */
         p = List;
         while (p) {
             Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */
             /* 从 List 中摘除 */
             tmp = p; p = p->next;
             /* 插入 B[Di] 号桶尾 */
             tmp->next = NULL;
             if (B[Di].head == NULL)
                 B[Di].head = B[Di].tail = tmp;
             else {
                 B[Di].tail->next = tmp;
                 B[Di].tail = tmp;
             }
         }
         /* 下面是收集的过程 */
         List = NULL; 
         for (Di=Radix-1; Di>=0; Di--) { /* 将每个桶的元素顺序收集入 List */
             if (B[Di].head) { /* 如果桶不为空 */
                 /* 整桶插入 List 表头 */
                 B[Di].tail->next = List;
                 List = B[Di].head;
                 B[Di].head = B[Di].tail = NULL; /* 清空桶 */
             }
         }
     }
     /* 将 List 倒入 A[] 并释放空间 */
     for (i=0; inext;
        A[i] = tmp->key;
        free(tmp);
     } 
}

基数排序主位优先

/* 基数排序 - 主位优先 */
 
/* 假设元素最多有 MaxDigit 个关键字,基数全是同样的 Radix */
 
#define MaxDigit 4
#define Radix 10
 
/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node{
    int key;
    PtrToNode next;
};
 
/* 桶头结点 */
struct HeadNode {
    PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
  
int GetDigit ( int X, int D )
{ /* 默认次位 D=1, 主位 D<=MaxDigit */
    int d, i;
     
    for (i=1; i<=D; i++) {
        d = X%Radix;
        X /= Radix;
    }
    return d;
}
 
void MSD(ElementType A[], int L, int R, int D )
{ /* 核心递归函数: 对 A[L]...A[R] 的第 D 位数进行排序 */
     int Di, i, j;
     Bucket B;
     PtrToNode tmp, p, List = NULL; 
     if (D==0) return; /* 递归终止条件 */
      
     for (i=0; ikey = A[i];
         tmp->next = List;
         List = tmp;
     }
     /* 下面是分配的过程 */
     p = List;
     while (p) {
         Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */
         /* 从 List 中摘除 */
         tmp = p; p = p->next;
         /* 插入 B[Di] 号桶 */
         if (B[Di].head == NULL) B[Di].tail = tmp;
         tmp->next = B[Di].head;
         B[Di].head = tmp;
     }
     /* 下面是收集的过程 */
     i = j = L; /* i, j 记录当前要处理的 A[] 的左右端下标 */
     for (Di=0; Dinext;
                 A[j++] = tmp->key;
                 free(tmp);
             }
             /* 递归对该桶数据排序, 位数减 1 */
             MSD(A, i, j-1, D-1);
             i = j; /* 为下一个桶对应的 A[] 左端 */
         } 
     } 
}
 
void MSDRadixSort(ElementType A[], int N )
{ /* 统一接口 */
    MSD(A, 0, N-1, MaxDigit); 
}

散列表

创建开放定址法的散列表

#define MAXTABLESIZE 100000 /* 允许开辟的最大散列表长度 */
typedef int ElementType;    /* 关键词类型用整型 */
typedef int Index;          /* 散列地址类型 */
typedef Index Position;     /* 数据所在位置与散列地址是同一类型 */
/* 散列单元状态类型,分别对应:有合法元素、空单元、有已删除元素 */
typedef enum {Legitimate, Empty, Deleted} EntryType;
 
typedef struct HashEntry Cell; /* 散列表单元类型 */
struct HashEntry{
    ElementType Data; /* 存放元素 */
    EntryType Info;   /* 单元状态 */
};
 
typedef struct TblNode *HashTable; /* 散列表类型 */
struct TblNode {   /* 散列表结点定义 */
    int TableSize; /* 表的最大长度 */
    Cell *Cells;   /* 存放散列单元数据的数组 */
};
 
int NextPrime( int N )
{ /* 返回大于 N 且不超过 MAXTABLESIZE 的最小素数 */
    int i, p = (N%2)? N+2 : N+1; /* 从大于 N 的下一个奇数开始 */
 
    while(p <= MAXTABLESIZE) {
        for( i=(int)sqrt(p); i>2; i-- )
            if (!(p%i) ) break; /* p 不是素数 */
        if (i==2) break; /* for 正常结束,说明 p 是素数 */
        else  p += 2; /* 否则试探下一个奇数 */
    }
    return p;
}
 
HashTable CreateTable( int TableSize )
{
    HashTable H;
    int i;
 
    H = (HashTable)malloc(sizeof(struct TblNode));
    /* 保证散列表最大长度是素数 */
    H->TableSize = NextPrime(TableSize);
    /* 声明单元数组 */
    H->Cells = (Cell *)malloc(H->TableSize*sizeof(Cell));
    /* 初始化单元状态为 “空单元” */
    for(i=0; iTableSize; i++ )
        H->Cells[i].Info = Empty;
 
    return H;
}

平方探测法的查找与插入

Position Find(HashTable H, ElementType Key)
{
    Position CurrentPos, NewPos;
    int CNum = 0; /* 记录冲突次数 */
 
    NewPos = CurrentPos = Hash(Key, H->TableSize ); /* 初始散列位置 */
    /* 当该位置的单元非空,并且不是要找的元素时,发生冲突 */
    while(H->Cells[NewPos].Info!=Empty && H->Cells[NewPos].Data!=Key ) {
                                           /* 字符串类型的关键词需要 strcmp 函数!! */
        /* 统计 1 次冲突,并判断奇偶次 */
        if(++CNum%2){ /* 奇数次冲突 */
            NewPos = CurrentPos + (CNum+1)*(CNum+1)/4; /* 增量为 +[(CNum+1)/2]^2 */
            if (NewPos>= H->TableSize )
                NewPos = NewPos % H->TableSize; /* 调整为合法地址 */
        }
        else { /* 偶数次冲突 */
            NewPos = CurrentPos - CNum*CNum/4; /* 增量为 -(CNum/2)^2 */
            while(NewPos < 0)
                NewPos += H->TableSize; /* 调整为合法地址 */
        }
    }
    return NewPos; /* 此时 NewPos 或者是 Key 的位置,或者是一个空单元的位置(表示找不到)*/
}
 
bool Insert(HashTable H, ElementType Key)
{
    Position Pos = Find(H, Key); /* 先检查 Key 是否已经存在 */
 
    if(H->Cells[Pos].Info != Legitimate ) { /* 如果这个单元没有被占,说明 Key 可以插入在此 */
        H->Cells[Pos].Info = Legitimate;
        H->Cells[Pos].Data = Key;
        /* 字符串类型的关键词需要 strcpy 函数!! */
        return true;
    }
    else {
        printf("键值已存在");
        return false;
    }
}

分离链接法的散列表实现

#define KEYLENGTH 15                   /* 关键词字符串的最大长度 */
typedef char ElementType[KEYLENGTH+1]; /* 关键词类型用字符串 */
typedef int Index;                     /* 散列地址类型 */
/******** 以下是单链表的定义 ********/
typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
/******** 以上是单链表的定义 ********/
 
typedef struct TblNode *HashTable; /* 散列表类型 */
struct TblNode {   /* 散列表结点定义 */
    int TableSize; /* 表的最大长度 */
    List Heads;    /* 指向链表头结点的数组 */
};
 
HashTable CreateTable( int TableSize )
{
    HashTable H;
    int i;
 
    H = (HashTable)malloc(sizeof(struct TblNode));
    /* 保证散列表最大长度是素数,具体见代码 5.3 */
    H->TableSize = NextPrime(TableSize);
 
    /* 以下分配链表头结点数组 */
    H->Heads = (List)malloc(H->TableSize*sizeof(struct LNode));
    /* 初始化表头结点 */
    for(i=0; iTableSize; i++ ) {
         H->Heads[i].Data[0] = '\0';
         H->Heads[i].Next = NULL;
    }
 
    return H;
}
 
Position Find(HashTable H, ElementType Key)
{
    Position P;
    Index Pos;
     
    Pos = Hash(Key, H->TableSize ); /* 初始散列位置 */
    P = H->Heads[Pos].Next; /* 从该链表的第 1 个结点开始 */
    /* 当未到表尾,并且 Key 未找到时 */ 
    while( P && strcmp(P->Data, Key) )
        P = P->Next;
 
    return P; /* 此时 P 或者指向找到的结点,或者为 NULL */
}
 
bool Insert(HashTable H, ElementType Key)
{
    Position P, NewCell;
    Index Pos;
     
    P = Find(H, Key);
    if (!P) { /* 关键词未找到,可以插入 */
        NewCell = (Position)malloc(sizeof(struct LNode));
        strcpy(NewCell->Data, Key);
        Pos = Hash(Key, H->TableSize ); /* 初始散列位置 */
        /* 将 NewCell 插入为 H->Heads[Pos] 链表的第 1 个结点 */
        NewCell->Next = H->Heads[Pos].Next;
        H->Heads[Pos].Next = NewCell; 
        return true;
    }
    else { /* 关键词已存在 */
        printf("键值已存在");
        return false;
    }
}
 
void DestroyTable(HashTable H)
{
    int i;
    Position P, Tmp;
     
    /* 释放每个链表的结点 */
    for(i=0; iTableSize; i++ ) {
        P = H->Heads[i].Next;
        while(P) {
            Tmp = P->Next;
            free(P);
            P = Tmp;
        }
    }
    free(H->Heads ); /* 释放头结点数组 */
    free(H);        /* 释放散列表结点 */
}

你可能感兴趣的:(浙大MOOC_C语言代码)