24王道考研408数据结构代码整合(学习用)

本文整理了24王道考研数据结构课件中所有代码,个人复习使用,发现有缺漏和错误欢迎指出,一起加油!

目录

第二章 线性表

2.1 线性表的基本操作

2.2 顺序表的定义

2.2.1 静态分配

2.2.3 动态分配

2.3 顺序表的基本操作

2.3.1 插入操作

2.3.2 删除操作

2.3.3 查找操作

2.4 单链表上基本操作的实现

2.4.1 头插法建立链表

2.4.2 尾插法建立链表

2.4.3 按序号查找结点

2.4.4 按值查找表结点

2.4.5 插入结点操作

2.4.6 删除结点操作 

2.4.7 求表长操作

2.5双链表

2.5.1双链表的初始化

2.5.2双链表的插入(后插)

2.5.3双链表的删除(后删)

2.5.4双链表的遍历

2.6循环链表

2.6.1循环单链表

2.6.2循环双链表

2.6.3双链表的插入

2.6.4双链表的删除

2.7 静态链表

2.7.1 代码定义静态链表

第三章 栈、队列和数组 

3.1 栈的顺序存储

3.1.1 栈的初始化

3.1.2 进栈操作

3.1.3 出栈操作

3.1.4 读栈顶元素操作

3.1.5 共享栈

3.2 栈的链式存储

3.2.1 链栈的定义

3.2.2 链栈的进栈、出栈操作

3.3 队列的顺序实现

3.3.1 队列的初始化

3.3.2 入队操作

3.3.3 循环队列

3.4队列的链式实现

3.4.1 队列的初始化

3.4.2 入队操作

3.4.3 出队操作

​编辑

3.5 栈在括号匹配中的应用

第四章 串

4.1串的存储结构

4.1.1 顺序存储

4.1.2 链式存储

4.1.3 基本操作(求子串、串的比较、定位操作)

4.2 匹配算法

4.2.1 朴素模式匹配算法

​编辑

4.2.2 KMP匹配算法

第五章 树与二叉树

5.1 二叉树的存储结构

5.1.1 顺序存储

5.1.2 链式存储

5.2 二叉树的遍历和线索二叉树

5.2.1 二叉树的遍历

5.2.2 线索二叉树

中序线索化

先序线索化

后序线索化

 5.2.3 线索二叉树找前驱/后继

中序线索二叉树找中序后继

中序线索二叉树找中序前驱 

5.3 树和森林

5.3.1 树的存储结构

双亲表示法(顺序存储)

孩子表示法(顺序+链式存储)

孩子兄弟表示法(链式存储)

5.3.2 树的遍历

先根遍历

后根遍历

5.4  并查集

基本操作

Union的优化

Find的优化

第六章 图

6.1 图的存储

6.1.1 邻接矩阵法

6.1.2 邻接表法

6.2 图的遍历

6.2.1 广度优先遍历BFS

6.2.2 深度优先遍历DFS

6.3 图的应用

6.3.1 最短路径问题

BFS算法

Dijkstra算法

Floyd算法

6.3.2拓补排序

第七章 查找

7.1 基本查找操作

7.1.1 顺序查找

7.1.2 折半查找

7.1.3 分块查找

7.2 树型查找

7.2.1二叉排序树(BST)

二叉树的查找

二叉树的插入

二叉树的构造

第八章 排序

8.1 插入排序

8.1.1直接插入排序

8.1.2 折半插入排序

8.1.3 希尔排序

8.2 交换排序

8.2.1 冒泡排序

8.2.2 快速排序

8.3 选择排序

8.3.1 简单选择排序

8.3.2 堆排序

8.4 归并排序和基数排序

8.4.1 归并排序


第二章 线性表

2.1 线性表的基本操作

InitList(&L): 初始化表。构建一个空线性表L,分配内存空间
DestroyList(&L): 销毁操作。销毁线性表,并释放线性表L所占用的内存空间

ListInsert(&L,i,e): 插入操作。在表L中的第i个位置插入指定元素e
ListDelete(&L,i,&e): 删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值

LocateElem(L,e): 按值查找操作。在表L中查找具有给定关键字值的元素
GetElem(L,i): 按位查找操作。获取表L中第i个位置的元素的值


其他常用操作:
Length(L): 求表长。返回线性表L的长度,即L中数据元素的个数
PrintList(L): 输出操作。按前后顺序输出线性表L的所有元素值
Empty(): 判空操作。若L为空表,则返回true,否则返回false

2.2 顺序表的定义

2.2.1 静态分配

#include <stdio.h>
#define MaxSize 10       //定义最大长度
typedef struct{
    ElemType data[MaxSize];    //用静态的“数组”存放数据元素
    int length;    //顺序表的当前长度
}SeqList;    //顺序表的类型定义(静态分配方式)

//基本操作——初始化一个顺序表
void InitList(SqList &L){
    for(int i=0; i<MaxSize; i++)   
        L.data[i]=0;    //将所有数据元素设置为默认初始值
    L.length=0;    //顺序表初试长度为0
}        

int main(){
    SeqList L;    //声明一个顺序表
    InitList(L);    //初始化顺序表
    ......
    return 0;
}

2.2.3 动态分配

#include <stdlib.h>
#define InitSize 10    //默认的最大长度
typedef struct{
    int *data;    //指示动态分配数组的指针
    int MaxSize;    //顺序表的最大容量
    int length;    //顺序表的当前长度
}SeqList;

void InitList(SeqList &L){
    //用 malloc 函数申请一片连续的存储空间
    L.data = (int *)malloc(InitSize*sizeof(int));
    L.length = 0;
    L.MaxSize = InitSize;
}

//增加动态数组的长度
void IncreaseSize(SeqList &L, int len){
    int *p = L.data;
    L.data = (int *)malloc((L.MaxSize+len)*sizeof(int));
    for(int i=0; i<L.length; i++){
        L.data[i] = p[i];    //将数据复制到新区域
    }
    L.MaxSize = L.MaxSize+len;    //顺序表最大长度增加 len
    free(p);    //释放原来的内存空间
}

int main(){
    SeqList L;    //声明一个顺序表
    InitList (L);    //初始化顺序表
    ...... 
    IncreaseSize(L,5);
    return 0;
}

2.3 顺序表的基本操作

2.3.1 插入操作

#define MaxSize 10    //定义最大长度
typeof struct{
    int data[MaxSize];    //用静态“数组”存放数据元素
    int length;    //顺序表的当前长度
}SeqList;    //顺序表的类型定义

bool ListInsert(SeqList &L,int i,int e){
    if(i<1 || i>L.length+1)    //判断i的范围是否有效
        return false;
    if(L.length >= MaxSize)    //当前存储空间已满,不能插入
        return false;
    for(int i=L.length; j>=i; j--)    //将第i个元素及之后的元素后移
        L.data[j] = L.data[j-1];
    L.data[i-1]=e;    //在第i个位置放入e
    L.length++;    //长度加1
    return true;
}

2.3.2 删除操作

bool ListDelete(SeqLizt &L,int i,int &e){
    if(i<1 || i>L.length)    //判断i的范围是否有效
        return false;   
    e = L.data[i-1];    //将被删除的元素赋给e
    for(int j=i; j<L.length; j++)    //将第i个位置后的元素前移
        L.data[j-1] = L.data[j];
    L.length--;    //线性表长度-1
    return true;
}

int main(){
    SeqList L;
    InitList(L);
    ......
    int e = -1;
    if (ListDelete(L,3,e))
        printf("已删除第3个元素,删除元素值为=%d\n",e);
    else
        printf("位序i不合法,删除失败\n");
    return 0;
}

2.3.3 查找操作

按位查找

GetElem(L,i);        获取表中第i个位置的元素的值

#define MaxSize 10    //定义最大长度
typedef struct{
    ElemType data[MaxSize];    //用静态的“数组”存放数据元素(静态分配)
    or
    ElemType *data;    //动态分配

    int length;    //顺序表的当前长度
}SeqList;    //顺序表的类型定义(静态分配方式)

ElemType GetElem(SeqList L, int i){
    return L.data[i-1];
}
        

按值查找

LocateElem(L,e);        在表L中查找具有给定关键字的值

#define InitSize 10
typedef struct{
    ElemType *data;
    int MaxSize;
    int length;
}SeqList;

//在顺序表L中查找第一个元素值等于e的元素,并返回其位序
int LocateElem(SeqList L, ElemType e){
    for(int i=0; i<L.length; i++)
        if(L.data[i] == e;
            return i+1;
    return 0;
}

2.4 单链表上基本操作的实现

2.4.1 头插法建立链表

LinkList List_HeadInsert(LinkList &L){	//逆向建立单链表 
	LNode *s;
	int x;
	L = (LinkList)malloc(sizeof(LNode));//创建头结点 
	L->nest = NULL;						//初始为空链表 
	scanf("%d",&x);						//输入结点的值 
	while(x!=9999){						//输入9999表示结束 
		s=(LNode*)malloc(sizeof(LNode));//创建新结点 
		s->data = x;
		s->next = L->next;
		L->next = s;					//将新结点插入表中,L为头指针 
		scanf("%d",&x);
	}
	return L;
} 

2.4.2 尾插法建立链表

LinkList List_TailInsert(LinkList &L){	//正向建立单链表 
	int x;								//设ElemType为整型 
	L = (LinkList)malloc(sizeof(LNode));//建立头结点 
	LNode *s, *r=L;						//r为表尾指针 
	scanf("%d",&x);						//输入结点的值 
	while(x!=9999){						//输入9999表示结束 
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r=s;							//r指向新的表尾结点 
		scanf("%d",&x);
	} 
	r->next->NULL;						//尾结点指针置空 
	return L;
} 

2.4.3 按序号查找结点

//按位查找,返回第i个元素(带头结点)
LNode * GetElem(LinkList L, int i){
	if(i<0)
		return NULL;
	LNode *p;	//指针p指向当前扫描到的结点 
	int j=0;	//当前p指向的是第几个结点 
	p = L;		//L指向头结点,头结点是第0个结点(不存数据) 
	while(p!=NULL && j<i){	//循环找到第i个结点 
		p = p->next;
		j++;
	}
	return p;
} 

2.4.4 按值查找表结点

//按值查找,找到数据域==e的结点
LNode *LocateElem(LinkList L, ElemType e){
	LNode *p = L->next;
	//从第1个结点开始查找数据域为e的结点
	while(p!=NULL && p->data!=e)
		p = p->next;
	return p;	//找到后返回该结点指针,否则返回NULL 
} 

2.4.5 插入结点操作

在第i个位置插入元素e(带头结点) 

//在第i个位置插入元素e(带头结点) 
bool ListInsert(LinkList &L,int i, ElemType e){
	if(i<1)
		return false;
	LNode *p;	//指针p指向当前扫描到的结点 
	int j=0;	//当前p指向的是第几个结点 
	p = L;		//L指向头结点,头结点是第0个结点(不存数据) 
	while(p!=NULL && j<i-1){	//循环找到第 i-1 个结点 
		p=p->next;
		j++;
	}
	if(p==NULL)		//i值不合法 
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;	//将结点s连到p之后 
	return true;	//插入成功 
} 

在第i个位置插入元素e(不带头结点)

//按位序插入(不带头结点)
bool ListInsert (&L, int i, ElemType e){
	if(i<1)
		return false;
	if(i==1){	//插入第1个结点的操作与其他结点不同 
		LNode *s = (LNode *)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L = s;	//头指针指向新结点 
		return true;
	}
	LNode *p;	//指针p指向当前扫描到的结点 
	int j=1;	//当前p指向的是第几个结点 
	p = L;		//p指向第1个结点(注意:不是头结点) 
	while(p!=NULL && j<i-1){	//循环找到第i-1个结点 
		p = p->next;
		j++;
	}
	if(p==NULL)		//i值不合法 
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;	//插入成功 
}

指定结点的前插、后插操作:

//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p,ElemType e){
	if(p==NULL)
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if(s==NULL)		//内存分配失败 
		return false;
	s->next = p->next;
	p->next = s;		//新结点s连到p之后 
	s->data = p->data;	//将p中元素复制到s中 
	p->data = e;		//p中元素覆盖为e 
	return true;
} 
//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p, ElemType e){
	if(p==NULL)
		return false;
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if (s==NULL)	//内存分配失败 
		return false;
	s->data = e;	//用结点s保存数据元素e 
	s->next = p->next;
	p->next = s;	//将结点s连到p之后 
	return true;
} 
//在第i个位置插入元素e(带头结点) 
bool ListInsert(LinkList &L, int i, ElemTypee e){
	if(i<1)
		return false;
	LNode *p;    //指针p指向当前扫描到的结点
	int j=0;     //当前p指向的是第几个结点
	p = L;       //L指向头结点,头结点是第0个结点(不存数据)
	while(p!=NULL && j<i-1){    //循环找到第 i-1 个结点
		p = p->next;
		j++;
	}
	return InsertPriorNode(p,e);
	or
	return InsertNextNode(p,e);
} 

2.4.6 删除结点操作 

//删除指定结点p
bool DeleteNode (LNode *p){
	if(p==NULL)
		return false;
	LNode *q = p->next;		//令q指向*p的后继结点 
	p->data = p->next->data;//和后继结点交换数据域 
	p->next = q->next;		//将*q结点从链中“断开” 
	free(q);				//释放后继结点的存储空间 
	return true;
} 

2.4.7 求表长操作

//求表的长度
int Length(LinkList L){
	int len = 0;	//统计表长 
	LNode *p = L;
	while(p->next != NULL){
		p = p->next;
		len++;
	}
	return len;
} 

2.5双链表

2.5.1双链表的初始化

typedef struct DNode{			//定义双链表结点类型
	ElemType data;				//数据域 
	struct DNode *prior,*next;	//前驱和后继指针 
}DNode, *DLinklist;				

//初始化双链表(带头结点) 
bool InitDLinklist(DLinklist &L){
	L = (DNode *)malloc(sizeof(DNode));
	if(L == NULL)
		return false;
	L->prior = NULL;
	L->next = NULL;
	return true; 
} 

void testDLinkList(){
	//初始化双链表
	DLinklist L;
	InitDLinkList(L);
	...... 
}

2.5.2双链表的插入(后插)

//在p结点之后插入s结点
bool InsertNextDNode (DNode *p, DNode *s){
	if(p==NULL || s==NULL)	//非法参数 
		return false;
	s->next = p->next;
	if(p-next != NULL)
		p->next->prior=s;	//如果p结点后有后继节点 
	s->prior = p;
	p->next = s;
	return true; 
} 

2.5.3双链表的删除(后删)

//删除p结点的后继结点
bool DeleteNextDNode(DNode *p){
	if(p == NULL)	return false;
	DNode *q = p->next;		//找到p的后继结点q
	if(q == NULL)	return false;	//p没有后继 
	p->next = q->next;
	if(q->next != NULL)
		q->next->prior = p;
	free(q);		//释放结点空间 
	return true; 
} 

void DestoryList(DLinklist &L){
	//循环释放各个数据节点
	while (L->next != NULL)
		DeleteNextDNode(L);
	free(L);	//释放头结点 
	L = NULL; 	//头指针指向NULL 
}

2.5.4双链表的遍历

//后向遍历
while(p!=NULL){
	//对结点p做相应处理,如打印
	p = p->next; 
} 

//前向遍历
while(p!=NULL){
	//对结点p做相应处理
	p = p->prior;
}

//前向遍历(跳过头结点) 
while(p->prior!=NULL){
	//对结点p做相应处理
	p = p->prior;
} 

2.6循环链表

2.6.1循环单链表

typedef	struct LNode{	//定义单链表结点类型 
	ElemType data;		//每个结点存放一个数据元素 
	struct LNode *next;	//指针指向下一个结点 
}LNode, *LinkList;

//初始化一个循环单链表
bool InitList(LinkList &L){
	L = (LNode *)malloc(sizeof(LNode));	//分配一个头结点 
	if(L==NULL)			//内存不足,分配失败 
		return false;
	L->next = L;		//头结点next指向头结点 
	return true;
}
 
//判断循环单链表是否为空
bool Empty(LinkList L){
	if(L->next == L)
		return true;
	else
		return false;
} 

//判断结点p是否为循环单链表的表尾结点
bool isTail(LinkList L, LNode *p){
	if(p->next == L)
		return true;
	else
		return false;
} 

2.6.2循环双链表


typedef struct DNode{
	ElemType data;
	struct DNode *prior,*next;
}DNode,*DLinklist;

//初始化空的循环双链表
bool InitDLinkList(DLinklist &L){
	L = (DNode *)malloc(sizeof(DNode));	//分配一个头结点 
	if(L==NULL)			//内存不足,分配失败 
		return false;
	L->prior = L;		//头结点的 prior 指向头结点 
	L->next = L;		//头结点的 next 指向头结点 
	return true;
} 
 
void testDLinkList(){
	//初始化循环双链表
	DLinklist L;
	InitDLinkList(L);
	......
}

//判断循环双链表是否为空
bool Empty(DLinklist L){
	if(L->next == L)
		return true;
	else
		return false;
} 

//判断结点p是否为循环双链表的表尾结点
bool isTail(DLinklist L, DNode *p){
	if(p->next == L)
		return true;
	else
		return false;
} 

2.6.3双链表的插入

//在p结点之后插入s结点
bool InsertNextDNode(DNode *p, DNode *s){
	s->next = p->next;
	p->next->prior = s;
	s->prior = p;
	p->next = s;
} 

2.6.4双链表的删除

//删除p的后继结点q
p->next = q->next;
q->next->prior = p;
free(q); 

2.7 静态链表

2.7.1 代码定义静态链表

#define MaxSize 10	//静态链表的最大长度 
struct Node{		//静态链表结构类型的定义 
	ElemType data;	//存储数据元素  
	int next;		//下一个元素的数组下标 
};
typeof struct Node SLinkList [MaxSize];

第三章 栈、队列和数组 

3.1 栈的顺序存储

3.1.1 栈的初始化

//初始化栈
void InitStack(SqStack &S){
	S.top = -1; 	//初始化栈顶指针 
} 
 
void testStack(){
	SqStack S;	//声明一个顺序栈(分配空间)
	InitStack(S);
	...... 
} 

//判断栈空
bool StackEmpty(SqStack S){
	if(S.top == -1)		//栈空
		return true;
	else
		return false;	//不空 
}

3.1.2 进栈操作

//新元素入栈
bool Push(SqStack &S,ElemType x){
	if(S.top == MaxSize-1)	//栈满,报错
		return false;
	S.top = S.top+1;		//指针先+1 
	S.data[S.top] = x; 		//新元素入栈 
	return true; 
} 

3.1.3 出栈操作

//出栈操作
bool Pop(SqStack &S,ElemType &x){
	if(S.top == -1)		//栈空,报错
		return false;
	x = S.data[S.top];	//栈顶元素先出栈 
	S.top = S.top-1;	//指针再-1 
	return true;
}

3.1.4 读栈顶元素操作

//读栈顶元素操作 
bool Pop(SqStack &S,ElemType &x){
	if(S.top == -1)		//栈空,报错
		return false;
	x = S.data[S.top];	//x记录栈顶元素	
	return true;
}

3.1.5 共享栈

//共享栈
#define MaxSize 10			//定义栈中元素的最大个数 
typedef struct{
	ElemType data[MaxSize];	//静态数组存放栈中元素 
	int top0;				//0号栈栈顶指针 
	int top1;				//1号栈栈顶指针
}ShStack; 
 
//初始化栈
void InitStack(ShStack &S){
	S.top0 = -1;
	S.top1 = MaxSize;
} 

3.2 栈的链式存储

3.2.1 链栈的定义

typedef struct Linknode{
	ElemType data;			//数据域 
	struct Linknode *next;	//指针域 
}*LiStack;					//栈类型定义 

3.2.2 链栈的进栈、出栈操作

        对应头插法建立单链表(进栈)、单链表的删除操作(出栈)

3.3 队列的顺序实现

3.3.1 队列的初始化

#define MaxSize 10	//定义队列中元素的最大个数
typedef struct{
	ElemType data[MaxSize];	//用静态数组存放队列元素
	int front,rear;			//队头指针和队尾指针 
}SqQueue;

//初始化队列
void InitQueue(SqQueue &Q){
	//初始时 队头、队尾指针指向0
	Q.rear = Q.front = 0; 
} 

void testQueue(){
	//声明一个队列(顺序存储)
	SqQueue Q;
	InitQueue(Q);
	...... 
}

//判断队列是否为空
bool QueueEmpty(SqQueue Q) {
	if(Q.rear == Q.front)	//队空条件
		return true;
	else 
		return false; 
}

3.3.2 入队操作

判断队满:rear == MaxSize?

当队尾等于最大长度时有可能是队满,也有可能存在假溢出(可以使用循环队列解决这个问题) 

//入队操作
bool EnQueue(SqQueue &Q,ElemType x){
	if(队列已满)
		return false;	//队满则报错
	Q.data[Q.rear] = x;
	Q.rear = Q.rear+1;
	return true; 
} 

3.3.3 循环队列

队列已满的条件:队尾指针的再下一个位置就是队头

即:(Q.rear+1)%MaxSize == Q.front

//判断队列是否为空
bool QueueEmpty(SqQueue Q){
	if(Q.rear == Q.front)	//队空条件
		return true;
	else
		return false; 
} 

//入队
bool EnQueue(SqQueue &Q,ElemType x){
	if((Q.rear+1)%MaxSize == Q.front)
		return false;			//队满则报错
	Q.data[Q.rear] = x;			//新元素插入队尾 
	Q.rear = (Q.rear+1)%MaxSize; //队尾指针+1取模
	return true; 
} 

//出队(删除一个队头元素,并用x返回) 
bool DeQueue(SqQueue &Q,ElemType &x){
	if(Q.rear == Q.front)
		return false;		//队空则报错 
	x = Q.data[Q.front];
	Q.front = (Q.front+1)%MaxSize;
	return true; 
} 

//获得队头元素的值,用x返回
bool GetHead(SqQueue Q,ElemType &x){
	if(Q.rear == Q.front)
		return false;	//队空则报错
	x = Q.data[Q.front]
	return true; 
} 

判断队列已满/已空

方案一:牺牲一个位置存放队尾指针

方案二:定义size变量,表示队列当前长度

方案三:定义tag变量,表示最近进行的是插入or删除

3.4队列的链式实现

typedef struct LinkNode {	//链式队列结点
	ElemType data;
	struct LinkNode *next; 
}LinkNode;

typedef struct{				//链式队列 
	LinkNode *fron,*rear;	//队列的队头和队尾指针 
}LinkQueue;

3.4.1 队列的初始化

//初始化队列(带头结点)
void InitQueue (LinkQueue &Q){
	//初始时 front、rear 都指向头结点
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
	Q.front->next = NULL;
} 
//判断队列是否为空(带头结点)
bool IsEmpty(LinkQueue Q){
	if(Q.front == Q.rear)
		return true;
	else
		return false;
} 
----------------------------------------
//初始化队列(不带头结点)
void InitQueue(LinkQueue &Q){
	//初始时 front、rear 都指向NULL
	Q.front= NULL;
	Q.rear = NULL; 
} 
//判断队列是否为空(不带头结点)
bool IsEmpty(LinkQueue Q){
	if(Q.front == NULL)
		return true;
	else
		return false;
} 

void testLinkQueue(){
	LinkQueue Q;	//声明一个队列
	InitQueue(Q);	//初始化队列
	...... 
}

3.4.2 入队操作

//新元素入队(带头结点)
void EnQueue(LinkQueue &Q,ElemType x){
	LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	Q.rear->next = s;	//新结点插入到rear之后 
	Q.rear = s;			//修改表尾指针 
} 
------------------------------------------------------- 
//新元素入队(不带头结点)
void EnQueue(LinkQueue &Q,ElemType x){
	LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	if(Q.front == NULL){	//在空队列中插入第一个元素 
		Q.front= s;			//修改队头队尾指针 
		Q.reat= s;
	}else{
		Q.rear->next = s;	//新结点插入到 rear 之后 
		Q.rear = s; 		//修改rear指针 
	}
} 

3.4.3 出队操作

//队头元素出队(带头结点)
bool DeQueue(LinkQueue  &Q,ElemType &x){
	if(Q.front == Q.rear)
		return false;	//空队
	LinkNode *p = Q.front->next;//p指针指向要删除的结点(队头元素出队)
	x = p->data;	//用变量x返回队头元素
	Q.front->next = p->next;	//修改头结点的next指针
	if(Q.rear == p)				//此次是最后一个结点出队 
		Q.rear = Q.front;		//修改 rear 指针 
	free(p);					//释放结点空间 
	return true;
} 


//队头元素出队(不带头结点)
bool DeQueue(LinkQueue &Q,ElemType &x){
	if(Q.front == NULL)
		return false;	//空队
	LinkNode *p = Q.front; //p指向此次出队的结点
	x = p->data;		   //用变量x返回队头元素
	Q.front = p->next;	   //修改front指针
	if(Q.rear == p){	   //此次是最后一个结点出队 
		Q.front = NULL;	   //front 指向 NULL 
		Q.rear = NULL;	   //rear 指向 NULL 
	} 
	free(p);
	return true; 
} 

3.5 栈在括号匹配中的应用

 算法实现

bool bracketCheck(char str[],int length){
	SqStack S;
	InitStack(S);	//初始化一个栈
	for(int i=0; i<length; i++){
		if(str[i] == '(' || str[i] == '[' || str[i] == '{')
			Push(S,str[i]);		//扫描到左括号,压入栈 
	}else{
		if(StackEmpty(S))		//扫描到右括号,且当前栈空 
			return false; 		//扫描失败
		
		char topElem;
		Pop(S,topElem);			//栈顶元素出栈 
		if(str[i] == ')' && topElem != '(')
			return false;
		if(str[i] == ']' && topElem != '[')
			return false;
		if(str[i] == '}' && topElem != '{')
			return false;
	} 
	return StackEmpty(S);		//检索完全部括号后,栈空说明匹配成功 
} 

 匹配失败情况:①左括号单身 ②右括号单身 ③左右括号不匹配

第四章 串

4.1串的存储结构

4.1.1 顺序存储

#define MAXLEN 255		//预定义最大串长为255
 	
//静态数组实现(定长顺序存储)
typedef struct{
	char ch[MAXLEN];	//每个分量存储一个字符 
	int length;			//串的实际长度 
}SString; 

//动态数组实现(堆分配存储) 
typedef struct{
	char *ch;		//按串长分配存储区,ch指向串的基地址	
	int length;		//串的长度 
}HString; 

HString S;
S.ch = (char *) malloc(MAXLEN * sizeof(char));
S.length = 0; 

4.1.2 链式存储

typedef struct StringNode{
	char ch;	//每个结点存1个字符
	struct StringNode * next; 
}StringNode, * String;

typedef struct StringNode{
	char ch[4];	//每个结点存4个字符
	struct StringNode * next; 
}StringNode, * String;

4.1.3 基本操作(求子串、串的比较、定位操作)

//求子串(用Sub返回串S的第pos个字符起长度为len的子串) 
bool SubString(SString &Sub, SString s, int pos,int len){
	//子串范围越界
	if(pos+len-1 > S.length)
		return false;
	for(int i=pos; i<pos+len; i++)
		Sub.ch[i-pos+1] = S.ch[i];
	Sub.length = len;
	return true;
} 

//串的比较(若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0) 
int StrCompare(SString S, SString T){
	for(int i=1; i<=S.length && i<=T.length; i++){
		if(S.ch[i] != T.ch[i])
			return S.ch[i]-T.ch[i];
	}
	//扫描过的所有字符都相同,则长度长的串要大
	return S.length - T.length; 
} 

//求串在主串中的位置(若S中存在与串T相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0)
int Index(SString S, SString T){
	int i=1, n=StrLength(S), m=StrLength(L);
	SString sub;	//用于暂存子串
	while(i<=n-m+1){
		SubString(Sub,s,i,m);
		if(StrCompare(sub,T)!=0)  ++i;
		else return i;	//返回子串在主串中的位置 
	} 
	return 0;	//S中不存在与T相等的子串 
} 

4.2 匹配算法

4.2.1 朴素模式匹配算法

最坏时间复杂度:O(nm)

//朴素模式匹配算法
int Index(SSring S,SString T){
	int i=1,j=1;
	while(i<=s.length && j<=T.length){
		if(S.ch[i] == S.ch[j]){
			++i; ++j;	//继续比较后续字符 
		}
		else{
			i=i-j+2;	//i=(i-(j-1))+1 
			j=1;	//指针后退重新开始匹配 
		} 
	}
	if(j>T.length)
		return i-T.length;
	else
		return 0; 
} 

i=i-j+2 的解释:

        当i=j=6,模式串与主串不匹配时,i需要回到起始元素的下一个位置2,j回到1才能进行下一次匹配,即 i-(j-1),i回到1位置后再加一:i = i -( j-1)+1 = i-j+2

4.2.2 KMP匹配算法

//KMP匹配算法
int Index_KMP(SSring S,SString T,int next[]){
	int i=1,j=1;
	while(i<=s.length && j<=T.length){
		if(j==0 || S.ch[i] == S.ch[j]){
			++i; ++j;	//继续比较后续字符 
		}
		else
			j = next[i];	//模式串向后移动 
	}
	if(j>T.length)
		return i-T.length;	//匹配成功 
	else
		return 0; 
} 

第五章 树与二叉树

5.1 二叉树的存储结构

5.1.1 顺序存储

#define MaxSize 100
struct TreeNode{
	ElemType value;		//结点中的数据结构
	bool isEmpty;		//结点是否为空 
}; 

TreeNode t[MaxSize];

for(int i=0; i<MaxSize; i++){
	t[i].isEmpty = true;
} 

5.1.2 链式存储

//二叉树的结点(链式存储)
struct ElemType{
	int value;
};

typedef struct BiTNode{
	ElemType data;		//数据域
	struct BiTNode *lchild,*rchild;	//左、右孩子指针 
    (sruct BiTNode *parent;)	//父结点指针 
}BiTNode,*BiTNode; 

//定义一棵空树
BiTree root = NULL;

//插入根节点
root = (BiTree) malloc(sizeof(BiTNode));
root->data = {1};
root->lchild = NULL;
root->rchild = NULL;

//插入新结点
BiTree *p = (BiTNode *) malloc(sizeof(BiTNode));
p->data = {2};
p->lchild = NULL;
p->rchild = NULL;
root->lchild = p;	//作为根节点的左孩子 

5.2 二叉树的遍历和线索二叉树

5.2.1 二叉树的遍历

//先序遍历
void PreOrder(BiTree T){
	if(T != NULL){
		visit(T);			//访问根节点
		PreOrder(T->lchild);//递归遍历左子树 
		PreOrder(T->rchild);//递归遍历右子树 
	}
} 
//中序遍历
void InOrder(BiTree T) {
	if(T != NULL){
		InOrder(T->lchild);//递归遍历左子树 
		visit(T);			//访问根节点
		InOrder(T->rchild);//递归遍历右子树 
	}
}
//后序遍历 
void PostOrder(BiTree T){
	if(T != NULL){
		PostOrder(T->lchild);//递归遍历左子树 
		PostOrder(T->rchild);//递归遍历右子树
		visit(T);			//访问根节点
	}
} 

例:求树的深度(应用)

int treeDepth(BiTree T){
	if(T == NULL){
		return 0;
	}else{
		int l = treeDepth(T->lchild);
		int r = treeDepth(T->rchild);
		//树的深度 = Max(左子树深度,右子树深度)+ 1
		return l>r? l+1:r+1; 
	}
}

层序遍历 

//层序遍历
void LevelOrder(BiTree T){
	LinkQueue Q;	
	InitQueue(Q); 			//初始化辅助队列 
	BiTree p;
	EnQueue(Q,T);			//将根节点入队
	while(!IsEmpty(Q)){		//队列不空则循环 
		DeQueue(Q,p); 		//对头结点出队
		visit(p);			//访问出队结点
		if(p->lchild!=NULL)
			EnQueue(Q,p->lchild);	//左孩子入队 
		if(p->rchild!=NULL)
			EnQueue(Q,p->rchild);	//右孩子入队 
	} 
} 

typedef struct BiTNode{
	ElemType data;	
	struct BiTNode *lchild,*rchild;	
}BiTNode,*BiTNode; 

//链式队列结点
typedef struct LinkNode{
	BiTNode * data;
	struct LinkNode *next;
}LinkNode;

typedef struct{
	LinkNode *front,*rear;	//队头队尾 
}LinkQueue; 

5.2.2 线索二叉树

//线索二叉树结点
typedef struct ThreadNode{
	ElemType data;
	struct ThreaDNode *lchild,*rchild;
	int ltag,rtag;	//左、右线索标志 
	//ltag == 1,表示lchild指向前驱;ltag == 0,表示lchild指向左孩子
	//rtag == 1,表示rchild指向前驱;rtag == 0,表示rchild指向右孩子
}ThreadNode,*ThreadTree;

土办法找到中序前驱

//土办法找中序前驱
void findPre(BiTree){
	if(T!=NULL){
		findPre(T->lchild);
		visit(T);
		findPre(T->rchild);
	}
} 
//访问结点p
void visit(BiTNode *q){
	if(p==q)			//当前访问结点刚好是结点p 
		final = pre;	//找到p的前驱
	else
		pre = q; 
} 
//辅助全局变量,便于查找p的前驱
BiTNode *p;				//p指向目标结点 
BiTNode * pre = NULL;	//指向当前访问结点的前驱 
BiTNode * final = NULL; //用于记录最终结果
中序线索化
//中序线索化

//全局变量pre,指向当前访问结点的前驱
ThreadNode *pre = NULL;
//中序线索化二叉树T
void CreateInThread(ThreadTree T){
	pre = NULL;				//初始化pre为NULL 
	if(T!=NULL){			//非空二叉树才能线索化 
		InThread(T);		//中序线索化二叉树 
		if(pre->rchild == NULL)
			pre->rtag = 1;	//处理遍历的最后一个结点 
	}
} 
//线索二叉树结点
typedef struct ThreadNode{
	ElemType data;
	struct ThreadNode *lchild,*rchild;
	int ltag,rtag;
}ThreadNode,*ThreadTree;
//中序遍历二叉树,一边遍历一遍线索化
void InThread(ThreadTree T){
	if(T!=NULL){
		InThread(T->lchild);
		visit(T);
		InThread(T->rchild);
	}
} 
void visit(ThreadNode *q){
	if(q->lchild == NULL){	//左子树为空,建立前驱线索 
		q->lchild = pre;
		q->ltag =  1;
	}
	if(pre!=NULL && q->rchild == NULL){
		pre->rchild = q;	//建立前驱结点的后驱线索 
		pre->rtag = 1;
	} 
	pre = q;
}
先序线索化
//先序线索化

//全局变量pre,指向当前访问结点的前驱
ThreadNode *pre = NULL;
//先序线索化二叉树T
void CreatePreThread(ThreadTree T){
	pre = NULL;					//pre初始化为NULL
	if(T!=NULL){				//非空二叉树才能线索化 
		PreThread(T);			//先序线索化二叉树 
		if(pre->rchild == NULL)
			pre->rchild = 1;	//处理遍历的最后一个结点 
	} 
}
//先遍历二叉树,一边遍历一遍线索化
void PreThread(ThreadTree T){
	if(T!=NULL){
		visit(T);			//先处理根节点 
		if(T->ltag == 0)	//lchild不是前驱线索
			PreThread(T->lchild);
		PreThread(T->rchild); 
	}
} 
void visit(ThreadNode *q){
	if(q->lchild == NULL){	//左子树为空,建立前驱线索 
		q->lchild = pre;
		q->ltag = 1;
	}
	if(pre!=0 && q->rchild == NULL){
		pre->rchild = q;	//建立前驱结点的后继线索 
		pre->rtag = 1;
	}
	pre = q;
}
后序线索化
//后序线索化

//全局变量pre,指向当前访问结点的前驱
ThreadNote *pre = NULL;
//后序线索化二叉树T
void CreatPostThread(ThreadTree T){
	pre = NULL;				//pre初始为NULL 
	if(T!=NULL){			//非空二叉树才能线索化 
		PostThread(T);		//后序线索化二叉树 
		if(pre->rchild == NULL)
			pre->rtag = 1;	//处理遍历的最后一个结点 
	} 
} 
//后序遍历二叉树,一边遍历一边线索化 
void postThread(ThreadTree T){
	if(T!==NULL){
		PostThread(T->lchild);	//后序遍历左子树
		PostThread(T->rchild);	//后序遍历右子树
		visit(T);				//访问根节点 
	} 
} 
void visit(ThreadNode *q){
	if(q->lchild == NULL){	//左子树为空,建立前驱线索 
		q->lchild = pre;
		q->ltag = 1;
	}
	if(pre!=NULL && q->rchild == NULL){
		pre->rchild = q;	//建立前驱结点的后继线索
		pre->rtag = 1; 
	}
	pre = q;
} 

 5.2.3 线索二叉树找前驱/后继

中序线索二叉树找中序后继
//中序线索二叉树找中序后继

//找到以P为根的子树中,第一个被中序遍历的结点
ThreadNode *Firstnode(ThreadNode *p){
	//循环找到最左下结点(不一定是叶结点)
	while(p->ltag == 0)
		p=p->lchild;
	return p; 
} 
//在中序线索二叉树中找到结点p的后继结点
ThreadNode *Nextnode(ThreadNode *p){
	//右子树中最左下结点
	if(p->rtag == 0)
		return Firstnode(p->rchild);
	else 
		return p->rchild;	//rtag==1直接返回后继线索 
} 
//对中序线索二叉树进行中序遍历(利用线索实现的非递归算法)
void Inorder(ThreadNode *T){
	for(ThreadNode *p=Firstnode(T); p!=NULL; p=Nextnode(p))
		visit(p);
} 
中序线索二叉树找中序前驱 
//中序线索二叉树找中序前驱

//找到以P为根的子树中,最后一个被中序遍历的结点
ThreadNode *Lastnode(ThreadNode *p){
	//循环找到最右下的结点(不一定是叶结点)
	while(p->rtag == 0)
		p=p->rchild;
	return p; 
} 
//在中序线索二叉树中找到结点p的前驱结点
ThreadNode *Prenode(ThreadNode *p){
	//左子树中最右下结点
	if(p->ltag == 0)
		return Lastnode(p->lchild);
	else
		return p->lchild;	//ltag==1直接返回前驱线索 
} 
//对中序线索二叉树进行逆向中序遍历
void RevInorder(ThreadNode *T){
	for(ThreadNode *p=Lastnode(t); p!=NULL; p=Prenode(p));
	visit(p);
} 

5.3 树和森林

5.3.1 树的存储结构

双亲表示法(顺序存储)
//双亲表示法(顺序存储)
#define MAX_TREE_SIZE 100		//树中最多结点数
typedef struct{					//树中的结点定义
	ElemType data;				//数据元素 
	int parent;					//双亲位置域 
}PTNode;
typedef struct{					//树的类型定义 
	PTNode nodes[MAX_TREE_SIZE];//双亲表示 
	int n;						//结点数 
}PTree; 
孩子表示法(顺序+链式存储)
//孩子表示法
struct CTNode{
	int child;	//孩子结点在数组中的位置 
	struct CTNode *next;	//下一个孩子 
}; 
typedef struct{
	ElemType data;
	struct CTNode *firstChild;	//第一个孩子 
}CTBox;
typedef struct{
	CTBox nodes[mAX_TREE_SIZE];
	int n, r;	//结点数和根的位置 
}CTree; 
孩子兄弟表示法(链式存储)
//孩子兄弟表示法
typedef struct CSNode{
	ElemType data;		//数据域 
	struct CSNode *firstchild,*nextsibling;	//第一个孩子和右兄弟指针 
}CSNode,*CSTree; 

5.3.2 树的遍历

先根遍历
//树的先根遍历
void PreOrder(TreeNode *R){
	if(R!=NULL){
		visit(R);	//访问根节点
		while(R还有下一个子树T)
			PreOrder(T);	//先根遍历下一个子树 
	}
} 
后根遍历
//树的后根遍历
void PostOrder(TreeNode *R){
	if(R!=NULL){
		while(R还有下一个子树T)
			PostOrder(T);	//后根遍历下一棵子树 
		visit(R);	//访问根节点 
	}
} 

5.4  并查集

基本操作
//并查集的基本操作
#define SIZE 13
int UFSets[SIZE];	//集合元素数组

//初始化并查集
void Initial(int S[]){
	for(int i=0; i<SIZE; i++)
		S[i] = -1;
} 

//Find “查”操作,找x所属集合(返回x所属根节点)
int Find(int S[],int x){
	while(S[x]>=0)		//循环寻找x的根
		x = S[x];
	return x;			//根的S[]小于0 
} 
//Union “并”操作,将两个集合合并为一个 
void Union(int S[],int Root1,int Root2){
	//要求Root1与Root2是不同的集合
	if(Root1 == Root2)	return;
	//将根Root2连接到另一根Root1下面
	S[Root2] = Root1; 
} 
Union的优化
//Union “并”操作,小树合并到大树
void Union(int S[],int Root1,int Root2){
	if(Root1 == Root2)	return;
	if(S[Root2]>S[Root1]){		//Root2结点数更少 
		S[Root1] += S[Root2];	//累加节点总数 
		S[Root2] = Root1; 		//小树合并到大树 
	}else{
		S[Root2] += S[Root1];	//累加结点总数 
		S[Root1] = Root2		//小树合并到大树 
	}
} 
Find的优化
//Find “查”操作,先找到根节点,再进行“压缩路径” 
int Find(int S[],int x){
	int root = x;
	while(S[root]>0) root = S[root];	//循环找到根
	while(x != NULL){	//压缩路径 
		int t = S[x];	//t指向x的父节点 
		S[x] = root;	//x直接挂到根节点下 
		x = t;
	} 
	return root;		//返回根结点编号 
} 

第六章 图

6.1 图的存储

6.1.1 邻接矩阵法

//邻接矩阵法
#define MaxVertexNum 100		//顶点数目的最大值 
typedef struct{
	char Ver[MaxVertexNum];					//顶点表 
	int Edge[MaxVertexNum][MaxVertexNum];	//邻接矩阵、边表
	int vexnum,arcnum; 						//图的当前顶点数和边数/弧数 
}MGraph; 
//邻接矩阵法存储带权图	
#define MaxVertexNum 100		//顶点数目的最大值 
#define INFINITY 最大的int值	//宏定义常量“无穷” 
typedef char VertexType;		//顶点的数据类型 
typedef int EdgeType;			//带权图中边上权值的数据类型 
typedef struct{
	VertexType Vex[MaxVertexNum];				//顶点 
	EdgeType Edge[MaxVertexNum][MaxVertexNum];	//边的权 
	int vexnum,arcnum;							//图的当前顶点数和弧数 
}MGraph; 

6.1.2 邻接表法

//用邻接表存储的图
typedef struct{
	AdjList vertices;
	int vexnum,arcnum;
}ALGRaph; 
//“边/弧” 
typedef struct ArcNode{
	int adjvex;				//边/弧指向哪个结点 
	struct ArcNode *next;	//指向下一条弧的指针 
	//InfoType info;		//边权值 
}ArcNode; 
//顶点
typedef struct VNode{
	VertexType data;	//顶点信息 
	ArcNode *first;		//第一条边/弧 
}VNode,AdjList[MaxvertexNum]; 

6.2 图的遍历

6.2.1 广度优先遍历BFS

//广度优先遍历 
bool visited[MAX_VERTEX_NUM];	//访问标记数组 
void BFSTraverse(Graph G){		//对图G进行广度优先遍历	
	for(i=0; i<G.vexnum; ++i)	 
		visited[i] = FALSE;		//访问标记数组初始化 
	InitQueue(Q);				//初始化辅助队列Q 
	for(i=0; i<G.vexnum; ++i)	//从0号顶点开始遍历	 
		if(!visited[i])			//对每个连通分量调用一次BFS 
			BFS(G,i);			//vi未访问过,从vi开始BFS 
} 
void BFS(Graph G,int v){		//从顶点v出发,广度优先遍历图G 
	visit(v);					//访问初始顶点v 
	visited[i] = TRUE;			//对v做已访问标记 
	Enqueue(Q,v);				//顶点v入队列Q 
	while(!isEmpty(Q)){
		DeQueue(Q,v);			//顶点v出队列 
		for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w))
			//检测v所有邻接点
			if(!visited[w]){	//w为v的尚未访问的邻接顶点 
				visit(w);		//访问顶点w 
				visited[w]=TRUE;//对w做已访问标记 
				EnQueue(Q,w);	//顶点w入队列 
			}//if
	}//while
} 

6.2.2 深度优先遍历DFS

//深度优先遍历
bool visited[MAX_VERTEX_NUM];	//访问标记数组
void DFSTraverse(Graph G){		//对图G进行深度优先遍历 
	for(v=0; v<G.vexnum; ++v)
		visited[v] = FALSE;		//初始化已访问标记数据 
	for(v=0; v<G.vexnum; ++v)	//从v = 0开始遍历 
		if(!visited[w])
			DFS(G,v);
} 
void DFS(Graph G,int v){	//从顶点v出发,深度优先遍历G 
	visit(v);				//访问顶点v 
	visited[v] = TRUE;		//设已访问标记 
	for(w=FirstNeighbor(G,v); w>=0; w=NextNeighor(G,v,w))
		if(!visited[w]){	//w为u的尚未访问的邻接顶点 
			DFS(G,w);
		}	//if
}

6.3 图的应用

6.3.1 最短路径问题

BFS算法
//求顶点u到其他顶点的最短路径
void BFS_MIN_Distance(Graph G,int u){
	//d[i]表示u到i结点最短路径 
	for(i=0; i<G.vexnum; ++i){
		d[i] = ∞;		//初始化路径长度 
		path[i] = -1;	//最短路径从哪个顶点过来 
	} 
	d[u] = 0;
	visited[u] = TRUE;
	EnQueue(Q,u);
	while(!isEmpty(Q)){
		while(!isEmpty(Q)){				//BFS算法主过程 
			DeQueue(Q,u);				//队头元素u出队 
			for(w=FirstNeighbor(G,u); w>=0; w=NextNeighbor(G,u,w))
				if(!visited[w]){		//w为u的尚未访问的邻接顶点 
					d[w] = d[u]+1;		//路径长度加1 
					path[w] = u;		//最短路径应从u到w 
					visited[w] = TRUE;	//设已访问标记 
					EnQueue(Q,w);		//顶点w入队 
				}//if
		}//while
	}
} 
Dijkstra算法

        初始:若从v0开始,令final[0]=true; dist[0]=0; path[0]=-1。
                   其余顶点final[k]=false; dist[k]=arcs[0][k]; path[k]=(arc[0][k]== ∞)? -1:0
n-1轮处理:循环遍历所有的顶点,找到还没确定最短路径,且dist最小的顶点vi,令final[i]=true。                     并检查所有邻接自vi的顶点,对于邻接自vi的顶点vj,                                                                        若final[j]=false 且 dist[i]+arcs[i][j]<dist[j],则令dist[j]=dist[i]+arcs[i][j];path[j]=i                                  (注:arcs[i][j]表示vi到vj的弧的权值)

Floyd算法
//Floyd核心代码
//......核心代码,根据图的信息初始化矩阵A和path
for(int k=0; k<n; k++){			//考虑以 vk 为中转点 
	for(int i=0; i<n; i++){		//遍历整个矩阵,i为行号,j为列号 
		for(int j=0; j<n; j++){
			if(A[i][j] > A[i][k] + A[k][j]){	//以 vk 为中转点的路径更短 
				A[i][j] = A[i][k] + A[k][j];	//更新最短路径长度 
				path[i][j] = k; 				//中转点 
			}
		}
	}
} 

6.3.2拓补排序

//拓补排序
#define MaxVertexNum 100	//图中顶点数目的最大值
typedef struct ArcNode{		//边表结点 
	int adjvex;			//该弧所指向的顶点的位置 
	struce ArcNode *nextarc;//指向下一条弧的指针 
	//InfoType info; 		//网的边权值 
}ArcNode;
typedef struct VNode{		//顶点表结点 
	VertexType data;		//顶点信息 
	ArcNode * firstare;		//指向第一条依附该顶点的弧的指针 
}VNode,AdjList[MaxvertexNum];
typedef struct{
	AdjList vertices;		//邻接表 
	int vexnm,arcnum;		//图的顶点数和弧数 
}Graph; 					//Graph是以邻接表存储的图类型 

bool TopologicalSort(Graph G){
	InitStack(S);
	for(int i=0 ;i<G.vexnum; i++)
		if(indegree[i] == 0)
			Push(S,i);
	int count=0;
	while(!IsEmpty(S)){
		Pop(S,i);
		print[count++]=i;
		for(P=G.vertices[i].firstarc; p; p->nextarc){
		//将所有i指向的顶点的入度减1,并且讲入度减为0的顶点压入栈S
		v=p->adjvex;
		if(!(--indegree[v])) 
			Push(S,v);	
		}
	}//while
if(count<G.vexnum)
	return false;
else
	return true;
} 
//逆拓补排序的实现(DFS算法)
void DFSTraverse(Graph G){	//对图G进行深度优先遍历 
	for(v=0; v<G.vexnm; v++)
		visited[v]=FALSE;	//初始化已访问标记数据 
	for(v=0; v<G.vexnm; v++)//从v=0开始遍历 
		if(!visited[v])
			DFS(G,v);
} 
void DFS(Graph G,int v){	//从顶点v出发,深度优先遍历图G 
	visited[v]=TRUE;		//设已访问标记 
	for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w))
		if(!visited[w]){	//w为u的尚未访问的邻接顶点 
			DFS(G,w);
		}//if
	print(v);				//输出顶点 
}

第七章 查找

7.1 基本查找操作

7.1.1 顺序查找

typedef struct{		//查找表的数据结构(顺序表) 
	ElemType *elem;	//动态数组基址 
	int TableLen;	//表的长度 
}SSTable;
//顺序查找 
int Search_Seq(SSTable ST,ElemType key){
	int i;
	for(i=0; i<ST.TableLen && ST.elem[i] != key; ++i);
	//查找成功,则返回元素下标;查找失败,则返回-1
	return i==ST.TableLen? -1:i; 
} 

//顺序查找(哨兵)
int Search_Seq(SSTable ST,ElemType key){
	(ST.elem[0] = key;)	//哨兵 
	int i;
	for(i=ST.TableLen; ST.elem[i] != key; --i);	//引入哨兵时 
	//查找成功,则返回元素下标;查找失败,则返回0 
	return i; 
} 

7.1.2 折半查找

//折半查找
int Binary_Search(SSTable L, ElemType key){
	int low = 0, high = L.TableLen-1, mid;
	while(low <= high){
		mid = (low + high)/2;		//取中间位置 
		if(L.elem[mid] == key)
			return mid;				//查找成功则返回所在位置 
		else if(L.elem[mid] > key)
			high = mid - 1;			//从前半部分继续查找 
		else
			low = mid + 1;			//从后半部分继续查找 
	}
	return -1;						//查找失败,返回-1 
} 

7.1.3 分块查找

//索引表
typedef struct{
	ElemType maxValue;
	int low,high;
}Index;

//顺序表实际存储元素
ElemType List[100]; 

7.2 树型查找

7.2.1二叉排序树(BST)

二叉树的查找
//二叉排序树结点
typedef struct BSTNode{
	int key;
	struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree; 
//在二叉排序树中查找值为key的结点
BSTNode *BST_Search(BSTree T,int key){
	while(T!=NULL && key!=T->key){	//若树空或等于根结点值,则结束循环 
		if(key<T->key)
			T=T->lchild;	//小于,则在左子树上查找 
		else
			T=T->rchild;	//大于,则在右子树上查找 
	}
	return T;
} 
//在二叉排序树中查找值为key的结点(递归实现)
BSTNode *BSTSearch(BSTree T, int key){
	if(T == NULL)
		return NULL;	//查找失败
	if(key == T->key)
		return T;		//查找成功
	else if(key < T->key)
		return BSTSearch(T->lchild,key);	//在左子树中找
	else
		return BSTSearch(T->rchild,key);	//在右子树中找 
} 
二叉树的插入
//在二叉排序树插入关键字为k的新结点(递归实现)
int BST_Insert(BSTree &T, int k){
	if(T==NULL){			//原树为空,新插入结点为根结点 
		T=(BSTree)malloc(sizeof(BSTNode));
		T->key = k;
		T->lchild = T->rchild = NULL;
		return 1; 			//返回1.插入成功 
	}
	else if(k == T->key)	//树中存在相同关键字的结点,插入失败 
		return 0; 
	else if(k<T->key)		//插入到T的左子树 
		return BST_Insert(T->lchild,k);
	else					//插入到T的右子树 
		return BST_Insert(T->rchild,k); 
} 
二叉树的构造
//按照 str[] 中的关键字序列建立二叉排序树
void Creat_BST(BSTree &T,int str[],int n){
	T=NULL;			//初始时T为空树 
	int i=0;
	while(i<n){		//依次将每个关键字插入到二叉排序树中 
		BST_Insert(T,str[i]);
		i++;
	}
} 

第八章 排序

8.1 插入排序

8.1.1直接插入排序

//直接插入排序
void InsertSort(int A[], int n){
	int i,j,temp;
	for(i=1; i<n; i++)			//将各元素插入已排好序的序列中 
		if(A[i]<A[i-1]){		//若A[i]关键字小于前驱 
			temp = A[i];		//用temp暂存A[i] 
			for(j=i-1; j>=0&&A[j]>temp; --j)	//检查所有前面已排好序的元素 
				A[j+1] = A[j];	//所有大于temp的元素都向后挪位 
			A[j+1] = temp;		//复制到插入位置 
		}
} 
//直接插入排序(带哨兵)
void InsertSort(int A[], int n){
	int i,j;
	for(i=2; i<=n; i++)			//依次将A[2]~A[n]插入到前面已排序序列 
		if(A[i]<A[i-1]){		//若A[i]关键字小于前驱,将A[i]插入有序表 
			A[0] = A[i];		//复制为哨兵,A[0]不存元素 
			for(j=i-1; A[0]<A[j]; --j)	//向后往前查找待插入位置 
				A[j+1] = A[j];	//向后挪位 
			A[j+1] = A[0];		//复制到插入位置 
		}
} 

8.1.2 折半插入排序

//折半插入排序
void InsertSort(int A[], int n){
	int j,i,low,high,mid;
	for(i=2; i<=n; i++){			//依次将A[2]~A[n]插入前面的已排序序列 
		A[0]=A[i];					//将A[i]暂存到A[0] 
		low = 1; high = i-1; 		//设置折半查找的范围 
		while(low<=high){			//折半查找(默认递增有序) 
			mid=(low+high)/2;		//取中间点 
			if(A[mid]>A[0])	high = mid-1;//查找左半子表 
			else low = mid+1;		//查找右半子表 
		}
		for(j=i-1; j>=high+1; --j)
			A[j+1] = A[j];			//统一后移元素,空出插入位置 
		A[high+1] = A[0];			//插入操作 
	}
} 

8.1.3 希尔排序

//希尔排序
void ShellSort(int A[],int n){
	int d,i,j;
	//A[0]只是暂存单元,不是哨兵,当j<=0时,插入位置已到
	for(d=n/2; d>=1; d=d/2)	//步长变化
		for(i=d+1; i<=n; ++i)
			if(A[i]<A[i-d]){	//需要将A[i]插入有序增量子表 
				A[0]=A[i];			//暂存在A[0] 
				for(j=i-d; j>0 && A[0]<A[j]; j-=d) 
					A[j+d]=A[j];	//记录后移,查找插入位置 
				A[j+d]=A[0];		//插入 
			}
} 

8.2 交换排序

8.2.1 冒泡排序

//交换
void swap(int &a,int &b){
	int temp = a;
	a = b;
	b = temp;
} 
//冒泡排序
void BubbleSort(int A[], int n){
	for(int i=0; i<n-1; i++){
		bool flag = false;			//表示本趟冒泡是否发生交换的标志 
		for(int j=n-1; j>i; j--)	//一趟冒泡过程 
			if(A[j-1] > A[j]){		//若为逆序 
				swap(A[j-1],A[j]);	//交换 
				flag = true;
			}
		if(flag == false)
			return					//本趟遍历后没有发生交换,说明表已经有序 
	}
}

8.2.2 快速排序

//用第一个元素将待排序序列划分成左右两个部分
int Partition(int A[], int low, int high){
	int pivot = A[low];		//第一个元素作为枢轴 
	while(low<high){		//用low、high搜索枢轴的最终位置 
		while(low<high&&A[high]>=pivot)	--high;
		A[low] = A[high];	//比枢轴小的元素移动到左端 
		while(low<high&&A[low]<=pivot)	++low;
		A[high] = A[low];	//比枢轴大的元素移动到右端 
	}
	A[low] = pivot;			//枢轴元素存放到最终位置 
	return low;				//返回存放枢轴的最终位置 
} 
//快速排序
void QuickSort(int A[], int low, int high){
	if(low<high){	//递归跳出的条件 
		int pivotpos = Partition(A,low,high);	//划分	 
		QuickSort(A,low,pivotpos-1);	//划分左子表 
		QuickSort(A,pivotpos+1,high); 	//划分右子表 
	}
} 

8.3 选择排序

选择排序:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列

8.3.1 简单选择排序

//简单选择排序
void SelectSort (int A[],int n){
	for(int i=0; i<n-1;i++){		//一共进行n-1躺 
		int min=i;					//记录最小元素位置 
		for(int j=i+1; j<n; j++)	//在A[i...n-1]中选择最小的元素 
			if(A[j]<A[min])	min=j;	//更新最小元素位置 
		if(min!=i) swap(A[i],A[min]);//封装的swap()函数共移动元素3次 
	}
} 
//交换
void swap(int &a,int &b){
	int temp = a;
	a = b;
	b = temp;
} 

8.3.2 堆排序

//建立大根堆
void BuildMaxHeap(int A[], int len){
	for(int i=len/2; i>0; i--)	//从后往前调整所有非终端结点
		HeadAdjust(A,i,len); 
} 
//将以k为根的子树调整为大根堆
void HeadAdjust(int A[],int k, int len){
	A[0]=A[k];						//A[0]暂存子树的根结点 
	for(int i=2*k; i<=len; i*=2){	//沿key较大的子结点向下筛选 
		if(i<len&&A[i]<A[i+1])
			i++;					//取key较大的字结点的下标 
		if(A[0]>=A[i])	break;		//筛选结束 
		else{		
			A[k] = A[i];			//将A[i]调整到双亲结点下 
			k = i;					//修改k值,以便向下继续筛选 
		}	
	}
	A[k] = A[0];					//被筛选结点的值放入最终位置 
} 
//完整逻辑
void HeapSort(int A[], int len){
	BuildMaxHeap(A,len);		//初始建堆 
	for(int i=len; i>1; i--){	//n-1躺的交换和建堆过程 
		swap(A[i],A[1]);		//把堆顶元素和堆底元素交换 
		HeadAjdust(A,1,i-1);	//把剩余的待排序元素整理成堆 
	}
} 

8.4 归并排序和基数排序

8.4.1 归并排序

//归并排序
int *B = (int *)malloc(n*sizeof(int)); //辅助数组B

//A[low...mid]和A[mid+1...high]各自排序,将两个部分归并
void Merge(int A[], int low, int mid, int high){
	int i,j,k;
	for(k=low; k<=high; k++)
		B[k] = A[k];		//将A中所有元素复制到B中
	for(i=low,j=mid+1,k=i; i<=mid&&j<=high; k++){
		if(B[i] <= B[j])
			A[k] = B[i++];	//将较小值复制到A中
		else
			A[k] = B[j++]; 
	}//if 
	while(j<=mid)	A[k++] = B[i++];
	while(j<=high) 	A[k++] = B[j++];
} 

void MergeSort(int A[], int low, int high){
	if(low<high){
		int mid = (low+high)/2;		//从中间划分 
		MergeSort(A,low,mid);		//对左半部分归并排序 
		MergeSort(A,mid+1,high);	//对右半部分归并排序
		Merge(A,low,mid,high);		//归并 
	}//if 
}

  • 32
    点赞
  • 283
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值