预定义常量及类型
函数结果状态代码
#define OK 1
#define ERROR 0
#define OVERFLOW -2
//Status是函数返回值类型,其值是函数结果状态代码。
typedef int Status;
数据结构的表示(存储结构)类型定义( typedef )描述;数据元素类型约定为ElemType,由用户在使用该数据类型时自行定义。
基本操作的算法都用如下格式的函数来描述:
函数类型函数名(函数参数表){
//算法说明
语句序列
}//函数名
当函数返回值为函数结果状态代码时,函数定义为Status 类型。为了便于描述算法,除了值调用方式外,增加了C++语言引用调用的参数传递方式。在形参表中,以“&”打头的参数即为引用参数。传递引用给函数与传递指针的效果是-样的,形参变化实参也发生变化,但引用使用起来比指针更加方便、高效。
内存的动态分配与释放。
使用new和delete动态分配和释放内存空间:
分配空间 指针变量=new 数据类型;
释放空间 delete指针变量;
赋值语句:
简单赋值 变量名 = 表达式;
串联赋值 变量名1 = 变量名2 = ... = 变量名n = 表达式;
成组赋值 (变量名1, ..., 变量名n) = (表达式1, ..., 表达式n);
结构赋值 结构名1 = 结构名2;
结构名 = (值1,值2,....值n);
条件赋值 变量名 = 条件表达式?表达式T:表达式F;
交换赋值 变量名1 <-->变量名2;
选择语句:
条件语句1 if (表达式)语句;
条件语句2 if (表达式) 语句;
else语句;
开关语句 switch (表达式)
{
case值1: 语句序列1 ;break;
case值2: 语句序列2 ;break;
...
case值n: 语句序列n ;break;
default: 语句序列n+1;
}
循环语句:
for语句 for (表达式1; 条件; 表达式2)语句;
while语句 while (条件) 语句;
do-while语句 do {
语句序列;
} while (条件);
结束语句:
函数结束语句 return 表达式;
return;
case 或循环结束语句 break;
异常结束语句 exit (异常代码);
输入输出语句使用C++流式输人输出的形式:
输入语句 cin>>变量1>>..>>变量n;
输出语句 cout<<表达式1<<...<<表达式n;
基本函数:
求最大值 Max (表达式1, ..., 表达式n)
求最小值 Min (表达式1, ..., 表达式n)
线性表的顺序存储结构:
#define MAXSIZE 100 // 顺序表可能达到的最大长度
typedef struct
{
ElemType *elem; // 存储空间的基地址
int length; // 当前长度
}SqList; // 顺序表的结构类型为SqList
初始化:
Status InitList(SqList &L)
{
L.elem = new ElemType[MAXSIZE]; // 为顺序表分配一个大小为MAXSIZE的数组空间
if (!L.elem) exit(OVERFLOW);
L.length = 0;
return OK;
{
取值:
Status GetElem(SqList L, int i, ElemType &e)
{
if (i<1 || i>L.length) return ERROR;
e = L.elem[i-1];
return OK;
}
查找
int LocateElem(SqList L, ElemType e)
{
for (int i = 0; i < L.length; i++)
if (L.elem[i] == e) return i+1;
return 0;
}
插入
Status ListInsert(SqList &L, int i, ElemType e)
{
if ((i<1) || (i>L.length+1)) return ERROR;
if (L.length == MAXSIZE) return ERROR;
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;
}
删除
Status ListDelete(SqList &L, int i)
{
if ((i < 1) || (i > L.length)) return ERROR;
for (int j = i; j <= L.length - 1; j++)
L.elem[j - 1] = L.elem[j];
--L.length;
return OK;
}
多项式的顺序存储结构:
#define MAXSIZE 100 // 多现实可能达到的最大长度
typedef struct // 多项式非零项的定义
{
float coef; // 系数
int expn; // 指数
}Polynomial;
typedef struct
{
Polynmial *elem; // 存储空间的基地址
int length; // 多项式中当前项的个数
}SqList // 多项式的顺序存储结构类型为SqList
图书表的顺序春初结构类型定义:
#define MAXSIZE 1000
typedef struct
{
char no[20]; // 图书ISBN
char name[50]; // 图书名字
float price; // 图书价格
}Book;
typedef struct
{
Book *elem; // 存储空间的基地址
int length; // 图书表中当前图书个数
}SqList; // 图书表的顺序存储结构类型位SqList
顺序表的初始化:
// 构造一个空的顺序表L
Status InitList(SqList &L)
{
L.elem = new ElemType[MAXSIZE]; // 为顺序表分配一个大小为MAXSIZE的数组空间
if(!L.elem) exit(OVERFLOW); // 存储分配失败退出
L.length = 0; // 空表长度为0
return OK;
}
顺序表的取值:
Status GetElem(SqList L, int i, ElemType &e)
{
if (i < 1 || i > L.length) return ERROR; // 判断i值是否合理,若不合理,返回ERROR
e = L.elem[i - 1]; // elem[i-1]单元存储第i个数据元素
return OK;
}
顺序表的查找:
int LocateElem(SqList L, ElemType e)
{
for (i=0; i<L.length; i++)
if (L.elem[i] == e) return i+1; // 查找成功,返回序号i+1
return 0; // 查找失败,返回0
}
顺序表的插入:
// 在顺序表L中的第i个位置之前插入新的元素e,i值的合法范围是1<=i<=L.length+1
Status ListInsert(SqList &L, int i, ElemType e)
{
if ((i<1) || (i>L.length+1)) return ERROR; // i值不合法
if (L.length == MAXSIZE) return ERROR; // 当前存储空间已满
for (j=L.length-1; j>=1-1; j--)
L.elem[j+1] = L.elem[j]; // 插入位置及之后的元素后移
L.elem[i-1] = e; // 将新元素e放入第i个位置
++L.length; // 表长加1
return OK;
}
顺序表的删除:
Status ListDelete(SqList &L, int i)
{
if ((i<1) || (i>L.length)) return ERROR; // i值不合法
for (j=i; j<=L.length-1; j++)
L.elem[j-1] = L.elem[j]; // 被删除元素之后的元素前移
--L.length; // 表长减1
return OK;
}
线性表的链式表示和实现
单链表的存储结构:
typedef struct LNode
{
ElemType data; // 结点的数据域
struct LNode *next; // 节点的指针域
}LNode, *LinkList; // LinkList为指向结构体LNode的指针类型
初始化:
// 构造一个空的单链表L
Status InitList(LinkList &L)
{
L = new LNode; // 生成新节点作为头节点,用头指针L指向头节点
L->next = NULL; // 头节点的指针域置空
return OK;
}
单链表的取值:
// 在带偶节点的单链表L中根据序号i获取元素的值,用e返回L中的第i个数据元素的值
Status GetElem(LinkList L, int i, ElemType &e)
{
p = L->next; // 初始化,p指向首元节点,计数器j初值赋为1
j = 1; // 顺链域向后扫描,直到p为空或p指向第i个元素
while (p&&j < i)
{
p = p->next; // p指向下一个节点
++j; // 计数器j相应加1
}
if (!p || j>i) return ERROR; // i值不合法i>n或i<=0
e = p->data; // 取第i个节点的数据域
return OK;
}
单链表的按值查找:
// 在带头节点的单链表L中查找值为e的元素
LNode *LocateElem(LinkList L, ElemType e)
{
p = L->next; // 初始化,p指向首元结点
while (p && p->data != e) // p指向先一个节点
p = p->next; // 查找成功返回值为e的节点地址p,查找失败p为NULL
return p;
}
单链表的插入
Status ListInsert(LinkList &L, int i, ElemType e)
{
p = L;
j = 0;
while (p && (j < i - 1)) // 查找第i-1个结点,p指向该节点
{
p = p->next;
j++;
}
s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
单链表删除:
// 在带头结点的单链表L中,删除第i个元素
Status ListDelete(LinkList &L, int i)
{
p = L;
j = 0;
while (p && (j < i - 1)) // 查找第i-1个结点,p指向该节点
{
p = p->next;
++j;
}
if (!(p->next) || (j>i-1)) return ERROR; // 当i>n或i<1时,删除位置不合理
q = q->next; // 临时保存被删节点的地址以备释放
p->next = q->next; // 改变删除结点前驱结点的指针域
delete q; // 释放删除结点的空间
return OK;
}
前插法创建单链表:
void CreateList_H(LinkList &L, int n)
{
L = new LNode;
L->next = NULL; // 先建立一个带头结点的空链表
for (i=0; i<n; i++)
{
p = new LNode; // 生成新结点*p
cin>>p->data; // 输入元素值赋给新结点*p的数据域
p->next = L->next; // 将新节点*p插入到头节点之后
L->next = p;
}
}
后插法创建单链表
void CreateList_R(LinkList &L, int n)
{
L = new LNode;
L->next = NULL; // 先建立一个带头结点的空链表
r = L; // 尾指针r指向头节点
for (i=0; i<n; ++i)
{
p = new LNode; // 生成新结点*p
cin>>p->data; // 输入元素值赋给新结点*p的数据域
p->next = NULL;
r->next = p; // 将新节点*p插入到尾节点*r之后
r = p; // r指向新的尾结点*p
}
}
循环链表的存储结构:
typedef struct DulNode
{
ElemType data; // 数据域
struct DulNode *prior; // 直接前驱
struct DulNode *next; // 直接后驱
}
双向链表的插入:
Status ListInsert_DuL(DuLinkList &L, int i, ElemType e)
{
if(!(p = GetElem_DuL(L,i))) // 在L中确定第i个元素的位置指针p
return ERROR; // p为NULL时,第i个元素不存在
s = new DuLNode; // 生成新节点*s
s->data = e; // 将结点*s数据域置为e
s->prior = p->prior; // 将结点*s插入L中,对应 2.20 ①
p->prior->next = s; // 对应图2.20 ②
s->next = p; // 对应图2.20 ③
p->prior = s; // 对应图2.20 ④
return OK;
}
双向链表的删除:
Status ListDelete_DuL(DuLinkList &L, int i)
{
if (!(p = GetElem_DuL(L,i))) // 在L中确定第i哥元素的位置指针p
return ERROR;
p->prior->next = p->next; // 修改被删除结点的前驱结点的后继指针,对应图2.21 ①
p->next->prior = p->prior; // 修改被删除结点的前驱结点的前驱指针,对应图2.21 ②
delete p; // 释放被删除结点的空间
return OK;
}
LA和LB合并成LC
void MergeList_Sq(SqList LA, SqList LB, SqList &LC)
{
LC.length = LA.length + LB.length; // 新表长度为待合并两表的长度之和
LC.elem = new ElemType[LC.length]; // 为合并后的新标分配一个数组空间
pc = LC.elem; // 指针pc指向新表的第一个元素
pa = LA.elem;
pb = LB.elem; // 指针pa和pb的初值分别指向两个表的第一个元素
pa_last = LA.elem + LA.length - 1; // 指针pa_last指向LA的最后一个元素
pb_last = LB.elem + LB.length - 1; // 指针pb_last指向LB的最后一个元素
while ((pa<=pa_last) && (pb<=pb_last)) // LA和LB均未到达表尾
{
if (*pa <= *pb) *pc++ = *pa++; // 依次“摘取”两表中值较小的结点插入到LC的最后
else *pc++ = *pb++;
}
while (pa<=pa_last) *pc++=*pa++; // LB已到达表尾,依次将LA的剩余元素插入LC的最后
while (pb<=pb_last) *pc++=*pb++; // LA已到达表尾,依次将LB的剩余元素插入LC的最后
}
void MergeList_L(LinkList &LA, LinkList &LB, LinkList &LC)
{
pa = LA->next; // pa和pb的初值分别指向两个表的第一个节点
pb = LB->next; // 用LA的头节点作为LC的头节点
pc = LC; // pc的初值指向LC的头节点
while (pa&&pb) // LA和LB均未到达表尾,依次“摘取”两表中值较小的结点插入到LC的最后
{
if (pa->data <= pb->data)
{
pc->next = pa; // 将pa所指结点链接到pc所指结点之后
pc = pa; // pc指向pa
pa = pa->next; // pa指向下一节点
}
else // “摘取”pb所指结点
{
pc->next = pb; // 将pb所指结点链接到pc所指结点之后
pc = pb; // pc指向pb
pb = pb->next; // pb指向下一节点
}
}
pc->next = pa ? pa : pb; // 将非空表的声誉段插入到pc所指节点之后
delete LB; // 释放LB的头节点
}
// 多项式加法:Pa = Pa + Pb,利用两个多项式的结点构成“和多项式”
void AddPolyn(Polynomial &Pa, Polynomia &Pb)
{
p1 = Pa->next; // p1和p2初值分别指向Pa和Pb的首元结点
p2 = Pb->next;
p3 = Pa; // p3指向和多项式的当前节点,初值为Pa
while (p1 && p2) // p1和p2均非空
{
if (p1->expn == p2->expn) // 指数相等
{
sum = p1->coef + p2->coef; // sum保存两项系数和
if (sum != 0) // 系数和不为0
{
p1->coef = sum; // 修改Pa当前节点的系数值为两项系数的和
p3->next = p1;
p3 = p1; // 将修改后的Pa当前结点链在p3之后,p3指向p1
p1 = p1->next; // p1指向后一项
r = p2; p2 = p2->next; delete r; // 删除Pb为当前结点,p2指向后一项
}
else
{
r = p1; p1 = p1->next; delete r; // 删除Pa当前节点,p1指向后一项
r = p2; p2 = p2->next; delete r; // 删除Pb当前节点,p2指向后一项
}
}
else if (p1->expn < p2->expn) // Pa当前结点的指数值小
{
p3->next = p1; // 将p1链在p3之后
p3 = p1; // p3指向p1
p1 = p1->next; // p1指向后一项
}
else // Pb当前结点的指数值小
{
p3->next = p2; // 将p2链在p3之后
p3 = p2; // p3指向p2
p2 = p2->next; // p2指向后一项
}
} // end while
pe->next = p1 ? p1 : p2; // 插入非空多项式的剩余段
delete Pb; // 释放Pb的头结点
}
#define MAXSIZE 100 // 顺序栈存储空间的初始分配量
typedef struct
{
SElemType *base; // 栈底指针
SElemType *top; // 栈顶指针
int stcksize; // 栈可用的最大容量
}SqStack;
StatusInitStack(SqStack &S)
{
S.base = new SElemType[MAXSIZE]; // 为顺序栈动态分配一个最大容量为 MAXSIzE 的数组空间
if (!S.base) exit(OVERFLOW); // 存储分配失败
S.top = S.base; // top初始为base,空栈
S.stacksize = MAXSIZE: // stacksize 置为栈的最大容量 MAXSIZE
return OK;
}
// 插人元素e为新的栈顶元素
StatusPush(SqStack &S, SElemType e)
{
if(S.top-S.base == S.stacksize) return ERROR; // 栈满
*S.top++ = e; // 元素e压人栈顶,栈顶指针加1
return OK:
}
// 删除S的栈顶元素,用e返回其值
StatusPop(SqStack &S, SElemTyp e)
{
if (S.top == S.base) return ERROR; // 栈空
e = *--S.top; // 栈顶指针减 1,将栈顶元素賦给e
return OK;
}
// 返回S的栈顶元素,不修改栈顶指针
ElemTypeGetTop(SqStackS)
{
if (S.top != S.base) // 栈非空
return *(S.top - 1); // 返回栈顶元素的值,栈顶指针不变
}
// 构造一个空栈S,栈顶指针置空
Status InitStack(LinkStack &S)
{
S = NULL;
return OK;
}
// 在栈顶插人元素 e
StatusPush (LinkStack &S, SElemType e)
{
p = new StackNode; // 生成新结点
p->data = e; // 将新结点数据域置为e
p->next = S; // 将新结点插人栈顶
S = p; // 修改栈顶指针为p
return OK;
}
// 删除S的栈顶元素,用e返回其值
Status Pop (LinkStack &S, SElemType &e)
{
if(S == NULL) return ERROR; // 栈空
e = S->data; // 将栈顶元素赋给 e
p = S; // 用p临时保存栈顶元素空间,以备释放
S = S->next; // 修改栈顶指针
delete p; // 释放原栈顶元素的空间
return OK;
}
// 返回S的栈顶元素,不修改栈顶指针
SElemType GetTop (LinkStack S)
{
if (S != NULL) // 栈非空
return S->data; // 返回栈顶元素的值,栈顶指针不变
}
#define MAXQSIZE 100 // 队列可能达到的最大长度
typedef struct
{
QElemType *base; // 存储空间的基地址
int front; // 头指针
int rear; // 尾指针
}
Status InitQueue (SqQueue &Q)
{
Q.base = new QElemType[MAXQSIZE];
if (!Q.base) exit(OVERFLOW); // 存储分配失败
Q.front = Q.rear = 0;
return OK;
}
int QueueLength (SqQueue Q)
{
return (Q.rear - Q.front + MAXSIZE) % MAXQSIZE;
}
Status EnQueue (SqQueue &Q, QElemType e)
{
if ((Q.rear+1) % MAXQSIZE == Q.front) return ERROR;
Q.base[Q.rear] = e;
Q.rear = (Q.rear+1)%MAXQSIZE;
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) % MAXQSIZE; // 队头指针加1
return OK;
}
SElemType GetHead (SqQueue Q)
{
if (Q.front != Q.rear) // 队列非空
return Q.base[Q.front]; // 返回队头元素的值,队头指针不变
}
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 = new QNode; // 生成新结点作为头结点, 队头和队尾指针指向此结点
Q.front->next = NULL; // 头节点的指针域置空
return OK;
}
Status EnQueue (LinkQueue &Q, QElemType e)
{
p = new QNode;
p->data = e; // 为入队元素分配结点空间,用指针p指向
p->next = NULL;
Q.rear->next = p; // 将新节点放到队尾
Q.rear = p; // 新节点作为新的队尾指针
return OK;
}
Status DeQueue (LinkQueue &Q, QElemType &e)
{
if (Q.front == Q.rear) return ERROR; // 若队列空,则返回ERROR
p = Q.front->next; // p指向队头元素
e = p->data; // e保存队头元素的值
Q.front->next = p->next; // 修改头指针
if (Q.rear == p) Q.rear = Q.front; // 最后一个元素被删,队尾指针指向头节点
delete p; // 释放p
return OK;
}
SelemType GetHead (LinkQueue Q)
{
if (Q.front != Q.rear) // 判空
return Q.front->next->data; // 返回队头元素的值,队头指针不变
}
将一个十进制整数N转换为八进制数
void conversion (int N)
{
InitStack(S); // 初始化空栈S
while(N) // 当N非零时,循环
{
Push(S, N%8);
N = N/8;
}
while (!StackEmpty(s)) // 当栈S非空时,循环
{
Pop(S, e); // 弹出栈顶元素e
cout<<e; // 输出e
}
}
// 表达式以 ‘#’ 结尾
Status Matching()
{
InitStack(S);
flag = 1;
cin>>ch;
while (!='#' && flag)
{
switch (ch)
{
case '[' || '(': // 如果是左括号,直接压入栈
Push(S,ch);
break;
case ')': // 如果是 ‘)’,则根据当前栈顶元素的值分情况考虑
if (!StackEmpty(S) && GetTop(S) == '(') // 如果 栈非空 且 栈顶元素是 ‘(’ , 则匹配正确
Pop(S,x);
else flag = 0;
break;
case ']': // 如果是 ‘]’,则根据当前栈顶元素的值分情况考虑
if (!StackEmpty(S) && GetTop(S) == '[') // 如果 栈非空 且 栈顶元素是 ‘[’ , 则匹配正确
Pop(S,x);
else flag = 0;
break;
}
cin>>ch;
}
if (StackEmpty(S) && flag) return true;
else return false;
}
typedef struct BiTNode {
TElemType data; // 结点数据域
struct BiTNode *lchild, *rchild; // 左右孩子指针
}BiTNode, *BiTree
// 递归实现
void InOrderTraverse (BiTree T)
{
if (T)
{
InOrderTraverse(T->lchild);
cout<<T->data;
InOrderTraverse(T->rchild);
}
}
// 迭代实现
void InOrderTraverse (BiTree T)
{
InitStack(S);
p = T;
q = new BiTNode;
while (p || !StackEmpty(S))
{
if (p) // p非空
{
Push(S,p); // 根指针进栈
p = p->lchild; // 根指针进栈,遍历左子树
}
else // p为空
{
Pop(S,q); // 退栈
cout<<q->data; // 访问根节点
p = q->rchild; // 遍历右子树
}
} // end while
}
int Depth (BiTree T)
{
if (T == NULL) return 0;
else
{
m = Depth(T->lchild);
n = Depth(T->rchild);
if (m>n) return m+1;
else return n+1;
}
}
int NodeCount (BiTree T)
{
if (T==NULL) return 0;
else return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}
// 返回模式T在主串S中的第pos个字符开始第一次出现的位置,若不存在,则返回值为0
int Index_BF(SString S, SString T, int pos)
{
i = pos; j = 1;
while (i <= S.length && j <= T.legth)
{
if (S[i].ch == T[j].ch) { ++i; ++j; }
else { i=i-j+2; j=1; }
}
if (j > T.length) return i-T.length;
else return 0;
}
来源:https://blog.csdn.net/m0_60598323/article/details/123696693
#include
#include
#include
#include
void my_next(int* next,int n,const char* p)
{
int j = 0, k = -1;
next[0] = -1;
while(j<n)
{
if (k == -1 || p[j] == p[k])
{
next[j + 1] = k + 1;
j++;
k++;
}
else
{
k = next[k];
}
}
}
int kmp(const char* str1, const char* str2)
{
int i = 0, j = 0;
int len = (int)strlen(str2);
// next数组
int* next = (int*)malloc(len * sizeof(int));
assert(next);
my_next(next,len-1,str2);
while (str2[j])
{
if(j==-1||str1[i] == str2[j])
// j为-1时该位置下的i不会匹配成功,进入下一次匹配
{
i++;
j++;
}
else
{
j = next[j];//j进行回退
}
if (str1[i] == '\0')
{
free(next);
next = NULL;
return -1;
}
}
free(next);
next = NULL;
return i;
}
int main()
{
char arr[] = "abaabcdabcab";
char brr[] = "ef";
printf("%d\n",kmp(arr, brr));
return 0;
}
散列表处理冲突的办法
线性探测法
发生冲突时,从冲突地址的下一单元顺序寻找空单元
二次探测法
d i = 1 2 , − 1 2 , 2 2 , − 2 2 , . . . , k 2 , − k 2 ( k < = m / 2 ) d_i = 1^2,-1^2,2^2,-2^2,...,k^2,-k^2(k<=m/2) di=12,−12,22,−22,...,k2,−k2(k<=m/2)
伪随机探测法
(插入位置 + 随机数)% 数组长度 = 要插入位置
void Search_Bin(SSTsble ST, KeyType key)
{
low = l; high = ST.length;
while (low <= high)
{
mid = (low + high) / 2;
if (key == ST.R[mid].key) return mid;
else if (key > ST.R[mid].key) low = mid + 1;
else high = mid - 1;
}
return 0;
}
参考:
https://blog.csdn.net/qq_53436105/article/details/127296815
https://blog.csdn.net/weixin_52811588/category_11973986.html