线性表的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); /* 释放散列表结点 */
}