c语言基础

2023-05-16

基本语法

  1. 预定义常量及类型

    函数结果状态代码

    #define OK 1
    #define ERROR 0
    #define OVERFLOW -2
    //Status是函数返回值类型,其值是函数结果状态代码。
    typedef int Status;
    
  2. 数据结构的表示(存储结构)类型定义( typedef )描述;数据元素类型约定为ElemType,由用户在使用该数据类型时自行定义。

  3. 基本操作的算法都用如下格式的函数来描述:

    函数类型函数名(函数参数表){
    	//算法说明
    	语句序列
    }//函数名
    

    当函数返回值为函数结果状态代码时,函数定义为Status 类型。为了便于描述算法,除了值调用方式外,增加了C++语言引用调用的参数传递方式。在形参表中,以“&”打头的参数即为引用参数。传递引用给函数与传递指针的效果是-样的,形参变化实参也发生变化,但引用使用起来比指针更加方便、高效。

  4. 内存的动态分配与释放。

    使用new和delete动态分配和释放内存空间:
    分配空间 指针变量=new 数据类型;
    释放空间 delete指针变量;
    
  5. 赋值语句:

    简单赋值 变量名 = 表达式;
    串联赋值 变量名1 = 变量名2 = ... = 变量名n = 表达式;
    成组赋值 (变量名1, ..., 变量名n) = (表达式1, ..., 表达式n);
    结构赋值 结构名1 = 结构名2;
            结构名 = (1,2,....值n);
    条件赋值 变量名 = 条件表达式?表达式T:表达式F;
    交换赋值 变量名1 <-->变量名2;
    
  6. 选择语句:

    条件语句1 if (表达式)语句;
    条件语句2 if (表达式) 语句;
    				 else语句;
    开关语句 switch (表达式)
    				{
    					case1: 语句序列1 ;break;
    					case2: 语句序列2 ;break;
    					...
    					case值n: 语句序列n ;break;
    					default: 语句序列n+1;
    				}
    
  7. 循环语句:

    for语句    for (表达式1; 条件; 表达式2)语句;
    while语句  while (条件) 语句;
    do-while语句 do {
    									语句序列;
    								} while (条件);
    
  8. 结束语句:

    函数结束语句 return 表达式;
    					 return;
    					 case 或循环结束语句 break;
    					 异常结束语句 exit (异常代码);
    
  9. 输入输出语句使用C++流式输人输出的形式:

    输入语句 cin>>变量1>>..>>变量n;
    输出语句 cout<<表达式1<<...<<表达式n;
    
  10. 基本函数:

    求最大值 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;
}

B-树和B+树的区别

  1. B+树内节点不存储数据,所有 data 存储在叶节点导致查询时间复杂度固定为 log n。而B-树查询时间复杂度不固定,与 key 在树中的位置有关,最好为O(1)。
  2. B+树叶节点两两相连可大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和 data 在一起,则无法区间查找。
  3. B+树更适合外部存储。由于内节点无 data 域,每个节点能索引的范围更大更精确

字符串匹配

BF算法(暴力)

// 返回模式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;
}

KMP

来源:https://blog.csdn.net/m0_60598323/article/details/123696693

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

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;
}

散列表

散列表处理冲突的办法

  1. 线性探测法

    发生冲突时,从冲突地址的下一单元顺序寻找空单元

  2. 二次探测法

    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)

  3. 伪随机探测法

    (插入位置 + 随机数)% 数组长度 = 要插入位置

二分查找

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c语言基础 的相关文章

  • C语言基础----流程控制

    流程控制是C语言中比较基础的 它分为三种状态 xff1a 1是顺序结构 2是选择结构 3是循环结构 我要说明后两种结构 xff0c 选择机构和循环结构 首先先说 xff1a 选择结构 选择结构是指 xff1a 当一个条件成立则执 xff08
  • c语言基础

    基本语法 预定义常量及类型 函数结果状态代码 span class token macro property span class token directive hash span span class token directive k
  • go语言基础(二):切片

    切片的定义 切片的基本定义初始化如下 xff1a span class token comment 定义空切片 span a span class token operator 61 span span class token punctu
  • Rust 中的基本数据类型——Rust语言基础06

    文章目录 1 前言2 标量类型 xff08 Scalar xff09 2 1 整型 xff08 Integer xff09 2 2 Rust 的整数形式2 3 奇怪的问题 xff08 整数的溢出 xff09 2 4 浮点类型 xff08 F
  • c语言基础——一维数组的应用

    C语言基础 一维数组的应用 例如 在一个学校的班级中会有很多学生 此时就可以使用数组来保存这些学生的姓名 以便进行管理 eg xff1a 用数组保存学生姓名 本示例每一个元素都应该是可以保存字符串的类型 这里使用字符指针类型 span cl
  • C语言基础(初识C语言)

    学习一门编程语言是一条艰辛与快乐共存的一条路 xff0c 如今选择了这条路 xff0c 就应该一直走下去 xff0c 了解 C 语言的基础知识 xff0c 要先对 C语言有一个大概的认识 xff0c 下面我介绍一下C语言的基础 一 什么是C
  • Linux下C语言基础——arm交叉编译器安装

    ubuntu 16 04下输入该命令 apt install gcc arm linux gnueabi 重新编译main c文件 arm linux gnueabi gcc o mian main c 执行main xff0c 如果是原来
  • python 语言基础 - 你不得不知道的字符串常用函数之isalpha

    前言 小伙伴们大家好 xff0c 每天一个小知识 xff0c 一起学python每天进步一点点 不知道小伙伴们在开发的时候有没有遇到这样一种场景 xff0c 有时候一些业务需要 xff0c 想要判断一个字符串是不是由纯字符组成 xff0c
  • python 语言基础 - 你不得不知道的字符串常用函数之isdigit

    前言 小伙伴们大家好 xff0c 每天一个小知识 xff0c 一起学python每天进步一点点 上一篇文章中为大家分享了关于判断字符串是否全都是由字符组成的函数isalpha xff0c 今天要给大家分享的依然是判断字符串组成的函数isdi
  • Kotlin语言基础-我的第一个Kotlin

    一 Kotlin简介 1 1 使用kotlin开发服务端1 2使用Kotlin开发Android应用1 3Kotlin用于JavaScript 二 使用命令行编译 运行Kotlin 2 1环境安装和配置2 2 第一个Kotlin程序2 3编
  • C语言基础----流程控制

    流程控制是C语言中比较基础的 它分为三种状态 xff1a 1是顺序结构 2是选择结构 3是循环结构 我要说明后两种结构 xff0c 选择机构和循环结构 首先先说 xff1a 选择结构 选择结构是指 xff1a 当一个条件成立则执 xff08
  • r语言集合补集_R语言基础-reshape2、tidyr、dplyr包

    一 reshape2包 数据 xff1a 氮肥和磷肥的用量对植物生长的影响 将上图数据做成txt文件 1 melt 函数 xff0c 将宽数据转换为长数据 转换NP数据集 2 dcast 函数 xff0c 将长数据转换为宽数据 二 tidy
  • go语言基础-gozero

    go基础 go 文档 Go语言的并发是基于 goroutine 的 xff0c goroutine 类似于线程 xff0c 但并非线程 可以将 goroutine 理解为一种虚拟线程 Go 语言运行时会参与调度 goroutine xff0
  • 献给面试学生 关键字const是什么意思 ESP(译者:Embedded Systems Programming) --Dan Saks概括了const的所有用法

    关键字const是什么含意 答 我只要一听到被面试者说 const意味着常数 我就知道我正在和一个业余者打交道 去年Dan Saks已经在他的文章里完全概括了const的所有用法 因此ESP 译者 Embedded Systems Prog
  • Chapter Two : Python 语言基础、运算符与表达式、程序的控制结构合集

    目录 一 Python 语言基础 1 Python 语法规则 2 关键字与标识符 3 变量 4 基本数据类型 5 输入与输出 二 运算符与表达式 1 算术运算符 2 赋值运算符 3 比较 关系 运算符 4 逻辑运算符 5 位运算符 6 赋值
  • 银行卡编码规则及检验算法详解

    一 银行卡结构 XXXXXX XXXXXXXXXXXX X 发卡行标识代码 自定义位 校验码 根据ISO标准 银行卡长度一般在13 19位 国际上也有12位的 银联标准卡卡长度一般是在16 19位 双组织卡也有13 19位的 二 发卡行标识
  • 什么是TPS,什么是QPS,区别是什么?

    一 TPS Transactions Per Second 每秒传输的事物处理个数 即服务器每秒处理的事务数 TPS包括一条消息入和一条消息出 加上一次用户数据库访问 业务TPS CAPS 每个呼叫平均TPS TPS是软件测试结果的测量单位
  • IDEA-常用配置

    一 Appearance Behavior 1 1 设置主题 1 2 设置窗体及菜单的字体及大小 二 Editor General 2 1 设置自动导包的功能 Add unambiguous imports on the fly 自动导入不
  • STL中的排序算法一览[By ACM郭老师]

    这篇文章我很喜欢 是郭老师的新作 希望大家喜欢 详细的从算法的效率方面来说明了排序算法 STL中有多种排序算法 各有各的适用范围 下面听我一一道来 I 完全排序 sort 首先要隆重推出的当然是最最常用的sort了 sort有两种形式 第一
  • shell 脚本命令太长,如何换行?

    再加ENTER

随机推荐

  • 1.1 Qt Creater使用Python开发桌面软件的操作流程

    Qt Creater及Python的下载与安装过程不再赘述 xff0c 读者可自行在网上搜索相应的下载与安装方法 首先我们打开Qt Creater xff0c 单击 Create Project 按钮或单击菜单栏中的 文件 New Proj
  • zootracer使用说明——一款视频物体追踪软件,获取运动物体在屏幕坐标系的运动轨迹

    警告 xff01 软件会使用大量计算机资源 xff0c 请使用配置较高的电脑运行程序 xff01 不然容易把电脑跑坏 xff01 我的配置 xff1a CPU AMD Ryzen 7 5800H with Radeon Graphics G
  • Dockerfile概念简介

    Dockerfile概念简介 前言一 dockerfile概念二 Docker镜像的创建 1 基于现有镜像创建 2 基于本地模板创建 3 基于dockerfile创建 dockerfile结构 xff08 四部分 xff09 构建镜像命令
  • Android:file.mkdirs() false

    如果创建文件目录失败 就要考虑两个原因 1 是否给了读写权限 清单文件有读写权限 但是创建目录之前是否允许了 span class token operator lt span uses span class token operator
  • 【Flutter web】内网网站如何发布?解决外网下canvaskit.js和字体无法加载问题

    背景 由于部署的网站只能在内网下使用 xff0c 部署服务器又不能访问外网 xff0c 导致Flutter web部署遇到很多问题 xff0c 比如 xff1a 白屏 部署的网站为何首次加载缓慢 xff0c 会白屏 xff1f 通过浏览器开
  • 【Flutter web】实现批量生成可下载的二维码,二维码图片点击下载

    这里写自定义目录标题 先看效果 xff1a 方法 xff1a 先看效果 xff1a 方法 xff1a web布局就略过 xff0c 自行练习 xff0c 只讲重点 xff01 此项目需要用到三个依赖库 xff1a zxing2 0 1 0i
  • android 实现类似个人中心的界面设计

    上效果图 xff1a 先理清设计思路 xff1a 1 外层用linearlayout包裹 xff0c linearlayout采用shape 搭上描边 圆角和填充背景色 2 里层采用relativelayout填充进textview ima
  • 上传项目到github并供团队克隆

    github注册就不说了 1 创建仓库 创建后就能在首页中看到创建的仓库名了 2 本地克隆仓库 到github的项目仓库中找到项目的地址 xff0c 如第一图 磁盘中创建项目文件夹作为仓库 xff0c 右键选择torToiseGit gt
  • Fragment和Activity两种沉浸式状态栏的实现

    我们普通的Activity所有的标题栏颜色风格基本是一致的 xff0c 所以我们可以将这种单独的Activity的沉浸式状态栏放在BaseActivity中实现 但是如果遇到一级栏目的fragment中 xff0c 且有些fragment中
  • Android Studio Git实现回退至某一个版本

    流程 xff1a 一 android studio上部VCS gt Git gt Reset Head 二 选择Reset Type 注释 xff1a Reset Type git reset mixed xff1a 此为默认方式 xff0
  • Gitlab给指定人员设置指定权限

    1 选中指定的项目 xff0c 再选择Members 2 选择要指定的人员 xff0c 选择Project Access xff0c 为其添加指定的权限 xff0c 添加
  • 1.5 Qt Creater使用Python开发桌面软件的程序打包

    当我们开发完成软件后 xff0c 如果需要分发到其它电脑上运行 xff0c 我们需要进行程序打包 通过程序打包 xff0c 我们可以方便其他用户在其它设备上进行程序的使用 最简单且打包文件最小的方式为 xff1a 我们将开发用到的Pytho
  • Vue--Module parse failed: Unexpected character '' (1:0) (fonts/element-icons.ttf)

    当Vue引入iview Element ui后 xff0c npm run dev报错如下图 xff1a 本人项目采用webpack打包工具 xff0c 由于webpack打包工具是将浏览器不能直接运行的拓展语言 xff08 Scss xf
  • 安卓获取APP对应的Android id的原理分析

    android id 的生成原理是由系统生成的随机数 xff0c 并与应用 app 签名 xff0c 经过 HmacSHA256 算法生成的 xff1b 从 android 8 以后开始就是随机的了 xff0c 每个应用获取到的简要步骤 x
  • 将 Word 转换为 Markdown格式 【详细教程】

    文章目录 前言 下载安装Writage Word Markdown 下载安装Pandoc 再次Word Markdown总结 提示 xff1a 以下是本篇文章正文内容 xff0c 学习内容将会持续更新 前言 俗话说 好记性不如烂笔头 在我们
  • JAVA校验SQL语句与格式化语句

    想看实现直接滑倒左下边的工具类 xff0c 前边在说得是解决思路 前言 现在需要向数据库中某张表中的某个字段中 xff0c 插入的值为SQL语句 xff0c 但是要保证插入SQL语句的正确性 xff0c 而且还需要进行格式化 xff0c 就
  • 获取墨墨背单词里面的单词书中的单词

    首先 xff0c 其实是直接尝试抓包获取的 xff0c 不过在抓包的信息中没发现类似的内容 xff0c 然后就去百度了以下 xff0c 发现还是有聪明人 把下载的 apk 文件解压缩一下 xff0c 把里面的 assets 文件夹里面的 m
  • 2021年Redis面试题(持续更新)

    目录 1 redis基础redis 中的数据类型有哪些为什么说redis能够快速执行 2 Redis中的五种数据结构string 字符串 list 列表 set 集合 hash 哈希 zset 有序集合 3 Redis的持久化Redis 的
  • 吐槽一下csdn博客选中文字之后的悬浮窗

    悬浮窗出来的莫名其妙 xff0c 还会挡文字 xff0c 展示一下我框一段文字出现的一百种情况 xff0c csdn是否考虑出一个设置可以自定义把这个功能关闭和开启 看文章很自然的会选中文字一行一行的看 xff0c 我相信很多人都是这样的
  • c语言基础

    基本语法 预定义常量及类型 函数结果状态代码 span class token macro property span class token directive hash span span class token directive k