C语言数据结构

目录

简介

绪论

线性表

合并两个线性表

 提纯一个线性表 

合并两个有序线性表 

顺序表操作:

单链表

双向链表

栈和队列

顺序栈

链栈

串、数组和广义表 

树和二叉树

查找

排序


简介

本篇是对常用数据结构的学习,其中的数据结构实现方法为与C十分接近的C++,顺序表的主函数本人以用C重写,其余的部分不在重写,重写方法见:

C转C++_JoYER_cc的博客-CSDN博客

绪论

数值计算:数学模型->算法

数据结构:

        逻辑结构:集合结构,线性结构,树结构,图结构或网结构

        存储结构:顺序存储结构,链式存储结构

数据类型:基本数据类型,抽象数据类型

        抽象数据类型:

ADT 抽象数据类型名{
    数据对象: <数据对象的定义>
    数据关系: <数据关系的定义>
    基本操作: <基本操作的定义>
}ADT 抽象数据类型名

基本操作名(参数表)
    初始条件:<初始条件描述>
    操作结果:<操作结果描述>

算法:

        特性:有穷性,确定性,可行性,输入,输出

        标准:正确性,可读性,健壮性,高效性 

        时间复杂度:问题规模n,语句频度

        空间复杂度

线性表

有次序的有限序列

基本操作:

InitList(&L)    //构造一个空的线性表
DestroyList(&L)    //销毁线性表
ClearList(&L)    //将L重置为空表
ListEmpty(L)    //若L为空表,则返回true,否则返回false
ListLength(L)    //返回L中元素的个数
GetElem(L,i,&e)    //用e返回L中第i个数据元素的值
LocateElem(L,e)    //返回L中第1个值与e相同的元素在L中的位置。若这样的元素不存在,返回值为0
PriorElem(L,cur_e,&pre_e)    //若cur_e是L的数据元素,且不是第一个,则用pre_e返回其前驱,否则操作失败,pre_e无定义
NextElem(L,cur_e,&next_e)    //若cur_e是L的数据元素,且不是最后一个,则用next_e返回其后继,否则操作失败,next_e无定义
ListInsert(&L,i,e)    //在L中第i个位置之前插入新的数据元素e,L的长度加1
ListDelete(&L,i)    //删除L的第i个数据,L的数据减1
TraverseList(L)    //对线性表进行遍历,在遍历的过程中对L的每个结点访问一次

合并两个线性表

void union(List &La,List Lb)
{
    La_len=ListLength(La);
    Lb_len=ListLength(Lb);    //求线性表的长度
    for(i=1;i<=Lb_len;i++)
    {
        GetElem(Lb,i,e);    //取Lb中第i个数据元素赋值给e
        if(!LocateElem(La,e,euqal())
            ListInsert(La,++La_len,e);    //La中不存在和e相同的数据元素,则插入之
    }
}

 提纯一个线性表 

void union(List &La,List Lb)
{
    InitList(LA);
    La_len=ListLength(La);
    Lb_len=ListLength(Lb);    //求线性表的长度
    for(i=1;i<=Lb_len;i++)
    {
        GetElem(Lb,i,e);    //取Lb中第i个数据元素赋值给e
        if(ListEmpty(LA)||!equal(en,e))
        {
            ListInsert(La,++La_len,e);    //La中不存在和e相同的数据元素,则插入之
            en=e;    
        }    //La中不存在和e相同的元素,则插入之
    }
}

合并两个有序线性表 

顺序有序表

void MergeList_Sq(SqList LA, SqList LB, Sqlist &LC)
{
    LC.length=LA.lenghth+LB.length;
    LC.elem=new ElemType[Lc.length];    //为新表分配一个数组空间
    pc=LC.elem;    //指针pc,pa,pb分别指向表第一个元素
    pa=LA.elem;
    pb=LB.elem;
    pa_last=LA.elem+LA.length-1;    //指针pa_lat指向表尾最后一个元素
    pb_last=LB.elem+LB.length-1;    //指针pb_lat指向表尾最后一个元素
    while((pa<pa_last)&&(pb<=pb_last))    //LA和LB均未到达表尾
    {
        if(*pa<=*pb)    //依次取两表中的较小结点插入到LC最后
            *pc++=*pa++;
        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; pb=LB->next;    //pa和pb分别指向两个表的第一个结点
    LC=LA;    //用LA的头结点作为LC的头结点
    pc=LC;    //pc的初值指向LC的头结点
    while(pa&&pb)
    {
        if(pa->data<=pb->data)
        {
            pc->next=pa;
            pc=pa;
            pa=pa->next;
        }
        else
        {
            pc->next=pb;
            pc=pb;
            pb=pb->next;
        }
    }
    pc->next=pa?pa:pb;
    delete LB;
}

顺序表操作:

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

#define _CRT_SECURE_NO_WARNINGS
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status; //Status 是函数返回值类型,其值是函数结果状态代码。
typedef int ElemType; //ElemType 为可定义的数据类型,此设为int类型

#define MAXSIZE 100			//顺序表可能达到的最大长度
struct Book {
	char id[MAXSIZE];//ISBN
	char name[MAXSIZE];//书名
	double price;//定价
};
typedef struct {
	Book* elem; //存储空间的基地址
	int length; //当前长度
} SqList;

Status InitList_Sq(SqList& L) { //算法2.1 顺序表的初始化
	//构造一个空的顺序表L
	L.elem = new Book[MAXSIZE]; //为顺序表分配一个大小为MAXSIZE的数组空间
	if (!L.elem)
		exit(OVERFLOW); //存储分配失败退出
	L.length = 0; //空表长度为0
	return OK;
}

Status GetElem(SqList L, int i, Book& e) {//算法2.2 顺序表的取值
	if (i < 1 || i > L.length)
		return ERROR; //判断i值是否合理,若不合理,返回ERROR
	e = L.elem[i - 1]; //elem[i-1]单元存储第i个数据元素
	return OK;
}

int LocateElem_Sq(SqList L, double e) { //算法2.3 顺序表的查找
	//顺序表的查找
	for (int i = 0; i < L.length; i++)
		if (L.elem[i].price == e)
			return i + 1;//查找成功,返回序号i+1
	return 0;//查找失败,返回0
}

Status ListInsert_Sq(SqList& L, int i, Book e) { //算法2.4 顺序表的插入
	//在顺序表L中第i个位置之前插入新的元素e
	//i值的合法范围是1<=i<=L.length+1
	if ((i < 1) || (i > L.length + 1))
		return ERROR; //i值不合法
	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; //将新元素e放入第i个位置
	++L.length; //表长增1
	return OK;
}

Status ListDelete_Sq(SqList& L, int i) { //算法2.5 顺序表的删除
	//在顺序表L中删除第i个元素,并用e返回其值
	//i值的合法范围是1<=i<=L.length
	if ((i < 1) || (i > L.length))
		return ERROR; //i值不合法
	for (int j = i; j <= L.length; j++)
		L.elem[j - 1] = L.elem[j]; //被删除元素之后的元素前移
	--L.length; //表长减1
	return OK;
}

主函数: 

int main() {
	SqList L;
	int i = 0, temp, a, c, choose, p=1;
	double price;
	Book e;
	char head_1[]="", head_2[]="", head_3[]="";
	char buf[256], * s;
	printf("1. 建立\n");
	printf("2. 输入\n");
	printf("3. 取值\n");
	printf("4. 查找\n");
	printf("5. 插入\n");
	printf("6. 删除\n");
	printf("7. 输出\n");
	printf("0. 退出\n\n");

	choose = -1;
	while (choose != 0) {
		printf("请选择:");
		scanf ("%d",&choose);
		switch (choose) {
		case 1://创建顺序表
			if (InitList_Sq(L))
				printf("成功建立顺序表\n\n");
			else
				printf("顺序表建立失败\n\n");
			break;
		case 2: {//顺序表信息输入
			i = 0;
			//L.elem = new Book[MAXSIZE];
			L.elem = (Book*)malloc(MAXSIZE * sizeof(Book));
			if (!L.elem)
				exit(OVERFLOW);
			L.length = 0;
			FILE *fp;
			fp = fopen("book.txt","r+");
			if (fp==NULL) {
				printf("错误!未找到文件!\n" );
				exit(ERROR);
			}
			while (!feof(fp))
			{
				fgets(buf, 256, fp);
				//if ('\n' == buf[0]) continue;     //空行继续
				s = buf;
				sscanf(s, "%s%s%lf", &L.elem[i].id, &L.elem[i].name, &L.elem[i].price);
				i++;
			}
			
			  printf("输入 book.txt 信息完毕\n\n");
			L.length = i;
			fclose(fp);
		}
			  break;
		case 3://顺序表的取值
			printf("请输入一个位置用来取值:\n");
			scanf("%i", &i);
			temp = GetElem(L, i, e);
			if (temp != 0) {
				printf("查找成功\n");
				printf("第 %d 本图书的信息是:\n",i);
				printf("%-15s %-30s %lf\n", e.id, e.name, e.price);
			}
			else
				printf("查找失败!位置超出范围\n\n");
			break;
		case 4: //顺序表的查找
			printf("请输入所要查找价格:");
			scanf("%lf", &price);
			temp = LocateElem_Sq(L, price);
			if (temp != 0) {
				printf("查找成功\n");
				printf("该价格对应的书名为:");
				printf("%-30s\n", L.elem[temp - 1].name);
			}
			else
				printf( "查找失败!没有这个价格对应的书籍\n\n");
			break;
		case 5: //顺序表的插入
			printf("请输入插入的位置和书本信息,包括:编号 书名 价格(用空格隔开):");
			scanf("%d",&a);
			scanf("%s %s %lf", &e.id,&e.name,&e.price); //输入a和b,a代表插入的位置,b代表插入的数值(书本信息)
			if (ListInsert_Sq(L, a, e))
				printf("插入成功.\n\n");
			else
				printf("插入失败.\n\n");
			break;
		case 6: //顺序表的删除
			printf("请输入所要删除的书籍的位置:");
			scanf("%d",&c);
			if (ListDelete_Sq(L, c))
				printf("删除成功.\n\n");
			else
				printf("删除失败.\n\n");
			break;
		case 7: //顺序表的输出
			printf("当前图书系统信息(顺序表)读出:\n");
			do
			{
				printf("%-15s %-30s %lf\n", L.elem[p].id, L.elem[p].name, L.elem[p].price);
				p++;
			} while (p < L.length);
			p = 0;
			break;
		}
	}
	return 0;
}

单链表

struct Book {
	string id;//ISBN
	string name;//书名
	double price;//定价
};
typedef struct LNode {
	Book data; //结点的数据域
	struct LNode *next; //结点的指针域
} LNode, *LinkList; //LinkList为指向结构体LNode的指针类型

Status InitList_L(LinkList &L) { //算法2.6 单链表的初始化
	//构造一个空的单链表L
	L = new LNode; //生成新结点作为头结点,用头指针L指向头结点
	L->next = NULL; //头结点的指针域置空
	return OK;
}

Status GetElem_L(LinkList L, int i, Book &e) { //算法2.7 单链表的取值
	//在带头结点的单链表L中查找第i个元素
	//用e返回L中第i个数据元素的值
	int j;
	LinkList p;
	p = L->next;
	j = 1; //初始化,p指向第一个结点,j为计数器
	while (j < i && p) { //顺链域向后扫描,直到p指向第i个元素或p为空
		p = p->next; //p指向下一个结点
		++j; //计数器j相应加1
	}
	if (!p || j > i)
		return ERROR; //i值不合法i>n或i<=0
	e = p->data; //取第i个结点的数据域
	return OK;
} //GetElem_L

LNode *LocateElem_L(LinkList L, int e) { //算法2.8 按值查找
	//在带头结点的单链表L中查找值为e的元素
	LinkList p;
	p = L->next;
	while (p && p->data.price != e)//顺链域向后扫描,直到p为空或p所指结点的数据域等于e
		p = p->next; //p指向下一个结点
	return p; //查找成功返回值为e的结点地址p,查找失败p为NULL 
} //LocateElem_L

Status ListInsert_L(LinkList &L, int i, Book &e) { //算法2.9 单链表的插入
	//在带头结点的单链表L中第i个位置插入值为e的新结点
	int j;
	LinkList p, s;
	p = L;
	j = 0;
	while (p && j < i - 1) {
		p = p->next;
		++j;
	}//查找第i?1个结点,p指向该结点
	if (!p || j > i - 1)
		return ERROR; //i>n+1或者i<1
	s = new LNode; //生成新结点*s 
	s->data = e; //将结点*s的数据域置为e
	s->next = p->next; //将结点*s的指针域指向结点ai
	p->next = s; //将结点*p的指针域指向结点*s
	++length;
	return OK;
} //ListInsert_L

Status ListDelete_L(LinkList &L, int i) { //算法2.9 单链表的删除
	//在带头结点的单链表L中,删除第i个位置	
	LinkList p, q;
	int j;
	p = L;
	j = 0;
	while ((p->next) && (j < i - 1)) //查找第i?1个结点,p指向该结点
	{
		p = p->next;
		++j;
	}
	if (!(p->next) || (j > i - 1))
		return ERROR; //当i>n或i<1时,删除位置不合理 
	q = p->next; //临时保存被删结点的地址以备释放 
	p->next = q->next; //改变删除结点前驱结点的指针域 
	delete q; //释放删除结点的空间 
	--length;
	return OK;
} //ListDelete_L

void CreateList_H(LinkList &L, int n) { //算法2.11 前插法创建单链表
	//逆位序输入n个元素的值,建立到头结点的单链表L
	LinkList p;
	L = new LNode;
	L->next = NULL; //先建立一个带头结点的空链表
	length = 0;
	fstream file;
	file.open("book.txt");
	if (!file) {
		cout << "未找到相关文件,无法打开!" << endl;
		exit(ERROR);
	}
	file >> head_1 >> head_2 >> head_3;
	while (!file.eof()) {
		p = new LNode; //生成新结点*p
		file >> p->data.id >> p->data.name >> p->data.price; //输入元素值赋给新结点*p的数据域
		p->next = L->next;
		L->next = p; //将新结点*p插入到头结点之后
		length++;//同时对链表长度进行统计
	}
	file.close();
} //CreateList_F

void CreateList_R(LinkList &L, int n) { //算法2.12 后插法创建单链表
	//正位序输入n个元素的值,建立带表头结点的单链表L 
	LinkList p, r;
	L = new LNode;
	L->next = NULL; //先建立一个带头结点的空链表
	r = L; //尾指针r指向头结点
	length = 0;
	fstream file; //打开文件进行读写操作
	file.open("book.txt");
	if (!file) {
		cout << "未找到相关文件,无法打开!" << endl;
		exit(ERROR);
	}
	file >> head_1 >> head_2 >> head_3;
	while (!file.eof()) { //将文件中的信息运用后插法插入到链表中
		p = new LNode;//生成新结点
		file >> p->data.id >> p->data.name >> p->data.price;//输入元素值赋给新结点*p的数据域
		p->next = NULL;
		r->next = p;//将新结点*p插入尾结点*r之后 		
		r = p;//r指向新的尾结点*p
		length++; //同时对链表长度进行统计
	}
	file.close();
} //CreateList_L

双向链表

struct Book {
	string id;//ISBN
	string name;//书名
	double price;//定价
};
typedef struct DuLNode {
	Book data; //数据域
	struct DuLNode *prior; //直接前驱
	struct DuLNode *next; //直接后继
} DuLNode, *DuLinkList;

Status InitDuList_L(DuLinkList &L) {
	//构造一个空的双向链表L
	L = new DuLNode; //生成新结点作为头结点,用头指针L指向头结点
	L->next = NULL; //头结点的指针域置空
	L->prior = NULL;
	return OK;
}

DuLNode *GetElemP_DuL(DuLinkList L, int i) {
	//在带头结点的双向链表L中查找第i个元素,返回结点的地址
	int j;
	DuLinkList p;
	p = L->next;
	j = 1; //初始化,p指向第一个结点,j为计数器
	while (j < i && p) { //顺链域向后扫描,直到p指向第i个元素或p为空
		p = p->next;
		++j;
	}
	if (!p || j > i)
		return NULL; //第i个元素不存在
	return p;
} //GetElemP_DuL

Status ListInsert_DuL(DuLinkList &L, int i, Book e) { //算法2.13 双向链表的插入
	//在带头结点的双向链表L中第i个位置之前插入元素e,i的合法值为1<=i<=表长+1
	DuLinkList s, p;
	if (!(p = GetElemP_DuL(L, i))) //在L中确定第i个元素的位置指针p
		return ERROR; //p为NULL时,第i个元素不存在
	if (i == 1) {//在双向链表的第一个元素上插入
		s = new DuLNode; //生成新结点s
		s->data = e; //将结点s数据置为e
		DuLinkList p = L->next;
		L->next = s;
		s->prior = L;
		s->next = p;//将结点*s插入L中
		p->prior = s;
		++length;
	} else if (i == length) {//在双向链表的最后一个元素上插入
		s = new DuLNode; //生成新结点s
		s->data = e; //将结点s数据置为e
		DuLinkList p = L;
		while (p->next)
			p = p->next;//将LinkList p指向双向链表结尾
		p->next = s;
		s->prior = p;//将结点*s插入到p的后面,插入到L中
		s->next = NULL;
		++length;
	} else {
		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④
		++length;
	}
	return OK;
} //ListInsert_DuL

Status ListDelete_DuL(DuLinkList &L, int i) { //算法2.14 双向链表的删除
	//删除带头结点的双向链表L中第i个位置之前插入元素e,i的合法值为1<=i<=表长
	DuLinkList p;
	if (!(p = GetElemP_DuL(L, i))) //在L中确定第i个元素的位置指针p
		return ERROR; //p为NULL时,第i个元素不存在
	if (i == 1)//删除双向链表的第一个元素
		L = L->next;
	else if (i == length) {//删除双向链表的最后一个元素
		p->prior->next = NULL;
		delete p;
		--length;
		return OK;
	} else {
		p->prior->next = p->next; //修改被删结点的前驱结点的后继指针,对应图2.21①
		p->next->prior = p->prior; //修改被删结点的后继结点的前驱指针,对应图2.21②
		delete p; //释放被删结点的空间 
		--length;
		return OK;
	}
}//ListDelete_DuL

void CreateDuList_L(DuLinkList &L) {
	//正位序输入n个元素的值,建立带表头结点的双向链表L,同时建立前驱指针
	DuLinkList r, p;
	L = new DuLNode;
	L->next = NULL; //先建立一个带头结点的空链表
	r = L;//尾指针r指向头结点
	length = 0;
	fstream file;
	file.open("book.txt");
	if (!file) {
		cout << "未找到相关文件,无法打开!" << endl;
		exit(ERROR);
	}
	file >> head_1 >> head_2 >> head_3;
	while (!file.eof()) {
		p = new DuLNode; //生成新结点
		file >> p->data.id >> p->data.name >> p->data.price; //输入元素值
		p->next = NULL;
		r->next = p; //插入到表尾
		r = p; //r指向新的尾结点
		p->prior = L->prior; //插入到表头
		L->prior = p;
		length++;
	}
	file.close();
} //CreateDuList_L

栈和队列

顺序栈

//顺序栈定义
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAXSIZE  100//顺序栈存储空间的初始分配量
typedef int Status;
typedef char SElemType;

typedef struct {
	SElemType *base;//栈底指针
	SElemType *top;//栈顶指针
	int stacksize;//栈可用的最大容量
} SqStack;

//算法3.1 顺序栈的初始化
Status InitStack(SqStack &S) {
	//构造一个空栈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;
}
//算法3.2 顺序栈的入栈
Status Push(SqStack &S, SElemType e) {
	// 插入元素e为新的栈顶元素
	if (S.top - S.base == S.stacksize)
		return ERROR; //栈满
	*(S.top++) = e; //元素e压入栈顶,栈顶指针加1
	return OK;
}
//算法3.3 顺序栈的出栈
Status Pop(SqStack &S, SElemType &e) {
	//删除S的栈顶元素,用e返回其值	
	if (S.base == S.top)
		return ERROR;//栈空
	e = *(--S.top); //栈顶指针减1,将栈顶元素赋给e
	return OK;
}
//算法3.4 取顺序栈的栈顶元素
char GetTop(SqStack S) {//返回S的栈顶元素,不修改栈顶指针
	if (S.top != S.base) //栈非空
		return *(S.top - 1); //返回栈顶元素的值,栈顶指针不变
}

链栈

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef char SElemType;

typedef struct StackNode {
	SElemType data;
	struct StackNode *next;
} StackNode, *LinkStack;

//算法3.5 链栈的初始化
Status InitStack(LinkStack &S) { // 构造一个空栈 S,栈顶指针置空
	S = NULL;
	return OK;
}

//算法3.6 链栈的入栈
Status Push(LinkStack &S, SElemType e) {//在栈顶插入元素e
	LinkStack p;
	p = new StackNode; //生成新结点
	p->data = e; //将新结点数据域置为e
	p->next = S; //将新结点插入栈顶
	S = p; //修改栈顶指针为p
	return OK;
}

//算法3.7 链栈的出栈
Status Pop(LinkStack &S, SElemType &e) {//删除S的栈顶元素,用e返回其值
	LinkStack p;
	if (S == NULL)
		return ERROR; //栈空
	e = S->data; //将栈顶元素赋给e
	p = S; //用p临时保存栈顶元素空间,以备释放
	S = S->next; //修改栈顶指针
	delete p; //释放原栈顶元素的空间
	return OK;
}
//算法3.8 取链栈的栈顶元素
SElemType GetTop(LinkStack S) {//返回S的栈顶元素,不修改栈顶指针
	if (S != NULL) //栈非空
		return S->data; //返回栈顶元素的值,栈顶指针不变
}

 链队

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef char QElemType;
typedef int Status;
typedef char SElemType;

//- - - - - 队列的链式存储结构- - - - - 
typedef struct QNode {
	QElemType data;
	struct QNode *next;
} QNode, *QueuePtr;
typedef struct {
	QueuePtr front; //队头指针
	QueuePtr rear; //队尾指针
} LinkQueue;

//算法3.16 链队的初始化
Status InitQueue(LinkQueue &Q) {//构造一个空队列Q
	Q.front = Q.rear = new QNode; //生成新结点作为头结点,队头和队尾指针指向此结点
	Q.front->next = NULL; //头结点的指针域置空
	return OK;
}

//算法3.17 链队的入队
Status EnQueue(LinkQueue &Q, QElemType e) {//插入元素e为Q的新的队尾元素
	QueuePtr p;
	p = new QNode; //为入队元素分配结点空间,用指针p指向
	p->data = e; //将新结点数据域置为e
	p->next = NULL;
	Q.rear->next = p; //将新结点插入到队尾
	Q.rear = p; //修改队尾指针
	return OK;
}

//算法3.18 链队的出队
Status DeQueue(LinkQueue &Q, QElemType &e) {//删除Q的队头元素,用e返回其值 
	QueuePtr p;
	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; //释放原队头元素的空间
	return OK;
}

//算法3.19 取链队的队头元素
SElemType GetHead(LinkQueue Q) {//返回Q的队头元素,不修改队头指针
	if (Q.front != Q.rear) //队列非空
		return Q.front->next->data; //返回队头元素的值,队头指针不变
}

循环链队

#define MAXQSIZE 100
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef char QElemType;
typedef char SElemType;
typedef int Status;

typedef struct {
	QElemType *base;//初始化时动态分配存储空间
	int front;//头指针
	int rear;//尾指针
} SqQueue;

//算法3.11 循环队列的初始化
Status InitQueue(SqQueue &Q) {//构造一个空队列Q
	Q.base = new QElemType[MAXQSIZE]; //为队列分配一个最大容量为MAXSIZE的数组空间
	if (!Q.base)
		exit(OVERFLOW); //存储分配失败
	Q.front = Q.rear = 0; //头指针和尾指针置为零,队列为空
	return OK;
}

//算法3.12 求循环队列的长度
int QueueLength(SqQueue Q) {//返回Q的元素个数,即队列的长度
	return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

//算法3.13 循环队列的入队
Status EnQueue(SqQueue &Q, QElemType e) {//插入元素e为Q的新的队尾元素
	if ((Q.rear + 1) % MAXQSIZE == Q.front) //尾指针在循环意义上加1后等于头指针,表明队满
		return ERROR;
	Q.base[Q.rear] = e; //新元素插入队尾
	Q.rear = (Q.rear + 1) % MAXQSIZE; //队尾指针加1
	return OK;
}

//算法3.14 循环队列的出队
Status DeQueue(SqQueue &Q, QElemType &e) {//删除Q的队头元素,用e返回其值
	if (Q.front == Q.rear)
		return ERROR; //队空
	e = Q.base[Q.front]; //保存队头元素
	Q.front = (Q.front + 1) % MAXQSIZE; //队头指针加1
	return OK;
}

//算法3.15 取循环队列的队头元素
SElemType GetHead(SqQueue Q) {//返回Q的队头元素,不修改队头指针
	if (Q.front != Q.rear) //队列非空
		return Q.base[Q.front]; //返回队头元素的值,队头指针不变
}

 C语言实现循环链队:

高效解析单片机通讯协议,最实用的一个方法

串、数组和广义表 

BF算法:可参考BF算法(串模式匹配算法)C语言详解 (biancheng.net)

/***字符串匹配算法***/
#include<cstring>
#include<iostream>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
#define MAXSTRLEN 255   		//用户可在255以内定义最长串长
typedef char SString[MAXSTRLEN + 1];		//0号单元存放串的长度

Status StrAssign(SString T, const char* chars) { //生成一个其值等于chars的串T
	int i;
	if (strlen(chars) > MAXSTRLEN)
		return ERROR;
	else {
		T[0] = strlen(chars);
		for (i = 1; i <= T[0]; i++)
			T[i] = *(chars + i - 1);
		return OK;
	}
}

//算法4.1 BF算法
int Index(SString S, SString T, int pos)
{
	//返回模式T在主串S中第pos个字符之后第s一次出现的位置。若不存在,则返回值为0
	//其中,T非空,1≤pos≤StrLength(S)
	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;
	return 0;
}//Index

int main()
{
	SString S;
	StrAssign(S, "bbaaabbaba");
	SString T;
	StrAssign(T, "abb");
	cout << "主串和子串在第" << Index(S, T, 1) << "个字符处首次匹配\n";
	return 0;
}

树和二叉树

查找

排序

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值