第 02 章 線性表
順序存儲結構
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;
#define LIST_INIT_SIZE 100 // 初始分配量
#define LIST_INCREMENT 10 // 增量
typedef struct {
ElemType *elem; // 數組
int length; // 有效長度
int listSize; // 分配的空間
} SqList;
/**
* 初始化
*/
Status initList(SqList *L) {
L->elem = (ElemType *) malloc(LIST_INIT_SIZE * sizeof(ElemType)); // 開辟初始空間
if (L->elem == NULL) {
return ERROR;
}
L->length = 0;
L->listSize = LIST_INIT_SIZE;
return OK;
}
/**
* 銷毀
*/
Status destroyList(SqList *L) {
free(L);
return OK;
}
/**
* 插入算法
* 1宴猾,判斷插入位置i的合法性
* 2趣倾,若存儲空間滿了則增空間
* 3檐蚜,將i-1位置以及其往后的元素像后移動一位
* 4恬偷,將i-1位置的元素賦值為e
* 5缆镣,有效長度增加1
*/
Status insertList(SqList *L, int i, ElemType e) {
if (i < 1 || i > L->length + 1) { // 當i == L->length + 1 是插入在末尾的
return ERROR;
}
if (L->length >= L->listSize) {
ElemType *newbase = (ElemType *) realloc(L->elem, (L->listSize + LIST_INCREMENT) * sizeof(ElemType));
if (newbase == NULL) exit(OVERFLOW);
L->elem = newbase;
L->listSize += LIST_INCREMENT;
}
for (int j = L->length - 1; j >= i - 1; --j) {
L->elem[j + 1] = L->elem[j]; // 逐個往后移
}
L->elem[i - 1] = e;
++L->length;
return OK;
}
/**
* 刪除操作
* 1戚扳,判斷刪除位置i的合理性
* 2蝌箍,將i-1位置往后的元素前移一個位置
* 3么翰,有效長度減一
*/
Status deleteList(SqList *L, int i) {
if (i < 1 || i > L->length) return ERROR;
for (int j = i - 1; j < L->length; ++j) {
L->elem[j] = L->elem[j + 1]; // 逐個往前移
}
--L->length;
return OK;
}
/**
* 遍歷
*/
void traverseList(SqList L) {
printf("SqList = [");
for (int i = 0; i < L.length; ++i) {
printf("%d", L.elem[i]);
if (i != L.length - 1)printf(", ");
}
printf("]\n");
}
/**
* 獲取元素
* 因為用的是數組牺汤,所以這個操作非常方便
*/
Status getElem(SqList L, int i, ElemType *e) {
*e = L.elem[i - 1];
return OK;
}
/**
* 測試
*/
int main() {
SqList L;
initList(&L);
insertList(&L, 1, 54);
insertList(&L, 1, 78);
insertList(&L, 1, 20);
insertList(&L, 2, 19);
traverseList(L);
deleteList(&L, 1);
traverseList(L);
ElemType result;
getElem(L, 2, &result);
printf("result = %d\n", result);
return 0;
}
鏈式存儲結構
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;
typedef struct LNode {
ElemType data; // 數據域
struct LNode *next; // 指針域
} LNode,*LinkList; // LinkList是指向單鏈表的指針,由此唯一確定一個單鏈表
Status initList(LinkList *head) {
(*head) = (LinkList) malloc(sizeof(LNode)); // 頭指針指向頭節(jié)點
(*head)->next = NULL;
return OK;
}
/**
* 頭插法創(chuàng)建鏈表(為了方便測試浩嫌,選擇接受一個數組后寫入)
* 頭插法每次新增的結點都在頭部
*/
void createListFromHead(LinkList *head, int n, ElemType arr[]) {
// 創(chuàng)建鏈表
(*head) = (LinkList) malloc(sizeof(LNode));
(*head)->next = NULL;
// 循環(huán)寫入
LNode *p;
for (int i = n - 1; i >= 0; --i) {
p = (LNode *) malloc(sizeof(LNode));
p->data = arr[i];
p->next = (*head)->next;
(*head)->next = p;
}
}
/**
* 尾插法創(chuàng)建鏈表(為了方便測試檐迟,選擇接受一個數組后寫入)
* 尾插法每次新增加的結點都在尾部
*/
void createListFromTail(LinkList *head, int n, ElemType arr[]) {
// 創(chuàng)建鏈表
(*head) = (LinkList) malloc(sizeof(LNode));
LNode *p;
LNode *r;
r = *head; // 尾指針
for (int i = 0; i < n; ++i) {
// 創(chuàng)建新結點并賦值
p = (LNode *) malloc(sizeof(LNode));
p->data = arr[i];
r->next = p; // 尾指針的指針域指向新結點,如果是第一個結點可表示為 (*head)->next = p;
r = p; // 尾指針指向尾部
}
r->next = NULL;
}
// 遍歷輸出
void traverList(LinkList L) {
LNode *p = L->next;
printf("LinkList = [");
while (p) {
printf("%d", p->data);
p = p->next;
if (p) printf(", ");
}
printf("]\n");
}
/**
* 插入算法
* 1码耐,找到位置為i-1的元素
* 2追迟,生成新結點
* 3,新節(jié)點的指針域指向位置為i的元素骚腥,位置為i-1的元素的指針域指向新結點
*/
Status insertList(LinkList *head, int i, ElemType e) {
LNode *p = *head;
int k = 0;
while (p && k < i - 1) { // 這里改為 k <= i-2 可能更好理解一些敦间,
p = p->next;
++k;
}
if (p == NULL || k > i - 1) return ERROR; // 很明顯,這里k是不可能大于i-1的束铭,這里體現了代碼的健壯性
LNode *s = (LNode *) malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
/**
* 刪除算法
* 1廓块,找到位置為i-1的元素
* 2,令位置為i-1的元素指向位置為i+1的元素
* 3契沫,釋放位置為i的空間
*/
Status deleteList(LinkList *head, int i) {
LNode *p = *head;
int k = 0;
while (p->next && k < i - 1) {
p = p->next;
++k;
}
if (p->next == NULL || k > i - 1) return ERROR;
LNode *q = p->next; // 位置是i
p->next = p->next->next;
free(q);
return OK;
}
/*
* 獲取元素
* 算法:使用j來計數剿骨,到i-1個元素為止
*/
Status getElem(LinkList head, int i, ElemType *e) {
LNode *p = head;
int j = 0;
while (p != NULL && j <= i-1) {
p = p->next;
++j;
}
*e = p->data;
return OK;
}
int main() {
LinkList head;
int a[] = {1, 2, 3};
createListFromHead(&head, 3, a);
traverList(head);
insertList(&head, 2, 8);
traverList(head);
deleteList(&head, 3);
traverList(head);
ElemType result;
getElem(head, 2, &result);
printf("result = %d\n", result);
LinkList head02;
int b[] = {8, 12, 3, 56};
createListFromTail(&head02, 4, b);
traverList(head02);
return 0;
}
第 03 章 棧與隊列
順序棧
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int SElemType;
typedef int Status;
#define STACK_INIT_SIZE 100 // 初始分配量
#define STACK_INCREMENT 10 // 增量
typedef struct {
SElemType *base; // 棧底指針
SElemType *top; // 棧頂指針,靈魂所在
int stackSize; // 分配的空間
} SqStack;
Status initStack(SqStack *S) {
S->base = (SElemType *) malloc(STACK_INIT_SIZE * sizeof(SqStack));
if (S->base == NULL) exit(OVERFLOW);
S->top = S->base; // 表示空棧
S->stackSize = STACK_INIT_SIZE;
return OK;
}
/**
* 進棧操作
* 如果棧的長度為stackSize埠褪,擴大空間
*/
Status push(SqStack *S, SElemType e) {
if (S->top - S->base == S->stackSize) {
SElemType *newBase = realloc(S->base, (STACK_INIT_SIZE + STACK_INCREMENT) * sizeof(SqStack));
if (newBase == NULL) exit(OVERFLOW);
S->top = S->base + S->stackSize;
S->base = newBase;
S->stackSize += STACK_INCREMENT;
}
*(S->top) = e;
S->top++;
return OK;
}
/*
* 出棧操作
*/
Status pop(SqStack *S) {
if (S->top == S->base) return ERROR;
--S->top; // 向下移動一個位置
SElemType elem = *(S->top);
printf("SqStack pop elem = %d\n", elem);
return OK;
}
void getTop(SqStack S) {
if (S.top == S.base) return;
SElemType top = *(S.top - 1);
printf("SqStack top = %d\n", top);
}
/*
* 遍歷
*/
void traverseStack(SqStack S) {
SElemType *p = S.base;
printf("SqStack = [");
while (p < S.top) {
printf("%d", *p);
++p;
if (p != S.top) printf(", ");
}
printf("]\n");
}
int main() {
SqStack S;
initStack(&S);
push(&S, 2);
push(&S, 6);
traverseStack(S);
getTop(S);
pop(&S);
traverseStack(S);
return 0;
}
鏈棧
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int SElemType;
typedef int Status;
typedef struct StackNode {
SElemType data;
struct StackNode *next;
} StackNode, *LinkStackPtr;
typedef struct LinkStack {
LinkStackPtr top;
int count;
} LinkStack;
Status push(LinkStack *S, SElemType e) {
StackNode *p = (StackNode *) malloc(sizeof(StackNode));
p->data = e;
p->next = S->top;
S->top = p;
S->count++;
return OK;
}
Status pop(LinkStack *S, SElemType *e) {
StackNode *p;
*e = S->top->data;
p = S->top;
S->top = S->top->next;
free(p);
S->count--;
return OK;
}
int main() {
printf("Hello, World!\n");
return 0;
}
兩棧共享空間
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int SElemType;
typedef int Status;
#define MAX_SIZE 100
typedef struct {
SElemType data[MAX_SIZE];
int top1;
int top2;
} SqDoubleStack;
Status initStack(SqDoubleStack *S) {
// 指向各自的棧頂元素
S->top1 = -1;
S->top2 = MAX_SIZE;
}
// 壓棧操作浓利,根據stackId判斷要操作哪一個棧
Status push(SqDoubleStack *S, SElemType e, int stackId) {
// 判滿
if (S->top1 + 1 == S->top2) return ERROR;
if (stackId == 1) S->data[++S->top1] = e;
else S->data[--S->top2] = e;
return OK;
}
// 壓棧操作,根據stackId判斷要操作哪一個棧
Status pop(SqDoubleStack *S, SElemType *e, int stackId) {
if (S->top1 == -1 || S->top2 == MAX_SIZE) return ERROR;
if (stackId == 1 && S->top1 != -1) {
*e = S->data[S->top1--];
} else if (stackId == 2 && S->top2 != MAX_SIZE) {
*e = S->data[S->top2++];
}
return OK;
}
循環(huán)隊列
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAX_SIZE 100
typedef int QElemType;
typedef int Status;
/**
* 循環(huán)隊列
* 為了判端隊列是否為滿钞速,少用一個元素贷掖,判斷(Q->rear + 1) % MAX_SIZE == Q->front,為true則是隊滿
*/
typedef struct {
QElemType *base;
int front;
int rear;
} SqQueue;
Status initQueue(SqQueue *Q) {
Q->base = (QElemType *) malloc(MAX_SIZE * sizeof(QElemType));
if (Q->base == NULL) exit(OVERFLOW);
Q->front = Q->rear = 0; // 表示空隊列
return OK;
}
/**
* 隊尾入隊
*/
Status enQueue(SqQueue *Q, QElemType e) {
// 判滿
if ((Q->rear + 1) % MAX_SIZE == Q->front) {
return ERROR;
}
Q->base[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAX_SIZE; // 循環(huán)意義上的加一
return OK;
}
/**
* 隊頭出隊
*/
Status deQueue(SqQueue *Q, QElemType *e) {
// 判空
if (Q->front == Q->rear) {
return ERROR;
}
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAX_SIZE; // 循環(huán)意義的加1渴语,注意苹威,這里也是加1
return OK;
}
/**
* 獲取隊列長度
*/
int getQueueLength(SqQueue Q) {
return (Q.rear - Q.front + MAX_SIZE) % MAX_SIZE;
}
void traverQueue(SqQueue Q) {
printf("LinkQueue = [");
for (int i = Q.front; i < Q.rear; ++i) {
printf("%d", Q.base[i]);
if (i + 1 < Q.rear) printf(", ");
}
printf("]\n");
}
int main() {
SqQueue Q;
initQueue(&Q);
enQueue(&Q, 54);
enQueue(&Q, 80);
enQueue(&Q, 31);
enQueue(&Q, 26);
traverQueue(Q);
int result;
deQueue(&Q, &result);
printf("result = %d\n", result);
traverQueue(Q);
return 0;
}
鏈隊列
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int QElemType;
typedef int Status;
typedef struct QNode {
QElemType data;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct {
QueuePtr front; // 隊頭
QueuePtr rear; // 隊尾
} LinkQueue;
Status initQueue(LinkQueue *Q) {
Q->front = Q->rear = (QueuePtr) malloc(sizeof(QNode)); // 一開始都指向頭結點
if (Q->front == NULL)exit(OVERFLOW);
Q->front->next = NULL; // 此處也可以寫成 Q->rear->next = null
return OK;
}
/**
* 隊尾入隊
* 算法:
* 1,聲明結點p并分配空間
* 2驾凶,rear-next = p
* 3牙甫,rear = p
*/
Status enQueue(LinkQueue *Q, QElemType e) {
QNode *p = (QNode *) malloc(sizeof(QNode));
if (p == NULL) exit(OVERFLOW);
p->data = e;
p->next = Q->rear->next; // p->next = NULL;
Q->rear->next = p;
Q->rear = p;
return OK;
}
/**
* 隊頭出隊
*/
Status deQueue(LinkQueue *Q, QElemType *e) {
if (Q->rear == Q->front) return ERROR;
QNode *p = Q->front->next; // 隊頭
*e = p->data;
Q->front->next = p->next;
if (Q->rear == p) Q->rear = Q->front; // 特殊情況
free(p);
return OK;
}
void traverQueue(LinkQueue Q) {
QNode *p = Q.front->next;
printf("LinkQueue = [");
while (p != NULL) {
printf("%d", p->data);
p = p->next;
if (p != NULL)printf(", ");
}
printf("]\n");
}
int main() {
LinkQueue Q;
initQueue(&Q);
enQueue(&Q, 77);
enQueue(&Q, 8);
enQueue(&Q, 12);
enQueue(&Q, 35);
traverQueue(Q);
QElemType elem;
deQueue(&Q, &elem);
traverQueue(Q);
return 0;
}
第 04 章 串
kmp相關
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAXSTRLEN 255
typedef int Status;
typedef unsigned char SString[MAXSTRLEN + 1]; // 多出一個位置用于存放長度
/**
* 初始化
*/
Status initStr(SString T, const char *chars) {
int len = (int) strlen(chars);
if (len > MAXSTRLEN) {
return ERROR;
}
T[0] = len; // 定長字符串第一個元素存儲長度
for (int i = 1; i <= len; ++i) {
T[i] = chars[i - 1];
}
return OK;
}
/**
* 樸素的模式匹配算法
*/
int index_simple(SString S, SString T, int pos) {
int i = pos;
int j = 1;
while (i <= S[0] && j <= T[0]) {
if (S[i] == T[j]) {
++i;
++j;
} else {
i = i - j + 2;
j = 1;
}
}
if (j > T[0]) return i - T[0]; // 掷酗?
else return 0;
}
/**
* 獲得kmp算法要使用的next數組
* 1,固定的窟哺,第一位的next值為0泻轰,第二位的next值為1
* 2,之后每第 j 個的next值時且轨,根據第 j-1 進行比較浮声,有如下情況
* 3,如果 T[j-1] == T[next[j-1]] ,如果這兩個值相等旋奢,那么next[j] = next[j-1] +1
* 4泳挥,如果不等,則繼續(xù)沿著next值進行尋找至朗,若找到了相同的屉符,則next[j] = next[x]+1
* 5,若找不到锹引,則 next[j] = 1
*/
void get_next(SString T, int next[]) {
int i = 1;
int j = 0;
next[1] = 0; // 第一個默認為 0
while (i < T[0]) {
if (j == 0 || T[i] == T[j]) {
++i;
++j;
next[i] = j;
} else {
j = next[j];
}
}
}
/**
* 獲取nextval數組
*/
void get_nextval(SString T, int nextval[]) {
int i, j;
i = 1;
j = 0;
nextval[1] = 0;
while (i < T[0]) {
if (j == 0 || T[i] == T[j]) {
++i;
++j;
if (T[i] != T[j])
nextval[i] = j;
else
nextval[i] = nextval[j];
} else {
j = nextval[j];
}
}
}
/**
* KMP模式匹配算法
*/
int index_kmp(SString S, SString T, int pos, int next[]) {
int i = pos;
int j = 1;
while (i <= S[0] && j <= T[0]) {
if (j == 0 || S[i] == T[j]) {
++i;
++j;
} else {
j = next[j];
}
}
if (j > T[0]) return i - T[0];
else return 0;
}
/**
* 輸出打印
*/
void printString(SString S) {
printf("SString = [ ");
for (int i = 1; i <= S[0]; i++) {
printf("%c", S[i]);
}
printf(" ]\n");
}
int main() {
SString S;
char *chars = "goodgoogle";
initStr(S, chars);
printString(S);
SString T;
char *tchars = "google";
initStr(T, tchars);
printString(T);
// 獲取next數組
int *next = (int *) malloc((T[0] + 1) * sizeof(int));
get_next(T, next);
printf("next = ");
for (int p = 1; p <= T[0]; p++) {
printf("%d", next[p]);
}
printf("\n");
// 獲取nextval數組
int *nextval = (int *) malloc((T[0] + 1) * sizeof(int));
get_nextval(T, nextval);
printf("nextval = ");
for (int p = 1; p <= T[0]; p++) {
printf("%d", nextval[p]);
}
printf("\n");
// 測試kmp算法
int kmp_result = index_kmp(S, T, 1, nextval);
printf("kmp_result = %d\n", kmp_result);
return 0;
}
第 05 章 數組和廣義表
稀疏矩陣
// 稀疏矩陣的三元組順序存儲結構
typedef struct {
int i, j; // 該非零元素的下標
Element e;
} Triple;
typedef struct {
Triple data[MAX_SIZE + 1]; // 下標為0的空間不用
int mu, nu, tu; // 行數筑煮,列數,非零元素個數
} TSMatrix;
廣義表
// 廣義表的首尾鏈表表示法
typedef enum {
ATOM, LIST
} ELemtag;
typedef struct GLNode {
Elemtag tag; // 標志域粤蝎,用于區(qū)分元素結點和表結點
union { // 元素結點和表結點的聯合部分
Atomtype atom; // atom 是原子結點的值域
struct {
struct GLNode *hp, *tp; // hp和tp分別指向表頭和表尾
}ptr; // ptr是表結點的指針域
};
}*GList;
// 廣義表的孩子兄弟鏈表表示法
typedef enum {
ATOM, LIST
} ELemtag;
typedef struct GLNode {
ELemtag tag; // 標志域
union {
AtomType atom; // 原子結點的值域
struct GLNode *hp; // 表結點的指針
};
struct GLNode *tp;// 指向兄弟結點
} *GList;
第 06 章 樹和二叉樹
二叉樹
#include <stdio.h>
#include <stdlib.h>
#define OVERFLOW -2
#define OK 1
#define ERROR 0
typedef char TElemType;
typedef int Status;
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild; // 左右孩子
} BiTNode, *BiTree;
/**
* 統(tǒng)計二叉樹中結點個數。
*/
int getSum(BiTree root) {
int sum = 0;
if (root != NULL) {
sum++;
int left = getSum(root->lchild);
int right = getSum(root->rchild);
return sum + left + right;
}
return sum;
}
/**
* 按照先序遍歷的順序去創(chuàng)建二叉樹
*/
void createTree(BiTree *T) {
TElemType ch;
// ABD##EG###C#F##
scanf("%c", &ch);
if ('#' == ch) {
(*T) = NULL;
} else {
(*T) = (BiTree) malloc(sizeof(BiTNode));
if (!(*T)) exit(OVERFLOW);
(*T)->data = ch;
createTree(&(*T)->lchild);
createTree(&(*T)->rchild);
}
}
/**
* 先序遍歷:根袋马,左初澎,右
*/
Status PreOrderTraverse(BiTree T, Status(Visit)(TElemType)) {
if (T) {
Visit(T->data);
PreOrderTraverse(T->lchild, Visit);
PreOrderTraverse(T->rchild, Visit);
return OK;
} else return OK;
}
/**
* 中序遍歷:左,根虑凛,右
*/
Status InOrderTraverse(BiTree T, Status(Visit)(TElemType)) {
if (T) {
if (InOrderTraverse(T->lchild, Visit)) {
if (Visit(T->data)) {
if (InOrderTraverse(T->rchild, Visit))
return OK;
}
}
return ERROR;
} else return OK;
}
/**
* 后序遍歷:左碑宴,右,根
*/
Status PostOrderTraverse(BiTree T, Status(Visit)(TElemType)) {
if (T) {
if (PostOrderTraverse(T->lchild, Visit)) {
if (PostOrderTraverse(T->rchild, Visit)) {
if (Visit(T->data))
return OK;
}
}
return ERROR;
} else return OK;
}
Status PrintElement(TElemType e) {
printf("%c", e);
return OK;
}
int main() {
BiTree T;
createTree(&T);
PreOrderTraverse(T, PrintElement);
printf("\n");
InOrderTraverse(T, PrintElement);
printf("\n");
PostOrderTraverse(T,PrintElement);
return 0;
}
樹
// 樹的雙親表示法
typedef struct PTNode {
TElemType data;
int parent; // 雙親位置
}PTNode;
typedef struct {
PTNode nodes[MAX_TREE_SIZE];
int r,n; // n是結點數桑谍,r是根結點的下標
}PTree;
// 帶雙親的孩子鏈表表示法
typedef struct CTNode { // 鏈表結點
int child; // 孩子的下標
struct CTNode *next;
} *ChildPtr;
typedef struct { // 結點
int parent; // 雙親的下標
TElemType data;
ChildPtr firstChild; // 指向第一個孩子的指針
} CTBox;
typedef struct { // 樹結構
CTBox nodes[MAX_TREE_SIZE];
int n, r; // n是結點數延柠,r是根結點的下標
} CTree;
// 孩子兄弟表示法
typedef struct CSNode {
ElemType data;
struct CSNode *firstChild,*nextsibling; // 第一個孩子,兄弟結點
}CSNode,*CSTree;