1 引论
递归的两个基本法则:
- 基准情形:你必须总要有某些基准情形,它们不用递归就能求解。
- 不断推进:对于那些需要递归求解的情形,递归调用必须总能够朝着产生基准情形的方向推进。
2 算法分析
2.1 最大子序列和问题
//最大子序列和问题
int MaxSubsequenceSum(const int A[],int N){
int MaxSum=0;
int ThisSum=0;
for(int j=0;j<N;j++){
ThisSum+=A[j];
if(ThisSum>MaxSum)MaxSum=ThisSum;
else if(ThisSum<0)ThisSum=0;
}
return MaxSum;
}
2.1 判断偶数
//判断偶数
bool IsEven(int x){
return (x+1)%2;
}
2.2 高效率的取幂运算
//高效率的取幂运算
bool IsEven(unsigned int N){
return (N+1)%2;
}
long int Pow(const long int X,unsigned N){
if(N==0)return 0;
if(N==1)return X;
if(IsEven(N))return Pow(X*X,N/2);
else return Pow(X*X,N/2)*X;
}
}
2.3 求大于某数的下一个素数
static int NextPrime (int N) {
if (N % 2 == 0)
++N;
int i;
for (; ; N += 2){
for (i = 3; i*i <= N; i+=2)
if (N % i == 0)
goto ContOuter;
return N;
ContOuter:;
}
}
不使用goto语句
static int NextPrime (int N) {
if (N % 2 == 0)
++N;
int i;
bool NotPrime = false;
for (; ; N += 2){
NotPrime = true;
for (i = 3; i*i <= N; i+=2)
if (N % i == 0) {
NotPrime = true;
break;
}
if (!NotPrime)
return N;
}
}
2.4 isPrime
static int isPrime(int num) {
for (int i = 2; i <= sqrt(num); i++)
if (num % i == 0)
return 0;
return 1;
}
2.5 大数相加
#include <stdio.h>
#include <string.h>
const int maxn = 2000;
int arr[maxn];
char str1[maxn], str2[maxn];
int jiafa(int len1, int len2)
{
int sum = 0;
while (len1 > 0 && len2 > 0) {
arr[sum] = (str1[--len1] - '0') + (str2[--len2] - '0') + arr[sum];
arr[sum + 1] = arr[sum] / 10;
arr[sum] %= 10;
sum++;
}
while (len1 > 0) {
arr[sum] = (str1[--len1] - '0') + arr[sum];
arr[sum + 1] = arr[sum] / 10;
arr[sum] %= 10;
sum++;
}
while (len2 > 0) {
arr[sum] = (str2[--len2] - '0') + arr[sum];
arr[sum + 1] = arr[sum] / 10;
arr[sum] %= 10;
sum++;
}
if (arr[sum] != 0)
return sum;
else
return (sum - 1);
}
int main()
{
int n;
scanf("%d", &n);
for (int p = 1; p <= n; p++) {
memset(arr, 0, sizeof(arr));
memset(str1, 0, sizeof(str1));
memset(str2, 0, sizeof(str2));
scanf("%s %s", str1, str2);
int len1 = strlen(str1);
int len2 = strlen(str2);
int lrh = jiafa(len1, len2);
printf("Case %d:\n", p);
printf("%s + %s = ", str1, str2);
for (int i = lrh; i >= 0; i--)
printf("%d", arr[i]);
printf("\n");
if (p != n)
printf("\n");
}
return 0;
}
2.6快速幂
int poww(int a,int b){
int ans=1,base=a;
while(b!=0){
if(b&1!=0)ans*=base;
base*=base;
b>>=1;
}
return ans;
}
3 表、栈和队列
抽象数据类型ADT(abstract datad type)
全局变量和副作用是有害的观念正是出于模块化是有益的想法。
3.1 单向链表
有些编程人员发现递归地编写Find例程颇有吸引力,大概是因为这样可能避免冗长的终止条件。后面将看到,这是一个非常糟糕的想法,我们要不惜一切代价避免它。
//单向链表
//头文件
#pragma once
#ifndef _List_H
struct Node;
typedef struct Node* PtrToNode;
typedef PtrToNode List; //struct Node*
typedef PtrToNode Position;
List MakeEmpty(List L);
int IsEmpty(List L);
int IsLast(Position P, List L);
Position Find(int X, List L);
void Delete(int X, List L);
Position FindPrevious(int X, List L);
void Insert(int X, List L, Position P);
void DeleteList(List L);
Position Header(List L);
Position First(List L);
Position Advance(Position P);
int Retrieve(Position P);
#endif /* _List_H */
/* Place in the implementation file*/
struct Node {
int Element;
Position Next;
};
//源文件
void IsEmpty(List L){
return L->Next==NULL;
}
void IsLast(Position P,List L){
return P->Next==NULL;
}
Position Find(int X,List L){
Position P;
P=L;
while(P->Next!=NULL&&P->Element!=X)
P=P->Next;
return P;
}
Position FindPrevious(int X,List L){
Position P;
P=L;
while(P->Next!=NULL&&P->Next->Element!=X)
P=P->Next;
return P;
}
void Delete(int X,List L){
Position P,TemCell;
P=FindPrevious(X,L);
if(!IsLast(P)){
TemCell=P->Next;
P->Next=TemCell->Next;
free(TemCell);
}
}
void Insert(int X,List L,Position P){
Position TemCell;
TemCell=(Node*)malloc(sizeof(Node));
if(TemCell==NULL)
printf("FatalError:out of space!!!");
TemCell->Element=X;
TemCell->Next=P->Next;
P->Next=TemCell;
}
void DeleteList(List L){
Position P,TemCell;
P=L;
while(P!=NULL){
TemCell=P->Next;
free(P);
P=TemCell;
}
}
3.2 链表游标
//链表游标
#pragma once
#ifndef _Cursor_H
struct Node;
typedef struct Node* PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
void InitializeCursorSpace(void);
List MakeEmptyr(List L);
int IsEmpty(const List L);
int IsLast(const Position P, const List L);
Position Find(int X, const List L);
void Delente(int X, List L);
Position FindPrevious(int X, const List L);
void Insert(int X, List L, Position P);
void DeleteList(List L);
Position Header(const List L);
Position First(const List L);
Position Advance(const Position P);
int Retrieve(const Position P);
#endif /*_Cursor_H*/
/*Place in the implementation file*/
struct Node {
int Element;
Position Next;
};
struct Node CursorSpace[SpaceSize];
//源文件
//CursorAlloc & CursorFree
static Position CursorAlloc(void) {
Position P;
P = CursorSpace[0].Next;
CursorSpace[0].Next = CursorSpace[P].Next;
return P;
}
static void CursorFree(Position P) {
CursorSpace[P].Next = CursorSpace[0].Next;
CursorSpace[0].Next = P;
}
//测试一个链表是否为空的函数——游标实现
int IsEmpty(List L) {
return CursorSpace[L].Next == 0;
}
//测试P是否是链表的末尾的函数——游标实现
int IsLast(Position P, List L) {
return CursorSpace[P].Next == 0;
}
//Find——游标实现
Position Find(int X, List) {
Position P;
P = InitializeCursorSpace[L].Next;
while (P && CursorSpace[P].Element != X)
P = CursorSpace[P].Next;
return P;
}
//Delete——游标实现
void Delete(int X, List L) {
Position P, TmpCell;
P = FindPrevious(X, L);
if (!IsLast(P, L)) {
TmpCell = CursorSpace[P].Next;
CursorSpace[P].Next = CursorSpace[TmpCell].Next;
CursorFree(TmpCell);
}
}
//Insert——游标实现
void Insert(int X, List L, Position P) {
Position TmpCell;
TmpCell = CursorAlloc();
if (TmpCell == 0)
printf("FatalError:out of space!!!");
CursorSpace[TmpCell].Element = X;
CursorSpace[TmpCell].Next = CursorSpace[P].Next;
CursorSpace[P].Next = TmpCell;
}
3.3 栈——链表实现
//栈 链表实现
//头文件
#ifndef _Stack_h
struct Node;
typedef struct Node* PtrToNode;
typedef PtrToNode Stack;
int IsEmpty(Stack S);
Stack CreateStack(void);
void DisPoseStack(Stack S);
void MakeEmpty(Stack S);
void Push(int X, Stack S);
int Top(Stack S);
void Pop(Stack S);
#endif /* _Stack_h */
/* Place in implementation file */
/* Stack implementation is a liinked list with a header */
struct Node {
int Element;
PtrToNode Next;
};
//
//栈为空——链表实现
int IsEmpty(Stack S) {
return S->Next == NULL;
}
//创建一个空栈——链表实现
Stack CreateStack(void) {
Stack S;
S = (Node*)malloc(sizeof(struct Node));
if (S == NULL)
printf("FatalError:out of space!!!");
S->Next == NULL;
MakeEmpty(S);
return S;
}
void MakeEmpty(Stack S) {
if (S == NULL)
printf("FatalError:out of space!!!");
else while (!IsEmpty(S))
Pop(S);
}
//
void Push(int X, Stack S) {
PtrToNode TmpCell;
TmpCell = (Node*)malloc(sizeof(Node*));
if (TmpCell == NULL)
printf("FatalError:out of space!!!");
else {
TmpCell->Elememt = X;
TmpCell->Next = S->Next;
S->Next = TmpCell;
}
}
//
int Top(Stack S) {
if (!IsEmpty(S))
return S->Next->Element;
printf("Empty stack");
return 0;
}
//
void Pop(Stack S) {
PtrToNode FirstCell;
if (IsEmpty(S))
printf("Empty stack");
else {
FirstCell = S->Next;
S->Next = S->Next->Next;
free(FirstCell);
}
}
3.4 栈——数组实现
栈模型:只有栈顶元素是可访问的。
如果使用好的编程原则,调用例程不必知道使用的是哪种方法。
栈的链表实现:这种实现方法的缺点在于对malloc和free的调用的开销是昂贵的,特别是与指针操作的例程相比尤其如此。
//栈 数组实现
#ifndef _Stack_h
struct StackRecord;
typedef struct StackRecord* Stack;
int IsEmpty(Stack S);
Stack CreateStack(int);
void DisposeStack(Stack S);
void MakeEmpty(Stack S);
void Push(int X, Stack S);
int Top(Stack S);
void Pop(Stack S);
int TopAndPop(Stack S);
#endif /* _Stack_h */
/* Place in implementation file */
/* Stack implementation is a dynamically allocated array */
#define EmptyTOS (-1)
#define MinStackSize (5)
struct StackRecord {
int Capacity;
int TopOfStick;
int* Array;
};
//
Stack CreateStack(int MaxElements) {
Stack S;
if (MaxElements < MinStackSize)
printf("Stack size is too small");
S = (StackRecord*)malloc(sizeof(struct StackRecord));
if (S == NULL)
printf("FatalError:out of space!!!");
S->Array = malloc(sizeof(int) * MaxElements);
if (S->Array == NULL)
printf("FatalError:out of space!!!");
S->Capacity = MaxElements;
MakeEmpty(S);
return S;
}
//
void DisposeStack(Stack S) {
if (S != NULL) {
free(S->Array);
free(S);
}
}
//
int IsEmpty(Stack S) {
return S->TopOfStack == EmptyTOS;
}
//
void MakeEmpty(Stack S) {
S->TopOfStack = EmptyTOS;
}
//
void Push(int X, Satck S) {
if (IsFull(S))
printf("Full stack");
else
S->Array[++S->TopOfStack] = X;
}
//
int Top(Stack S) {
if (!IsEmpty(S))
return S->Arrat[S->TopOfStack];
printf("Empty stack");
return 0;
}
//
void Pop(Stack S) {
if (IsEmpty(S))
printf("Empty stack");
else
S->TopOfStack--;
}
//给出栈顶元素并从栈弹出——数组实现
int TopAndPop(Stack S) {
if (!IsEmpty(S))
return S->Array[S->TopOfStack--];
printf("Empty stack");
return 0;
}
3.5 队列——数组实现
//队列的数组实现
//
#ifndef _Queue_h
struct QueueRecord;
typedef struct QueueRecord* Queue;
int IsEmpty(QueueRecord Q);
int IsFull(Queue Q);
Queue CreateQueue(int MaxElements);
void DisopseQueue(Queue Q);
void MakeEmpty(Queue Q);
void Enqueue(int X, Queue Q);
int Front(Queue Q);
void Dequeue(Queue Q);
int FrontAndDequeue(Queue Q);
#endif /* _Queue_h */
/* Place in implementation file */
/* Queue implementation is a dynamically allocated array */
#define MinQueueSize (5)
struct QueueRecord {
int Capacity;
int Front;
int Rear;
int Size;
int* Array;
};
//
int IsEmpty(Queue Q) {
return Q->Size == 0;
}
//
void MakeEmpty(Queue Q) {
Q->Size = 0;
Q->Front = 1;
Q->Rear = 0;
}
//
static int Succ(int Value, Queue Q) {
if (++Value== Q->Capacity)
Value = 0;
return Value;
}
void Enqueue(int X, Queue Q) {
if (IsFull(Q))
printf("Full queue");
else {
Q->Size++;
Q->Rear = Succ(Q->Rear, Q);
Q->Array[Q->Rear] = X;
}
}
4 树
4.1 树
//树的节点声明
typedef struct TreeNode* PtrToNode;
struct TreeNode {
int Element;
PtrToNode FirstChild;
PtrToNode NextSibling;
};
//列出分级文件系统中目录
static void ListDir(DirectoryOrFile D, int Depth) {
if (D is a legitimate entry) {
PrintName(D, Depth);
if (D si a directory)
for each child, C, of D
ListDir(C, Depth + 1);
}
}
void ListDirectory(DirectoryOrFile D) {
ListDir(D, 0);
}
//目录(先序)列表
/usr
mark
book
ch1.r
ch2.r
ch3.r
course
cop3530
fall96
syl.r
spr97
syl.r
sum97
syl.r
junk.c
alex
junk.c
bill
work
course
cop3212
fall96
grades
prog1.r
prog2.r
fall97
prog2.r
prog1.r
grades
//计算一个目录大小
static void SizeDirectory(DirectoryOrFile D) {
int TotalSize;
TotalSize = 0;
if (D ia a legitimate entry) {
TotalSize = FileSize(D);
if (D is a directory)
for (each child, C, of D)
TotalSize += SizeDirecotry(C);
}
return TotalSize;
}
4.2 二叉查找树
//二叉查找树声明
#ifndef _Tree_H
struct TreeNode;
typedef struct TreeNode* Position;
typedef struct TreeNode* SearchTree;
SearchTree MakeEmpty(SearchTree T);
Position Find(int X, SearchTree T);
Position FindMin(SearchTree T);
Position FindMax(SearchTree T);
SearchTree Insert(int X, SearchTree T);
SearchTree Delete(int X, SearchTree T);
int Retrieve(Position P);
#endif /* _Tree_H */
/* Place in the implementation file */
struct TreeNode {
int Element;
SearchTree Left;
SearchTree Right;
};
//建立一棵空树的例程
SearchTree MakeEmpty(SearchTree T) {
if (T != NULL) {
MakeEmpty(T->Left);
MakeEmpty(T->Right);
free(T);
}
return NULL;
}
//二叉查找树的Find操作
Position Find(int X, SearchTree T) {
if (T == NULL)
return NULL;
if (X < T->Element)
return Find(X, T->Right);
else return T;
}
//对二叉查找树的FindMin的递归实现
Position FindMin(SearchTree T) {
if (T == NULL)
return NULL;
else
if ((T->Left == NULL))
return T;
else
return FindMin(T->Left);
}
//对二叉查找树的FindMax的非递归实现
Position FindMax(SearchTree T) {
if (T != NULL)
while (T->Right != NULL)
T = T->Right;
return T;
}
//插入元素到二叉查找树的例程
SearchTree Insert(int X, SearchTree T) {
if (T == NULL) {
T = (TreeNode*)malloc(sizeof(struct TreeNode));
if (T == NULL)
printf("Out of space!!!");
else {
T->Element = X;
T->Left = T->Right = NULL;
}
}
else
if (X < T->Element)
T->Left = Insert(X, T->Left);
else
if (X > T->Element)
T->Right = Insert(X, T->Right);
return T;
}
//二叉查找树的删除例程(返回树根节点)
SearchTree Delete(int X, SearchTree T) {
Position TmpCell;
if (T == NULL)
printf("Element not found");
else
if (X < T->Element)
T->Left = Delete(X, T->Left);
else
if (X > T->Element)
T->Right = Delete(X, T->Right);
else
if (T->Left && T->Right) {
TmpCell = FindMin(T->Right);
T->Element = TmpCell->Element;
T->Right = Delete(T->Element,T->Right);
}
else {/* One or zero children */
TmpCell = T;
if (T->Left == NULL) /* Also handles 0 children */
T = T->Right;
else if (T->Right == NULL)
T = T->Left;
free(TmpCell);
}
return T;
}
4.3 AVL树
#include<stdio.h>
#include<stdlib.h>
#define ElementType int
#ifndef _AvlTree_H
struct AvlNode;
typedef struct AvlNode* Position;
typedef struct AvlNode* AvlTree;
AvlTree MakeEmpty(AvlTree T);
Position Find(ElementType X, AvlTree T);
Position FindMin(AvlTree T);
Position FindMax(AvlTree T);
AvlTree Insert(ElementType X, AvlTree T);
AvlTree Delete(ElementType X, AvlTree T);
ElementType Retrieve(Position P);
static Position SingleRotateWithLeft(Position k2);
static Position DoubleRotateWithLeft(Position k3);
#endif /* _AvlTree_H */
/* Place in the implementation file */
struct AvlNode {
ElementType Element;
AvlTree Left;
AvlTree Right;
int Hight;
};
int Max(int a, int b) {
if (a > b)return a;
else return b;
}
//执行单旋转的例程
/* This function can be called only if k2 has a left child */
/* Perform a rotate between a node (k2) and its left child */
/* Update heights,then return new root */
/* 右旋 */
static Position SingleRotateWithLeft(Position k2) {
Position k1;
k1 = k2->Left;
k2->Left = k1->Right;
k1->Right = k2;
k2->Hight = Max(Height(k2->Left), Height(k2->Right)) + 1;
k1->Hight = Max(Height(k1->Left), k2->Hight) + 1;
return k1; /* New root */
}
static Position SingleRotateWithRight(Position k2) {
Position k1;
k1 = k2->Right;
k2->Right = k1->Left;
k1->Left = k2;
k2->Hight = Max(Height(k2->Left), Height(k2->Right)) + 1;
k1->Hight = Max(Height(k1->Left), k2->Hight) + 1;
return k1; /* New root */
}
//执行双旋转的例程
/* This function can be called only if k3 has a left */
/* child and k3's left child has a right child */
/* Do the left-right double rotation */
/* Update heights,then return new root */
static Position DoubleRotateWithLeft(Position k3) {
/* Rotate between k1 and k2 */
k3->Left = SingleRotateWithRight(k3->Left);
/* Rotate between k3 and k2 */
return SingleRotateWithLeft(k3);
}
static Position DoubleRotateWithRight(Position k3) {
/* Rotate between k1 and k2 */
k3->Right = SingleRotateWithLeft(k3->Right);
/* Rotate between k3 and k2 */
return SingleRotateWithRight(k3);
}
//计算AVL节点的高度的函数
static int Height(Position P) {
if (P == NULL)
return -1;
else
return P->Hight;
}
//向AVL树插入节点的函数
AvlTree Insert(ElementType X, AvlTree T) {
if (T == NULL) {
/* Creat and return a one-node tree */
T = (AvlNode*)malloc(sizeof(struct AvlNode));
if (T == NULL) {
printf("out of space!!!");
return NULL;
}
else {
T->Element = X;
T->Left = T->Right = NULL;
T->Hight = 0;
}
}
else
if (X < T->Element) {
T->Left = Insert(X, T->Left);
if (Height(T->Left) - Height(T->Right) == 2)
if (X < T->Left->Element)
T = SingleRotateWithLeft(T);
else
T = DoubleRotateWithLeft(T);
}
else
if (X > T->Element) {
T->Right = Insert(X, T->Right);
if (Height(T->Right) - Height(T->Left) == 2)
if (X > T->Right->Element)
T = SingleRotateWithRight(T);
else
T = DoubleRotateWithRight(T);
}
/* Else X is in the tree already: we'll do nothing */
T->Hight = Max(Height(T->Left), Height(T->Right)) + 1;
return T;
}
4.4 树的遍历
//按顺序打印二叉树的例程
void PrintTree(SearchTree T) {
if (T != NULL) {
PrintTree(T->Left);
PrintElement(T->Element);
PrintTree(T->Right);
}
}
//使用后序遍历计算树的高度例程
int Height(Tree T) {
if (T == NULL)
return -1;
else
return 1 + Max(Height(T->Left), Height(T->Right));
}
4.5 B树
5 散列
5.1 散列函数
typedef unsigned int Index;
//一个简单的散列函数
Index Hash(const char* Key, int TableSize) {
unsigned int HashVal = 0;
while (*Key != '\0')
HashVal += *Key++;
return HashVal % TableSize;
}
//一个好的散列函数
Index Hash(const char* Key, int TableSize) {
unsigned int HashVal = 0;
while (*Key != '\0')
HashVal = (HashVal << 5) + *Key++;
return HashVal % TableSize;
}
5.2 分离链接散列表
#include<stdio.h>
#include<stdlib.h>
#define ElementType int
//分离链接散列表的类型声明
#ifndef _HashSep_H
struct ListNode;
typedef struct ListNode* Position;
struct HashTbl;
typedef struct HashTbl* HashTable;
HashTable InitialzeTable(int TableSize);
void DestroyTable(HashTable H);
Position Find(ElementType Key, HashTable H);
void Insert(ElementType Key, HashTable H);
ElementType Retrieve(Position P);
/* Routines such as Delete and MakeEmpty are omittd */
#endif /* HashSep_H */
/* Place in the implementation file */
struct ListNode {
ElementType Element;
Position Next;
};
typedef Position List;
/* List *TheList will be an array of listss, allocated later */
/* The lists use headers(for simplicit), */
/* though this wastess space */
struct HashTbl {
int TableSize;
List* TheLists;
};
//分离链接散列表的初始化例程
HashTable InitializeTable(int TableSize) {
HashTable H;
int i;
if (TableSize < MinTableSize) {
printf("Table size too small");
return NULL;
}
/* Allocate table */
H = (HashTbl*)malloc(sizeof(struct HashTbl));
if (H == NULL)
printf("out of space!!!");
H->TableSize = NextPrime(TableSize);
/* Allocate array of lists */
H->TheLists = (List*)malloc(sizeof(List) * H->TableSize);
if (H->TheLists == NULL)
printf("out of space!!!");
/* Allocate list headers */
for (i = 0; i < H->TableSize; i++) {
H->TheLists[i] = (ListNode*)malloc(sizeof(struct ListNode));
if (H->TheLists == NULL)
printf("out of space!!!");
else
H->TheLists[i]->Next = NULL;
}
return H;
}
//分离连接散列表的Find例程
Position Find(ElementType Key, HashTable H) {
Position P;
List L;
L = H->TheLists[Hash(Key, H->TableSize)];
P = L->Next;
while (P != NULL && P->Element != Key)
/* Probably need strcmp!! */
P = P->Next;
return P;
}
//分离链接散列表的Insert例程
void Insert(ElementType Key, HashTable H) {
Position Pos, NewCell;
List L;
Pos = Find(Key, H);
if (Pos == NULL)/* Key is not found */
{
NewCell = (ListNode*)malloc(sizeof(struct ListNode));
if (NewCell == NULL)
printf("out of space!!!");
else
{
L = H->TheLists[Hash(Key, H->TableSize)];
NewCell->Next = L->Next;
NewCell->Element = Key;/* Probably need strcpy! */
L->Next = NewCell;
}
}
}
#include <stdio.h>
#include <stdlib.h>
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
typedef char* ElementType;
#ifndef _HashSep_H
struct ListNode;
typedef struct ListNode* Position;
struct HashTbl;
typedef struct HashTbl* HashTable;
HashTable initializeTable(int tableSize);
void destroyTable(HashTable h);
Position find(ElementType key, HashTable h);
void insert(ElementType key, HashTable h);
void Delete(ElementType key, HashTable h);
ElementType retrive(Position p);
#endif
//#include"fatal.h"
#include<math.h>
#include<string.h>
#define MinTableSize 10
struct ListNode {
ElementType element;
Position next;
};
typedef Position List;
struct HashTbl {
int tableSize;
List* theLists;//数组指针
};
static int hash(ElementType key, int tableSize) {
unsigned int hashVal = 0;
while (*key != '\0')
hashVal = (hashVal << 5) + *key++;
return hashVal % (tableSize);
}
static int isPrime(int num) {
for (int i = 2; i <= sqrt(num); i++)
if (num % i == 0)
return 0;
return 1;
}
static int nextPrime(int num) {
int i = num;
while (!isPrime(i))
i++;
return i;
}
int NextPrime(int n) {
if (n % 2 == 0)
n++;
while (!isPrime(n))
n += 2;
return n;
}
HashTable initializeTable(int tableSize) {
HashTable h;
int i;
if (tableSize < MinTableSize) {
Error("Table size too small");
return NULL;
}
h = (HashTbl*)malloc(sizeof(struct HashTbl));
if (h == NULL)
FatalError("Out of space!!!");
h->tableSize = nextPrime(tableSize);
h->theLists =(List*) malloc(sizeof(List) * h->tableSize);
if (h->theLists == NULL)
FatalError("Out of space!!!");
for (i = 0; i < h->tableSize; i++) {
h->theLists[i] = (List)malloc(sizeof(struct ListNode));
if (h->theLists == NULL)
FatalError("Out of space!!!");
else {
h->theLists[i]->next = NULL;
}
}
return h;
}
void destroyTable(HashTable h) {
for (int i = 0; i < h->tableSize; i++) {
List l = h->theLists[i];
Position p = l;
while (p) {
Position temp;
temp = p->next;
free(p);
p = temp;
}
}
free(h->theLists);
free(h);
}
Position find(ElementType key, HashTable h) {
Position p;
List l;
l = h->theLists[hash(key, h->tableSize)];
p = l->next;
while (p && strcmp(p->element, key) != 0)
p = p->next;
return p;
}
void insert(ElementType key, HashTable h) {
Position pos, newCell;
List l;
pos = find(key, h);
if (pos == NULL) {
newCell = (ListNode*)malloc(sizeof(struct ListNode));
if (newCell == NULL)
FatalError("Out of space!!!");
newCell->element = (char*)malloc(sizeof(char) * strlen(key) + 1);//+1是为了给\0留空间
if (newCell->element == NULL)
FatalError("Out of space!!!");
l = h->theLists[hash(key, h->tableSize)];
newCell->next = l->next;
l->next = newCell;
strcpy(newCell->element, key);
}
}
void Delete(ElementType key, HashTable h) {
Position p;
List l;
l = h->theLists[hash(key, h->tableSize)];
p = l;
while (p->next && strcmp(p->next->element, key) != 0)
p = p->next;
if (p->next) {
Position deleteCell = p->next;
p->next = deleteCell->next;
free(deleteCell->element);
free(deleteCell);
}
}
ElementType retrive(Position p) {
return p->element;
}
/*
int main() {
HashTable h = initializeTable(500);
insert("aaaaaaa", h);
Position p = find("aaaaaaa", h);
if (p)
printf("%s", retrive(p));
Delete("aaaaaaa", h);
p = find("aaaaaaa", h);
if (p)
printf("%s", retrive(p));
destroyTable(h);
}
*/
5.3 开放定址散列表
#include<stdio.h>
#include<stdlib.h>
#define MinTableSize 5
typedef char* ElementType;
//开放定址散列表声明
#ifndef _HashQuad_H
typedef unsigned int Index;
typedef Index Position;
struct HashTbl;
typedef struct HashTbl* HashTable;
HashTable InitializeTable(int TableSize);
void DestroyTable(HashTable H);
Position Find(ElementType Key, HashTable H);
void Insert(ElementType Key, HashTable H);
ElementType Retrieve(Position P, HashTable H);
HashTable Rehash(HashTable H);
Index Hash(const char* Key, int TableSize);
int NextPrime(int N);
/* Routines such as Delete and MakeEmpty are omitted */
#endif /* _HahsQuad_H */
/* Place in the implementation file */
enum KindOfEntry { Legitimate, Empty, Deleted };
struct HashEntry {
ElementType Element;
enum KindOfEntry Info;
};
typedef struct HashEntry Cell;
/* Cell *TheCells will be an array of */
/* Hash Entry cells,allocated later */
struct HashTbl {
int TableSize;
Cell* TheCells;
};
int NextPrime(int N) {
if (N % 2 == 0)
++N;
int i;
bool NotPrime = false;
for (; ; N += 2) {
NotPrime = true;
for (i = 3; i * i <= N; i += 2)
if (N % i == 0) {
NotPrime = true;
break;
}
if (!NotPrime)
return N;
}
}
Index Hash(const char* Key, int TableSize) {
unsigned int HashVal = 0;
while (*Key != '\0')
HashVal = (HashVal << 5) + *Key++;
return HashVal % TableSize;
}
//初始化开放定址散列表的例程
HashTable InitializeTable(int TableSize) {
HashTable H;
int i;
if (TableSize < MinTableSize) {
printf("Tablee size too small");
return NULL;
}
/* Sllocate table */
H = (HashTbl*)malloc(sizeof(struct HashTbl));
if (H == NULL)
printf("out of space!!!");
H->TableSize = NextPrime(TableSize);
/* Allocate array of Cells */
H->TheCells = (Cell*)malloc(sizeof(Cell) * H->TableSize);
if (H->TheCells == NULL)
printf("out of space!!!");
for (i = 0; i < H->TableSize; i++)
H->TheCells[i].Info = Empty;
return H;
}
HashTable in(int TableSize) {
HashTable H;
int i;
H = (HashTable)malloc(sizeof(struct HashTbl));
if (H == NULL)
printf("out of space!!!");
H->TableSize = NextPrime(TableSize);
H->TheCells = (Cell*)malloc(sizeof(Cell) * TableSize);
if (H->TheCells == NULL)
printf("out of space!!!");
for (i = 0; i < TableSize; i++) {
H->TheCells[i].Info = Empty;
}
return H;
}
//使用平方探测散列法的Find例程
Position Find(ElementType Key, HashTable H) {
Position CurrentPos;
int CollisionNum;
CollisionNum = 0;
CurrentPos = Hash(Key, H->TableSize);
while (H->TheCells[CurrentPos].Info != Empty && H->TheCells[CurrentPos].Element != Key)
/* Probably need strcmp!! */
{
CurrentPos += 2 * ++CollisionNum - 1;
if (CurrentPos >= H->TableSize)
CurrentPos -= H->TableSize;
}
return CurrentPos;
}
//使用平方探测散列表的插入例程
void Insert(ElementType Key, HashTable H) {
Position Pos;
Pos = Find(Key, H);
if (H->TheCells[Pos].Info != Legitimate) {
/* OK to insert here */
H->TheCells[Pos].Info = Legitimate;
H->TheCells[Pos].Element = Key;
/* Probably need strcpy */
}
}
//对开放定址散列表的再散列
HashTable Rehash(HashTable H) {
int i, OldSize;
Cell* OldCells;
OldCells = H->TheCells;
OldSize = H->TableSize;
/* Get a new, empty table */
H = InitializeTable(2 * OldSize);
/* Scan through old table,reiinserting into new */
for (i = 0; i < OldSize; i++)
if (OldCells[i].Info == Legitimate)
Insert(OldCells[i].Element, H);
free(OldCells);
return H;
}
6 优先队列(堆)
6.1 二叉堆
因为完全二叉树很有规律,所以它可以用一个数组表示而不需要指针。对于数组中任一位置i上的元素,其左儿子在位置2i上,右儿子(在左儿子后的单元2i+1)中,它的父亲则在位置[i/2]上。
03011222192
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7bk9UI5s-1675990011909)(D:/pictures/3.png)]
#include<stdio.h>
#include<stdlib.h>
#define MinPQSize 5
#define MinData -217
typedef int ElementType;
//优先队列的声明
#ifndef _BinHeap_H
struct HeapStruct;
typedef struct HeapStruct* PriorityQueue;
PriorityQueue Initialize(int MaxElemets);
void Destroy(PriorityQueue H);
void MakeEmpty(PriorityQueue H);
void Insert(ElementType X, PriorityQueue H);
ElementType DeleteMiin(PriorityQueue H);
ElementType FindMin(PriorityQueue H);
int IsEmpty(PriorityQueue H);
int IsFull(PriorityQueue H);
#endif
/* Place in implementation file */
struct HeapStruct {
int Capacity;
int Size;
ElementType* Elements;
};
//
PriorityQueue Initialize(int MaxElements) {
PriorityQueue H;
if (MaxElements < MinPQSize)
printf("Priority queue size is too small");
H = (HeapStruct*)malloc(sizeof(struct HeapStruct));
if (H == NULL)
printf("out of space!!!");
/* Allocate the array plus on extra for sentinel */
H->Elements = (ElementType*)malloc((MaxElements + 1) * sizeof(ElementType));
if (H->Elements == NULL)
printf("out of space!!!");
H->Capacity = MaxElements;
H->Size = 0;
H->Elements[0] = MinData;
return H;
}
//插入到一个二叉堆的过程
/* H->Element[0] is a sentinel */
void Insert(ElementType X, PriorityQueue H) {
int i;
if (IsFull(H)) {
printf("Priority queue is full");
return;
}
for (i = ++H->Size; H->Elements[i / 2] > X; i /= 2)
H->Elements[i] = H->Elements[i / 2];
H->Elements[i] = X;
}
//在二叉堆中执行DeleteMin的函数
ElementType DeleteMin(PriorityQueue H) {
int i, Child;
ElementType MinElement, LastElement;
if (IsEmpty(H)) {
printf("Priority queue is empty");
return H->Elements[0];
}
MinElement = H->Elements[1];
LastElement = H->Elements[H->Size--];
for (i = 1; i * 2 <= H->Size; i = Child) {
/* Find smaller child */
Child = i * 2;
if (Child != H->Size && H->Elements[Child + 1] < H->Elements[Child])
Child++;
/* Percolate one level */
if (LastElement > H->Elements[Child])
H->Elements[i] = H->Elements[Child];
else
break;
}
H->Elements[i] = LastElement;
return MinElement;
}
/*
//BuildHeap的简要代码
for (i = N / 2; i > 0; i--)
PercolateDown(i);
*/
6.2 左式堆
零路径
#include<stdio.h>
#include<stdlib.h>
typedef int ElementType;
//左式堆类型声明
#ifndef _LeftHeap_H
struct TreeNode;
typedef struct TreeNode* PriorityQueue;
/* Minimal set of priority queue operations */
/* Note that nodes will be shared among several */
/* leftist heaps after a merge; the user must */
/* make sure to not use the old leftist heaps */
PriorityQueue Initialize(void);
ElementType FindMin(PriorityQueue H);
int IsEmpty(PriorityQueue H);
PriorityQueue Merge(PriorityQueue H1, PriorityQueue H2);
#define Insert(X,H) (H=Insert1(X),h))
/* DeleteMin macro is left as an exercise */
PriorityQueue Insert1(ElementType X, PriorityQueue H);
PriorityQueue DeleteMin1(PriorityQueue H);
#endif
/* Place in implementation file */
struct TreeNode {
ElementType Element;
PriorityQueue Left;
PriorityQueue Right;
int Npl;
};
//
PriorityQueue Merge(PriorityQueue H1, PriorityQueue H2) {
if (H1 == NULL)
return H2;
if (H2 == NULL)
return H1;
if (H1->Element < H2->Element)
return Merge1(H1, H2);
else
return Merge1(H2, H1);
}
static PriorityQueue Merge1(PriorityQueue H1, PriorityQueue H2) {
if (H1->Left == NULL)/* Single node */
H1->Left = H2;/* H1->Right is already 0*/
else {
H1->Right = Merge(H1->Right, H2);
if (H1->Left->Npl < H1->Right->Npl)
SwapChildren(H1);
H1->Npl = H1->Right->Npl + 1;
}
return H1;
}
PriorityQueue Insert1(ElementType X, PriorityQueue H) {
PriorityQueue SingleNode;
SingleNode = (PriorityQueue)malloc(sizeof(struct TreeNode));
if (SingleNode == NULL)
printf("out of space");
else {
SingleNode->Element = X;
SingleNode->Npl = 0;
SingleNode->Left = SingleNode->Right = NULL;
H = Merge(SingleNode, H);
}
return H;
}
/* DeleteMin1 returns the new tree; */
/* To get the minimum,use FindMin */
/* This is for convenience */
PriorityQueue DeleteMin1(PriorityQueue H) {
PriorityQueue LeftHeap, RightHeap;
if (IsEmpty(H)) {
printf("Priority queue is empty");
return H;
}
LeftHeap = H->Left;
RightHeap = H->Right;
free(H);
return Merge(LeftHeap, RightHeap);
}
6.3 二项队列结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Kndj7sJ-1675990011913)(D:/pictures/6.png)]
#include<stdio.h>
#include<stdlib.h>
typedef int ElementType;
#define MaxTrees 99
#define Infinity 99999
//二项队列类型声明
typedef struct BinNode* BinTree;
typedef struct BinNode* Position;
typedef struct Collection* BinQueue;
struct BinNode {
ElementType Element;
Position LeftChild;
Position NextSibling;
};
struct Collection {
int CurrentSize;
BinTree TheTrees[MaxTrees];
};
//合并同样大小两棵二项树的例程
/* Return the result of merging equal-sized T1 and T2 */
BinTree CombineTrees(BinTree T1, BinTree T2) {
if (T1->Element > T2->Element)
return CombineTrees(T2, T1);
T2->NextSibling = T1->LeftChild;
T1->LeftChild = T2;
return T1;
}
BinTree combinTrees(BinTree T1, BinTree T2) {
if (T1->Element > T2->Element)
return combinTrees(T2, T1);
T2->NextSibling = T1->LeftChild;
T1->LeftChild = T2;
return T1;
}
//合并两个优先队列的例程
/* Merge two binomial queues */
/* Not optimized for early termination */
/* H1 contains merged result */
BinQueue Merge(BinQueue H1, BinQueue H2) {
BinTree T1, T2, Carry = NULL;
int i, j;
if (H1->CurrentSize + H2->CurrentSize > Capacity)
printf("Merge would exceed capacity");
H1->CurrentSize += H2->CurrentSize;
for (i = 0, j = 1; j <= H1->CurrentSize; i++, j *= 2) {
T1 = H1->TheTrees[i];
T2 = H2->TheTrees[i];
switch (!!T1 + 2 * !!T2 + 4 * !!Carry) {/* 0 1 */
case 0:/* No trees */
case 1:/* Only H1 */
break;
case 2:/* Only H2 */
H1->TheTrees[i] = T2;
H2->TheTrees[i] = NULL;
break;
case 4:/* Only Carry */
H1->TheTrees[i] = Carry;
Carry = NULL;
break;
case 3:/* H1 and H2 */
Carry = CombineTrees(T1, T2);
H1->TheTrees[i] = H2->TheTrees[i] = NULL;
break;
case 5:/* H1 and Carry */
Carry = CombineTrees(T1, Carry);
H1->TheTrees[i] = NULL;
break;
case 6:/* H2 and Carry */
Carry = CombineTrees(T2, Carry);
H2->TheTrees[i] = NULL;
break;
case 7:/* All three */
H1->TheTrees[i] = Carry;
Carry = CombineTrees(T1, T2);
H2->TheTrees[i] = NULL;
break;
}
}
return H1;
}
//二项队列的DeleteMin
ElementType DeleteMin(BinQueue H) {
int i, j;
int MinTree;/* The tree with the minimum item */
BinQueue DeletedQueue;
Position DeletedTree, OldRoot;
ElementType MinItem;
if (IsEmpty(H)) {
printf("Empty binomial queue");
return -Infinity;
}
MinItem = Infinity;
for (i = 0; i < MaxTrees; i++) {
if (H->TheTrees[i] && H->TheTrees[i]->Element < MinItem) {
/* Update minimum */
MinItem = H->TheTrees[i]->Element;
MinTree = i;
}
}
DeletedTree = H->TheTrees[MinTree];
OldRoot = DeletedTree;
DeletedTree = DeletedTree->LeftChild;
free(OldRoot);
DeletedQueue = Initialize();
DeletedQueue->CurrentSize = (1 << MinTree) - 1;
for (j = MinTree - 1; j >= 0; j--) {
DeletedQueue->TheTrees[j] = DeletedTree;
DeletedTree = DeletedTree->NextSibling;
DeletedQueue->TheTrees[j]->NextSibling = NULL;
}
H->TheTrees[MinTree] = NULL;
H->CurrentSize -= DeletedQueue->CurrentSize + 1;
Merge(H, DeletedQueue);
return MinItem;
}
7 排序
整个排序工作能够在主存中完成,元素的个数相对来说比较小(小于10^6)。不能在主存中完成而必须在磁盘或磁带上完成的排序也相当重要。这种类型的排序叫做外部排序。
插入,冒泡,选择n^2
7.1 插入排序
typedef int ElementType;
//插入排序例程
void InsertSort(ElementType A[], int N) {
int j, P;
ElementType Tmp;
for (P = 1; P < N; P++) {
Tmp = A[P];
for (j = P; j > 0 && A[j - 1] > Tmp; j--)
A[j] = A[j - 1];
A[j] = Tmp;
}
}
7.2 希尔排序
(缩小增量排序)
typedef int ElementType;
//使用希尔增量的希尔排序例程(可能有更好的增量)
void Shellsort(ElementType A[], int N) {
int i, j, Increment;
ElementType Tmp;
for (Increment = N / 2; Increment > 0; Increment /= 2)
for (i = Increment; i < N; i++) {
Tmp = A[i];
for (j = i; j >= Increment; j -= Increment)
if (Tmp < A[j - Increment])
A[j] = A[j - Increment];
else
break;
A[j] = Tmp;
}
}
7.3 堆排序
typedef int ElementType;
#define LeftChild(i)(2*(i)+1)
//堆排序
void PercDown(ElementType A[], int i, int N) {
int Child;
ElementType Tmp;
for (Tmp = A[i]; LeftChild(i) < N; i = Child) {
Child = LeftChild(i);
if (Child != N - 1 && A[Child + 1] > A[Child])
Child++;
if (Tmp < A[Child])
A[i] = A[Child];
else
break;
}
A[i] = Tmp;
}
void Swap(ElementType* a, ElementType* b) {
ElementType Tmp = *a;
*a = *b;
*b = Tmp;
}
void Heapsort(ElementType A[], int N) {
int i;
for (i = N / 2; i >= 0; i--)/* BuildHeap */
PercDown(A, i, N);
for (i = N - 1; i > 0; i--) {
Swap(&A[0], &A[i]);/* DeleteMax */
PercDown(A, 0, i);
}
}
7.4 归并排序
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
typedef int ElementType;
//归并排序例程
void MSort(ElementType A[], ElementType TmpArray[], int Left, int Right) {
int Center;
if (Left < Right) {
Center = (Left + Right) / 2;
MSort(A, TmpArray, Left, Center);
MSort(A, TmpArray, Center + 1, Right);
Merge(A, TmpArray, Left, Center + 1, Right);
}
}
void Mergesort(ElementType A[], int N) {
ElementType* TmpArray;
TmpArray = (ElementType*)malloc(N * sizeof(ElementType));
if (TmpArray != NULL) {
MSort(A, TmpArray, 0, N - 1);
free(TmpArray);
}
else
FatalError("No space for tmp array!!!");
}
/* Lpos = start of left half, Rpos = start of right half */
void Merge(ElementType A[], ElementType TmpArray[], int Lpos, int Rpos, int RightEnd) {
int i, LeftEnd, NumElements, TmpPos;
LeftEnd = Rpos - 1;
TmpPos = Lpos;
NumElements = RightEnd - Lpos + 1;
/* main loop */
while (Lpos <= LeftEnd && Rpos <= RightEnd)
if (A[Lpos] <= A[Rpos])
TmpArray[TmpPos++] = A[Rpos++];
while (Lpos <= LeftEnd)/* Copy rest of first half */
TmpArray[TmpPos++] = A[Rpos++];
/* Copy TmpArray back */
for (i = 0; i < NumElements; i++, RightEnd--)
A[RightEnd] = TmpArray[RightEnd];
}
7.5 快速排序
D&C
n log n
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
typedef int ElementType;
void Swap(ElementType* a, ElementType* b) {
ElementType Tmp = *a;
*a = *b;
*b = Tmp;
}
//插入排序例程
void InsertionSort(ElementType A[], int N) {
int j, P;
ElementType Tmp;
for (P = 1; P < N; P++) {
Tmp = A[P];
for (j = P; j > 0 && A[j - 1] > Tmp; j--)
A[j] = A[j - 1];
A[j] = Tmp;
}
}
//快速排序的驱动程序
void Quicksort(ElementType A[], int N) {
Qsort(A, 0, N - 1);
}
//实现三数中值分割方法的程序
/* Return median of Left, Center, and Right */
/* Order these and hide the pivot */
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]);
/* Invariant:A[Left]<=A[Center]<=A[Right] */
Swap(&A[Center], &A[Right - 1]);/* Hide pivot */
return A[Right - 1];/* return pivot */
}
//快速排序的主例程
#define Cutoff (3)
void Qsort(ElementType A[], int Left, int Right) {
int i, j;
ElementType Pivot;
if (Left + Cutoff <= Right) {
Pivot = Median3(A, Left, Right);
i = Left;
j = Right - 1;
for (;;) {
while (A[++i] < Pivot) {}
while (A[--j] > Pivot) {}
if (i < j)
Swap(&A[i], &A[j]);
else
break;
}
Swap(&A[i], &A[Right - 1]);/* Restore pivot */
Qsort(A, Left, i - 1);
Qsort(A, i + 1, Right);
}
else/* Do an insertion sort on the subarray */
InsertionSort(A + Left, Right - Left + 1);
}
//快速选择的主例程
/* Places the kth smallest element in the kth position */
/* Because arrays start at 0, this will be index k-1 */
void Qselect(ElementType A[], int k, int Left, int Right) {
int i, j;
ElementType Pivot;
if (Left + Cutoff <= Right) {
Pivot = Median3(A, Left, Right);
/*
i = Left;
j = Right - 1;
for (;;) {
while (A[++i] < Pivot) {}
while (A[--j] > Pivot) {}
if (i < j)
Swap(&A[i], &A[j]);
else
break;
}
*/
i = Left + 1; j = Right - 2;
for (;;) {
while (A[i] < Pivot)i++;
while (A[j > Pivot])j--;
if (i < j)Swap(&A[i], &A[j]);
else break;
}
Swap(&A[i], &A[Right - 1]);/* Restore pivot */
if (k <= i)
Qselect(A, k, Left, i - 1);
else if (k > i + 1)
Qselect(A, k, i + 1, Right);
}
else/* Do an insertion sort on the subarray */
InsertionSort(A + Left, Right - Left + 1);
}
typedef int ElementType;
void qsor(ElementType a[], int begin, int end) {
if (begin > end)return;
ElementType tem = a[begin];
int i = begin;
int j = end;
while (i != j) {
while (a[j] >= tem && j > i)j--;
while (a[i] <= tem && j > i)i++;
if (j > i) {
ElementType t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
a[begin] = a[i];
a[i] = tem;
qsorT(a, begin, i - 1);
qsorT(a, i + 1, end);
}
7.6 桶式排序
7.7 外部排序
8 不相交集ADT
#include<stdio.h>
#include<stdlib.h>
#define NumSets 99
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
typedef int ElementType;
//不相交集合的类型声明
#ifndef _DisjSet_H
typedef int DisjSet[NumSets + 1];
typedef int SetType;
typedef int ElementType;
void Initilialize(DisjSet S);
void SetUnion(DisjSet S, SetType Root1, SetType Root2);
SetType Find(ElementType X, DisjSet S);
#endif /* _DisjSet_H */
//不相交集合的初始化例程
void Initialize(DisjSet S) {
int i;
for (i = NumSets; i > 0; i--)
S[i] = 0;
}
//Union(不是最好的方法)
/* Assumes Root1 and Root2 are roots */
/* union is a C keyword, so this routine */
/* is named SetUnion */
void SetUnionN(DisjSet S, SetType Root1, SetType Root2) {
S[Root2] = Root1;
}
//一个简单不相交集合Find算法
SetType FindS(ElementType X, DisjSet S) {
if (S[X] <= 0)
return X;
else
return FindS(S[X], S);
}
//按高度(秩)求并的程序
/* Assumes Root1 and Root2 are roots */
/* union is a C keyword, so this routine */
/* is named SetUnion */
void SetUnion(DisjSet S, SetType Root1, SetType Root2) {
if (S[Root2] < S[Root1])/* Root2 is deeper set */
S[Root1]=Root2;/* Make Root2 new root */
else {
if (S[Root1] == S[Root2])/* Same height */
S[Root1]--;/* suo update */
S[Root2] = Root1;
}
}
//用路径压缩进行不相交集Find的程序
SetType Find(ElementType X, DisjSet S) {
if (S[X] <= 0)
return X;
else
return S[X] = Find(S[X], S);
}
9 图论算法
当前,还不存在找出从s到一个顶点的路径比找出从s到所有顶点路径更快(快多于一个常数因子)的算法。
9.6深度优先搜索的应用
双连通
如果一个连通的无向图中的任一顶点删除之后,剩下的图仍然连通,那么这样的无向连通图就是双连通的。
9.6.3欧拉回路
所有顶点的度(边的条数)均为偶数的任何连通图必然有欧拉回路。可以以线性时间找出这样一条回路。
9.6.5查找强分支
通过执行两次深度优先搜索,可以检测一个有向图是否是强连通的,如果它不是强连通的,那么我们实际上可以得到顶点的一些子集。
NP中的每一个问题都可以用一台非确定型计算机在多项式时间内求解。
除可满足问题外,哈米尔顿回路问题,巡回售货员问题,最长路径问题、图的着色问题以及团的问题都是著名的NP-完全问题。NP-完全问题相当广泛,包括来自操作系统(调度和安全)、数据库系统、运筹学、逻辑学、特别是图论等不同领域的问题。
10 算法设计技巧
10.1贪婪算法
如果所有的字符都以相同的频率出现,那么要节省空间是不可能的。
满树:所有的节点或者是树叶,或者有两个儿子。
近似装箱问题
存在使得任意联机装箱算法至少使用4/3最优箱子数的输入。
首次适合算法用到的大约比最优装箱方法多2%的箱子。
传统上,在正文中至少含有两个递归调用的例程叫做分治算法,而正文中只含一个递归调用的例程不是分治算法。
使用“五分化中项的中项”的快速选择算法的运行时间为O(N)。
10.3 动态规划
任何数学递归公式都可以直接翻译成递归算法。将递归算法重新写成非递归算法,让后者把那些子问题的答案系统地记录在一个表内。
在一步内删除一大组可能性的做法叫做裁剪。
12 高级数据结构及其实现
12.1 自顶向下伸展树
插入,查找(没找到最后一个节点展开)。
#include<stdio.h>
#include<stdlib.h>
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
//伸展树:声明和初始化
typedef int ElementType;
#ifndef _Splay_H
struct SplayNode;
typedef struct SplayNode* SplayTree;
SplayTree MakeEmpty(SplayTree T);
SplayTree Find(ElementType X, SplayTree T);
SplayTree FinMin(SplayTree T);
SplayTree FindMax(SplayTree T);
SplayTree Initialize(void);
SplayTree Insert(ElementType X, SplayTree T);
SplayTree Remove(ElementType X, SplayTree T);
ElementType Retrieve(SplayTree T);/* Gets root item */
static Position SingleRotateWithLeft(Position k2);
static Position SingleRotateWithRight(Position k2);
#endif /* _Splay_H */
/* Place in the implementation file */
struct SplayNode {
ElementType Element;
SplayTree Left;
SplayTree Right;
};
typedef struct SplayNode* Position;
static Position NullNode = NULL;/* Needs initialization */
static Position SingleRotateWithLeft(Position k2) {
Position k1;
k1 = k2->Left;
k2->Left = k1->Right;
k1->Right = k2;
return k1; /* New root */
}
static Position SingleRotateWithRight(Position k2) {
Position k1;
k1 = k2->Right;
k2->Right = k1->Left;
k1->Left = k2;
return k1; /* New root */
}
SplayTree Initialize(void) {
if (NullNode == NULL) {
NullNode = (Position)malloc(sizeof(struct SplayNode));
if (NullNode == NULL)
FatalError("out of space!!!");
NullNode->Left = NullNode->Right = NULL;
}
return NullNode;
}
/* 自顶向下的展开过程 */
/* Top-down splay procedure, not requiring Item to be in the tree */
SplayTree Splay(ElementType Item, Position X) {
static struct SplayNode Header;
Position LeftTreeMax, RightTreeMin;
Header.Left = Header.Right = NullNode;
LeftTreeMax = RightTreeMin = &Header;
NullNode->Element = Item;
while (Item != X->Element) {
if (Item < X->Element) {
if (Item < X->Left->Element)
X = SingleRotateWithLeft(X);
if (X->Left == NullNode)
break;
/* Link right */
RightTreeMin->Left = X;
RightTreeMin = X;
X = X->Left;
}
else {
if (Item > X->Right->Element)
X = SingleRotateWithRight(X);
if (X->Right == NullNode)
break;
/* Link Left */
LeftTreeMax->Right = X;
LeftTreeMax = X;
X = X->Right;
}
}/* while Item!=X->Element */
/* Reassemble */
LeftTreeMax->Right = X->Left;
RightTreeMin->Left = X->Right;
X->Left = Header.Right;
X->Right = Header.Left;
return X;
}
/* 自顶向下伸展树的插入 */
SplayTree Insert(ElementType Item, SplayTree T) {
static Position NewNode = NULL;
if (NewNode == NULL) {
NewNode = (Position)malloc(sizeof(struct SplayNode));
if (NewNode == NULL)
FatalError("out of space!!!");
}
NewNode->Element = Item;
if (T == NullNode) {
NewNode->Left = NewNode->Right = NullNode;
T = NewNode;
}
else {
T = Splay(Item, T);
if (Item < T->Element) {
NewNode->Left = T->Left;
NewNode->Right = T;
T->Left = NullNode;
T = NewNode;
}
else if (T->Element < Item) {
NewNode->Right = T->Right;
NewNode->Left = T;
T->Right = NullNode;
}
else
return T;/* Already in the tree */
}
NewNode = NULL;/* So next insert will call mmalloc */
return T;
}
/* 自顶向下的删除过程 */
SplayTree Remove(ElementType Item, SplayTree T) {
Position NewTree;
if (T != NullNode) {
T = Splay(Item, T);
if (Item == T->Element) {
/* Found it! */
if (T->Left == NullNode)
NewTree = T->Right;
else {
NewTree = T->Left;
NewTree = Splay(Item, NewTree);
NewTree->Right = T->Right;
}
free(T);
T = NewTree;
}
}
return T;
}
12.2红黑树
//使用两个标记对树的中序遍历
/* Print the tree,watch out for NullNode */
/* and skip header */
static void DoPrint(RedBlackTree T) {
if (T != NullNode) {
DoPrint(T->Left);
Output(T->Element);
DoPrint(T->Right);
}
}
void PrintTree(RedBlackTree T) {
DoPrint(T->Right);
}
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
typedef int ElementType;
//类型声明和初始化
struct RedBlackNode;
typedef enum ColorType{Red,Black}ColorType;
typedef RedBlackNode* RedBlackTree;
typedef RedBlackNode* Position;
struct RedBlackNode {
ElementType Element;
RedBlackTree Left;
RedBlackTree Right;
ColorType Color;
};
Position NullNode = NULL; /* Needs initialization */
/* Initialization procedure */
RedBlackTree Initialize(void) {
RedBlackTree T;
if (NullNode == NULL) {
NullNode = (Position)malloc(sizeof(struct RedBlackNode));
if (NullNode == NULL)
FatalError("out of space");
NullNode->Left = NullNode->Right = NullNode;
NullNode->Color = Black;
NullNode->Element = INFINITY;
}
/* Create the header node */
T = (RedBlackTree)malloc(sizeof(struct RedBlackNode));
if (T == NULL)
FatalError("out of space");
T->Element = -INFINITY;
T->Left = T->Right = NullNode;
T->Color = Black;
return T;
}
/* 旋转过程 */
/* Perform a rotation at node X */
/* (whose parent is passed as a parameter) */
/* The child is deduced by examining Item */
static Position Rotate(ElementType Item, Position Parent) {
if (Item < Parent->Element)
return Parent->Left = Item < Parent->Left->Element ?
SingleRotateWithLeft(Parent->Left) :
SingleRotateWithRight(Parent->Left);
else
return Parent->Right = Item < Parent->Right->Element ?
SingleRotateWithLeft(Parent->Right) :
SingleRotateWithRight(Parent->Right);
}
/* 插入过程 */
static Position X, P, GP, GGP;
static void HandleReorient(ElementType Item, RedBlackTree T) {
X->Color = Red;/* Do the color flip */
X->Left->Color = Black;
X->Right->Color = Black;
if (P->Color == Red) /* Have to rotate */
{
GP->Color = Red;
if ((Item < GP->Element) != (Item < P->Element))
P = Rotate(Item, GGP);/* Start double rotation */
X = Rotate(Item, GGP);
X->Color = Black;
}
T->Right->Color = Black;/* Make root black */
}
RedBlackTree Insert(ElementType Item, RedBlackTree T) {
X = P = GP = T;
NullNode->Element = Item;
while (X->Element != Item)/* Descend down the tree */
{
GGP = GP;
GP = P;
P = X;
if (Item < X->Element)
X = X->Left;
else
X = X->Right;
if (X->Left->Color == Red && X->Right->Color == Red)
HandleReorient(Item, T);
}
if (X != NullNode)
return NullNode;/* Duplicate */
X = (Position)malloc(sizeof(struct RedBlackNode));
if (X == NULL)
FatalError("out of space");
X->Element = Item;
X->Left = X->Right = NullNode;
if (Item < P->Element)/* Attach to its parent */
P->Left = X;
else
P->Right = X;
HandleReorient(Item, T);/* Color red;maybe rotate */
return T;
}
//使用两个标记对树的中序遍历
/* Print the tree,watch out for NullNode */
/* and skip header */
static void DoPrint(RedBlackTree T) {
if (T != NullNode) {
DoPrint(T->Left);
Output(T->Element);
DoPrint(T->Right);
}
}
void PrintTree(RedBlackTree T) {
DoPrint(T->Right);
}