数据结构相关代码

  1. 结构体定义方法
typedef struct
{
	int a;
	float b;
	char c;
	...
}结构体名
typedef struct 结构体名
{
	int a;
	float b;
	char c;
	struct 结构体名 *d;
	...
}结构体名
  1. 变量引用
int result = 0;

void add(int *r){
	(*r)++;
}

调用方法:add(&result);//这里的&是取地址符
int *p = NULL;

void add(int **p){//二级指针,指向指针的地址
	...
	*p = q;//q为某个地址
	...
}

调用方法:add(&p);
  1. 单链表节点定义
typedef struct LNode
{
	int data;
	struct LNode *next;
}LNode
  1. 双链表节点定义
typedef struct DLNode
{
	int data;
	struct DLNode *next;
	struct DLNode *prior;
}DLNode
  1. 顺序表建表代码
int A[maxSize];
int length;
int createList(int A[],int& length)
{
	std::cin>>length;
	if(length > maxSize) return 0;
	for(int i = 0;i < length;i++)
	std::cin>>A[i];
	return 1;
}
  1. 链表建表的代码
void createLinkListR(LNode *&head)
{
	head = (LNode*)malloc(sizeof(LNode));
	//每次为链表申请一个结点空间之后,把这个结点的next指针设定为NULL能够有
	//效避免错误
	head->next = NULL;
	/*我们使用的是尾插法,需要定义一个指针来指向当前尾部的结点。方便下一次创建。
	另外还需要一个指针来指向当前新增的结点。
	p指针为指向新增结点的指针。
	r指针为指向当前尾部结点的指针。
	*/
	LNode *p = NULL,*r = head;
	//描述要创建的结点的个数
	int n;
	std::cin>>n;//从键盘输入。scanf("%d",&n);
	for(int i = 0;i < n;++i)
	{
		//每次循环创建一个结点,并从键盘输入传个结点的data域
		p = (LNode*)malloc(sizeof(LNode));
		p->next = NULL;
		std::cin>>p->data;//scanf("%d",&(p->data);
		//此行代码删除对尾插法没有影响,增加这行代码能够使这个方法
		//适用于从中部插入,也就是适用于r结点指向中部的某一结点
		p->next = r->next;
		
		r->next = p;
		r = p;
	}
void createLinkListH(LNode *&head)
{
	head = (LNode*)malloc(sizeof(LNode));
	//每次为链表申请一个结点空间之后,把这个结点的next指针设定为NULL能够有
	//效避免错误
	head->next = NULL;
	/*使用头插法的话则不需要一个指针来指向尾结点了,
	只需要一个指向新建结点的指针*/
	LNode *p = NULL;
	//描述要创建的结点的个数
	int n;
	std::cin>>n;//从键盘输入。scanf("%d",&n);
	for(int i = 0;i < n;++i)
	{
		//每次循环创建一个结点,并从键盘输入传个结点的data域
		p = (LNode*)malloc(sizeof(LNode));
		p->next = NULL;
		std::cin>>p->data;//scanf("%d",&(p->data);
		//让p指向的结点中的指针指向head原先指向的结点
		p->next = head->next;
		//让头结点的指针指向新增的结点
		head->next = p;

	}
  1. 顺序表归并
//传入三个数组,(两个初始数组,一个结果数组),以及两个顺序表的长度
//这里返回值为void,假设传入的结果数组是足够长的,不存在归并失败的情况
void mergearray(int a[],int m,int b[],int n,int c[])
{	
	//i和j分别指向两个顺序表的首部
	int i = 0,j = 0;
	//用来指向结果顺序表的尾部
	int k = 0;
	while(i < m && j < n){
		if(a[i] < n[j])
		c[k++] = a[i++];
		else
		c[k++] = b[j++]; 
	}
	while(i < m) c[k++] = a[i++];
	while(j < n) c[k++] = b[j++]; 
}
  1. 链表归并
//升序归并
//传入三个链表的头指针,A和B是原先两个链表的头指针,不需要改变,因此不用引用类型
//而C是我们新得到的头结点的指针,需要进行改变,所以用引用类型
void merge(LNode *A,LNode *B,LNode *&C)
{
	//指向两个链表第一个结点的指针
	LNode *p = A->next;
	LNode *q = B->next;
	//用来保存每次比较指向data域较小结点的指针
	LNode *s;
	//让C指向A链表的头结点
	C = A;
	C->next = NULL;
	//释放B链表的头结点
	free(B);
	while(p != NULL && q != NULL){
		if(p->data < q->data) 
		{
			s = p;
			p = p->next;
			s->next = C->next;
			C->next = s;
		}
		else
		{
			s = q;
			q = q->next;
			s->next = C->next;
			C->next = s;
		}
	}
	while (p != NULL) 
	{
		s = p;
		p = p->next;
		s->next = C->next;
		C->next = s;
	}
	while (q != NULL)
	{
		s = q;
		q = q->next;
		s->next = C->next;
		C->next = s;
	}
}
//降序归并
//传入三个链表的头指针,A和B是原先两个链表的头指针,不需要改变,因此不用引用类型
//而C是我们新得到的头结点的指针,需要进行改变,所以用引用类型
void mergeR(LNode *A,LNode *B,LNode *&C)
{
	//指向两个链表第一个结点的指针
	LNode *p = A->next;
	LNode *q = B->next;
	//用来指向结果链表尾部元素的指针
	LNode *s;
	//让C指向A链表的头结点
	C = A;
	C->next = NULL;
	//释放B链表的头结点
	free(B);
	while(p != NULL && q != NULL){
		if(p->data < q->data) 
		{
			r->next = p;
			r = p;
			p = p->next;
		}
		else
		{
			r->next = q;
			r = q;
			q = q->next;
		}
	}
	if (p != NULL) 
		r->next = p;
	if (q != NULL)
		r->next = q;
}

  1. 中缀表达式转后缀表达式代码
//infix:中缀表达式
//s2:栈,用来存储转化结果
//top2:栈顶指针
void infixToPostFix(char infix[],char s2[],int &top2)
{	//辅助栈
	char s1[maxSize];int top = -1;
	int i = 0;
	//开始循环中缀表达式
	while(infix[i] != '\0')
	{
		//判断是否是数字字符,是的话直接入保存结果的栈
		if('0' <= infix[i] && infix[i] <= '9')
		{
			s2[++top2] = infix[i];
			++i;
		}
		//判断是否是左括号,是的话则直接入辅助栈
		else if(infix[i] == '(')
		{
			s1[++top1] = '(';
			++i;
		}
		//判断是否是运算符
		else if(infix[i] == '+' || infix[i] =='-' 
		|| infix[i] =='*' || infix[i] == '/')
		{	
			//是运算符的话还要进一步判断,如果栈为空或者栈顶元素为左括号
			//或者运算符比栈顶元素的优先级高则入辅助栈
			if(top1 == -1 || s1[top1] == '(' 
			|| getPriority(infix[i]) > getPriority(s1[top1])
			{
				s1[++top1] = infix[i];
				++i;
			}
			//否则的话就将辅助栈的栈顶元素出栈并且存储到结果栈中
			else 
				s2[++top2] = s1[top1--];
		}
		//判断是否是右括号
		else if (infix[i] == ')')
		{
			//判断栈顶元素是否是左括号,不是的话则栈顶元素一直出栈并存入结果栈中,
			//直到栈顶元素为左括号
			while(s1[top1] != '(')
				s2[++top2] = s1[top1--];
			--top1;//把左括号也出栈,但不存入结果栈中
			++i;	
		}
	}
		//扫描完中缀表达式之后在将辅助栈中剩余的运算符存到结果栈中
		while(top1 != -1)
		s2[++top2] = s1[top1--];
}
  1. 中缀表达式转前缀表达式代码
//infix:中缀表达式
//len:中缀表达式的长度
//s2:栈,用来存储转化结果
//top2:栈顶指针
void infixToPreFix(char infix[],int len,char s2[],int &top2)
{	//辅助栈
	char s1[maxSize];int top = -1;
	int i = len - ;
	//开始循环中缀表达式
	while(infix[i] != '\0')
	{
		//判断是否是数字字符,是的话直接入保存结果的栈
		if('0' <= infix[i] && infix[i] <= '9')
		{
			s2[++top2] = infix[i];
			--i;
		}
		//判断是否是右括号,是的话则直接入辅助栈
		else if(infix[i] == ')')
		{
			s1[++top1] = ')';
			--i;
		}
		//判断是否是运算符
		else if(infix[i] == '+' || infix[i] =='-' 
		|| infix[i] =='*' || infix[i] == '/')
		{	
			//是运算符的话还要进一步判断,如果栈为空或者栈顶元素为右括号
			//或者运算符比栈顶元素的优先级高或等于则入辅助栈
			if(top1 == -1 || s1[top1] == ')' 
			|| getPriority(infix[i]) >= getPriority(s1[top1])
			{
				s1[++top1] = infix[i];
				--i;
			}
			//否则的话就将辅助栈的栈顶元素出栈并且存储到结果栈中
			else 
				s2[++top2] = s1[top1--];
		}
		//判断是否是左括号
		else if (infix[i] == '(')
		{
			//判断栈顶元素是否是右括号,不是的话则栈顶元素一直出栈并存入结果栈中,
			//直到栈顶元素为右括号
			while(s1[top1] != ')')
				s2[++top2] = s1[top1--];
			--top1;//把左括号也出栈,但不存入结果栈中
			--i;	
		}
	}
		//扫描完中缀表达式之后在将辅助栈中剩余的运算符存到结果栈中
		while(top1 != -1)
		s2[++top2] = s1[top1--];
}
  1. 用栈求中缀表达式的值代码
//判断运算符优先级
void getPriority(char op)
{
	if( op == '+' || == '-')
		return 0;
	else 
		return 1;
}

//计算子表达式函数,根据当前出栈的运算符进行相应的计算
//opand1、opand2是操作数,op为运算符
int calSub(float opand1,char op,float opand2,float &result)
{
	if(op == '+') result = opand1 + opand2;
	if(op == '-') result = opand1 - opand2;
	if(op == '*') result = opand1 * opand2;
	if(op == '/') 
	{
		//检测除数是否为0
		//fabs:求绝对值,MIN:预先定义好的宏,代表一个十分接近0的正数
		//这样写是判断浮点数是否为0的标准写法,在十分接近0的时候我们认为它为0
		if(fabs(opand2) < MIN)
		{
			//说明当前运算无法继续下去
			return 0;
		}
		else
		{
			return opand1/opand2;
		}
	}
}
int calStackTopTwo(float s1[], int &top1, char s2[], int &top2)
{
	float opnd1,opnd2,result;
	char op;
	int flag;
	//出栈两个操作数	
	opnd2 = s1[top1--];
	opnd1 = s1[top1--];
	//出栈运算符
	op = s2[top2--];
	//调用计算函数
	flag = calSub(opnd1,op,opnd2,result);
	//判断子表达式是否求值成功
	if(flag == 0)
		std::cout<<"ERROR"<<std:endl;//puts("ERROR");
	s1[++top1] = result;
	return flag;
}
//直接将运算结果返回
float calInfix(char exp[])
{
	//定义两个栈,一个用来存放操作数,一个用来存放运算符
	float s1[maxSize];int top1 = -1;
	char s2[maxSize];int top2 = -1;
	int i = 0;
	//循环中缀表达式
	while (exp[i] != '\0')
	{
		//假设输入的操作数都是一位数的
		if('0' <= exp[i] && exp[i] <= '9')
		{
			//是操作数则入s1栈
			s1[++top1] = exp[i] - '0';
			++i;
		}
		//判断是否为左括号
		else if(exp[i] == '(')
		{
			//左括号直接入s2栈
			s2[++top2] = '(';
			++i;
		}
		//判断是否为运算符
		else if (exp[i] == '+' ||
				 exp[i] == '-' ||
				 exp[i] == '*' ||
				 exp[i] == '/')
		{
			//优先级大于栈顶运算符或栈为空或栈顶为左括号时则入栈
			if(top2 == -1 || s2[top2] == '(' ||
			getPriority(exp[i]) > getPriority(s2[top2])
			{
				s2[++top2] = exp[i];
				++i;
			}
			//否则出栈栈顶运算符和两个操作数并进行一次运算
			else 
			{
				int flag = calStackTopTwo(s1,top1,s2,top2);
				//如果返回的标志为0,结束函数
				if(flag == 0) return 0;
				//计算完之后,i不需要加1,因为还要重新对i所指向的运算符与栈顶运算符比较
			}
		} 
		//判断是否为右括号
		else if(exp[i] ==')')
		{
			//一直出栈s2栈顶元素进行运算直至遇到左括号
			while(s2[top2] != '(')
			{
				int flag = calStackTopTwo(s1,top1,s2,top2);
				//如果返回的标志为0,结束函数
				if(flag == 0) return 0;
			}
			//循环结束,出栈左括号
			top2--;
			//处理表达式下一个字符
			++i;
		}
	}
	
	//当中缀表达式扫描完之后,s2栈仍有运算符时,不断出栈进行计算
	while(top2 != -1)
	{
		int flag = calStackTopTwo(s1,top1,s2,top2);
				//如果返回的标志为0,结束函数
				if(flag == 0) return 0;
	}
		
		//最后s1栈顶元素即为结果
		return s1[top1];
}
  1. 用栈求后缀表达式的值代码
float calPostFix(char exp[])
{
	float s[maxSize];int top = -1;
	while(exp[i] != '\0')
	{
		if(exp[i] >= '0' && exp[i] <= '9')
			s[++top] = exp[i] -'0';
		else if (exp[i] == '+' ||
				 exp[i] == '-' ||
				 exp[i] == '*' ||
				 exp[i] == '/')
		{
			float opnd1,opnd2,result;
			char op;
			int flag;
			opnd2 = s[top--];
			opnd1 = s[top--];
			op = exp[i];
			flag = calSub(opnd1,op,opnd2,result);
			//判断子表达式计算是否成功
			if(flag == 0)
			{
				std::cout<<"ERROR"<<std::endl;//puts("ERROR");
				return 0;
			}
			//成功则把子表达式计算结果压入栈中
			s[++top] = result;
		}
		i++;
	}
	return s[top];
}
  1. 用栈求前缀表达式的值代码
float calPreFix(char exp[],int len)
{
	float s[maxSize];int top = -1;
	for(int i = len - 1;i >= 0;i--)
	{
		if(exp[i] >= '0' && exp[i] <= '9')
			s[++top] = exp[i] -'0';
		else 
		{
			float opnd1,opnd2,result;
			char op;
			int flag;
			opnd1 = s[top--];
			opnd2 = s[top--];
			op = exp[i];
			flag = calSub(opnd1,op,opnd2,result);
			//判断子表达式计算是否成功
			if(flag == 0)
			{
				std::cout<<"ERROR"<<std::endl;//puts("ERROR");
				return 0;
			}
			//成功则把子表达式计算结果压入栈中
			s[++top] = result;
		}
	}
	return s[top];
}
  1. 括号匹配代码
//定义一个方法判断括号是否匹配
int isMatch(char left, char right)
{
	if(left =='(' && right == ')')
	return 1;
	else if(left == '[' && right == ']')
	return 1;
	else if(left == '{' && right == '}')
	return 1;
	else
	return 0;
}
//判断表达式的括号是否匹配
int isParenthesesBalenced(char exp[])
{
	char s[maxSize];int top = -1;
	for(int i = 0;exp[i] != '\0';i++)
	{
		//判断是否为左括号,是的话直接入栈
		if(exp[i] == '(' || exp[i] == '[' || exp[i] == '{')
		 s[++top] = exp[i];
		 //判断是否为右括号,分情况讨论
		 if(exp[i] == ')' || exp[i] == ']' || exp[i] == '}')
		 {
		 	//如果栈空,函数结束,括号不匹配
		 	if(top == -1)
		 	return 0;
			//栈不空,出栈栈顶括号,判断是否与扫描到的括号匹配
			char left = s[top--];
			//括号不匹配,函数结束,表达式括号不匹配
			if(isMatched(left ,exp[i] == 0)
				return 0;
		 }
	}	
	//扫描完表达式之后,如果栈不为空的话,代表表达式括号不匹配,函数结束。
	if(top > -1) return 0;
	//表达式括号匹配
	return 1;
}
  1. 字符串赋值代码
//str:用串的结构体(变长存储结构)定义的一个变量,定义为引用型,引用我们要使字符串发生改变
//ch:指向我们申请好的一片连续的存储空间的首地址,等价于一个数组
//用存在于数组中的数组赋值给我们的目标串
int strAssign(Str &str,char *ch)
{
	//如果将要被赋值的串已经指向一片存储空间,就释放这片存储空间
	if(str.ch) free(str.ch);
	int len = 0;
	char *c = ch;
	//确定我们赋值目标串的长度,当c来到数组中的最后一个字符也就是'\0'循环就结束
	while(*c)
	{
		++len;
		++c;
	}
	//拿来赋值的字符串是个空串
	if(len == 0)
	{
		str.ch = NULL;
		str.length = 0;
		return 1;
	}
	else
	{
		//要为结束标记也分配一个存储空间
		str.ch = (char*)malloc(sizeof(char) * (len + 1));
		//如果为NULL,表明申请存储空间失败,返回0,赋值失败
		if(str.ch == NULL)
			return 0;
		else 
		{
			c = ch;
			//循环len + 1次,把结束标记也复制过来
			for(int i = 0; i <= len;++i;++c)
				str.ch[i] = *c;
			str.length = len;
			return 1;
		}
	}
}
  1. 字符串比较代码:
int strCompare(Str s1,Str s2)
{
	for(int i = 0; i < s1.length && i <s2.length; i++)
		if(s1.ch[i] != s2.ch[2])
			return s1.ch[i] - s2.ch[i];
	return s1.length - s2.length;
}
  1. 字符串求子串代码
//pos 为起点
//len 为所要取的长度
int getSubString(Str &substr,Str str,int pos,int len)
{
	//不合法的情况
	if(pos < 0 || pos >= str.length 
	   || len < 0 || len > str.length - pos)
	   return 0;
	if(substr.ch)
	{
		free(substr.ch);
		substr.ch = NULL;
	}
	if(len == 0)
	{
		substr.ch = NULL;
		sub.length = 0;
		return 1;
	}
	else
	{
		substr.ch = (char*)malloc(sizeof(char) * (len +1));
		int i = pos;
		int j = 0;
		while(i < pos + len)
		{
			substr.ch[j] = str.ch[i];
			i++;
			j++;
		}
		substr.ch[j] = '\0';
		substr.length = len;
		return 1;
	}
}
  1. 字符串清空代码
int clearString(Str &str)
{
	if(str.ch)
	{
		free(str.ch);
		str.ch = NULL;
	}
	str.length = 0;
	return 1;
}
  1. 字符串连接代码
int concat(Str &str,Str str1,Str str2)
{
	if(str.ch)
	{
		free(str.ch);
		str.ch = NULL;
	}
	str.ch = (char*)malloc(sizeof(char) * (str1.length + str2.length + 1));
	//申请存储空间失败
	if(!str.ch) return 0;
	int i = 0;
	while(i <str1.length)
	{
		str.ch[i] = str1.ch[i];
		++i;
	}
	int j = 0;
	//把结束标志也存储过来
	while(i <=str2.length)
	{
		str.ch[i+j] = str2.ch[i];
		++j;
	}
	str.length = str1.length + str2.length;
	return 1;
}
  1. 简单模式匹配算法代码
//简单模式匹配算法、朴素模式匹配算法
//返回值为int ,如果在主串中找到了子串的话就返回第一个字符所在的位置
//找不到就返回一个不会用到的值作为标记
int naive(Str str, Str substr)
{
	//辅助变量,i指向主串,j指向模式串
	//k为标记,用于存储每轮比较主串比较的元素的初始位置
	//初值为1代表模式串跟主串都是从数组下标1开始存储
	int i = 1,j =1,k = i;
	//开始循环
	while(i <= str.length && j <= substr.length)
	{
		if(str.ch[i] == substr.ch[i])
		{
			++i;++j;
		}
		else
		{
			i = ++k;
			j = 1;
		}
	}
	//判断是否成功找到,当j超过模式串长度即为找到,此时k指在这个子串首字母所在位置
	if(j > substr.length)
		return k;
	else 
		return 0;
}
  1. KMP算法代码:
//简单模式匹配算法、朴素模式匹配算法
//返回值为int ,如果在主串中找到了子串的话就返回第一个字符所在的位置
//找不到就返回一个不会用到的值作为标记
int KMP(Str str, Str substr, int next[])
{
	//辅助变量,i指向主串,j指向模式串
	//初值为1代表模式串跟主串都是从数组下标1开始存储
	int i = 1,j =1;
	//开始循环
	while(i <= str.length && j <= substr.length)
	{
		//通过next数组,j有可能为0;
		//判断主串与模式串的字符相不相等
		if(j == 0 || str.ch[i] == substr.ch[i])
		{
			++i;++j;
		}
		//某个字符不匹配,通过next数组来调整j指针的位置
		else
		{
			j = next[j];
		}
	}
	//判断是否成功找到,当j超过模式串长度即为找到,此时k指在这个子串首字母所在位置
	if(j > substr.length)
		return i - substr.length;
	else 
		return 0;
}

求解next数组

//参数为模式串和next数组,由于一般不会执行失败,所以返回值为void
//由next[j]求得next[j+1]的值
void getNext(Str substr, int next[])
{
	int j = 1,t = 0;
	next[1] = 0;
	while(j < substr.length)
	{
		if(t == 0 || substr.ch[j] == substr.ch[t])
		{
			next[j+1] = t + 1;
			++t;
			++j; 
		}
		else
			t = next[t];
	}
}
  1. KMP算法改进
void getNextval(Str substr, int nextval[])
{
	int j = 1,t = 0;
	nextval[1] = 0;
	while(j < substr.length)
	{
		if(t == 0 || substr.ch[j] == substr.ch[t])
		{
			if(substr.ch[j+1] != substr.ch[t+1])
				nextval[j+1] = t+1;
			else
				nextval[j+1] = nextval[t+1];
			++t;
			++j; 
		}
		else
		//使用nextval数组来调整t的位置
			t = nextval[t];
	}
}
  1. 二叉树的先序遍历非递归化代码
typedef struct BTNode
{
	int data;
	BTNode *lchild;
	BTNode *rchild;
}BTNode


//参数为二叉树结点类型的指针,一般传入根结点
void preorderNonrecursion(BTNode *bt)
{
	if(bt != NULL)
	{
		//辅助栈,存储指向结点的指针
		BTNode *Stack[maxSize];
		int top = -1;
		//遍历指针
		BTNode *p = NULL;
		//开始遍历
		Stack[++top] = bt;
		//当栈不空时继续操作
		while(top != -1) 
		{
			//出栈一个结点
			p = Stack[top--];
			//访问这个结点
			Visit(p);
			//判断其左右孩子是否存在,存在则将它们入栈,右左顺序
			if(p->rchild != NULL)
				Stack[++top] = p->rchild;
			if(p->lchild != NULL)
				Stack[++top] = p->lchild;
		}
	}
}
  1. 二叉树的后续遍历非递归化代码
//参数为二叉树结点类型的指针,一般传入根结点
void postorderNonrecursion(BTNode *bt)
{
	if(bt != NULL)
	{
		//辅助栈,存储指向结点的指针
		BTNode *Stack1[maxSize];
		int top1 = -1;
		//辅助栈,保存逆后序遍历序列
		BTNode *Stack12[maxSize];
		int top2 = -1;
		//遍历指针
		BTNode *p = NULL;
		//开始遍历
		Stack[++top1] = bt;
		//当栈不空时继续操作
		while(top != -1) 
		{
			//出栈一个结点
			p = Stack[top1--];
			//出栈后进入另外一个栈
			Stack2[++top2] = p;
			//判断结点的左右孩子结点是否存在,存在则入栈,左右顺序
			if(p->lchild != NULL)
				Stack[++top1] = p->lchild;
			if(p->rchild != NULL)
				Stack[++top1] = p->rchild;
		}
		//出栈辅助栈元素,由逆后序序列得到后序遍历序列
		while(top2 != -1)
		{
			p = Stack[top2--];
			Visit(p);
		}
	}
}
  1. 二叉树的中序遍历非递归化代码
void inorderNorecursion(BTNode *bt)
{	
	if(bt != NULL)
	{
		BTNode *Stack[maxSize];int top = -1;
		BTNode *p = NULL;
		p = bt;
		//开始遍历
		//判断栈是否为空或遍历指针是否为空,当两者同时为空时循环结束
		while(top != -1 || p != NULL)
		{
			//指针p沿着左走直至左孩子指针为空,将途经的结点入栈
			while(p != NULL)
			{
				Stack[++top] = p;
				p = p->lChild;
			}
			if(top != -1)
			{
				//出栈一个结点并访问它
				p = Stack[top--];
				Visit(p);
				//将遍历指针指向这个结点的右孩子,准备判断它是否为空
				p = p->rChild;
			}
		}
	}
}
  1. 二叉树层次遍历代码
void level(BTNode *bt)
{
	if(bt != NULL)
	{
		//队头队尾指针,定义一个辅助队列
		int front,rear;
		BTNode *que[maxSize];
		front = rear = 0;
		BTNode *p;
		//根结点入队
		rear = (rear + 1)% maxSize;
		que[rear] = bt;
		//开始遍历
		while(front != rear)
		{
			//出队一个结点并访问
			front = (front + 1)% maxSize;
			p = que[front];
			Visit(p);
			//判断结点的左右孩子是否存在,存在则入队
			if(p->lChild != NULL)
			{
				rear = (rear + 1)% maxSize;
				que[rear] = p->lChild;
			}
			if(p->rChild != NULL)
			{
				rear = (rear + 1)% maxSize;
				que[rear] = p->rChild;
			}
		}
	}
}
  1. 树的深度优先先序遍历代码
typedef struct Branch
{
	int cIdx;
	Branch *next;
}

typedef struct TNode
{
	int data;
	Branch *first;
}

void preOrder(TNode *p,TNode tree[])
{
	if(p != NULL)
	{
		Visit(p);
		Branch *q;
		q = p->first;
		while(q != NULL)
		{
			preOrder(&tree[q->cIdx],tree);
			q = q->next;
		}
}
  1. 树的深度优先后序遍历代码
void postOrder(TNode *p,TNode tree[])
{
	if(p != NULL)
	{
		Branch *q;
		q = p->first;
		while(q != NULL)
		{
			postOrder(&tree[q->cIdx],tree);
			q = q->next;
		}
		Visit(p);
}
  1. 树的层次遍历代码
void level(TNode *tn,TNode tree[])
{
	if(tn != NULL)
	{
		//队头队尾指针,定义一个辅助队列
		int front,rear;
		TNode *que[maxSize];
		front = rear = 0;
		TNode *p;
		//根结点入队
		rear = (rear + 1)% maxSize;
		que[rear] = tn;
		//开始遍历
		while(front != rear)
		{
			//出队一个结点并访问
			front = (front + 1)% maxSize;
			p = que[front];
			Visit(p);
			//找到第一个孩子结点
			Branch *q = p->first;
			//将这个孩子结点的兄弟结点依次入队
			while(q != NULL)
			{
				rear = (rear + 1)% maxSize;
				que[rear] = &tree[q->cIdx];
				q = q->next;
			}
		}
	}
}
  1. 二叉树中序线索化代码
//p,遍历指针,初值一般指向根结点
//pre指针,指向当前结点的前驱结点,初值为空
void inThread(TBTNode *p, TBTNode *&pre)
{
	if(p != NULL)
	{
		inThread(p->lChild,pre);
		//中序遍历过程中,如果某结点的左孩子指针为空
		//则将左孩子指针规定为线索,连接其前驱结点
		if(p->lChild == NULL)
		{
			p->lChild = pre;
			p->lTag = 1;
		}
		//如果前驱结点不为空且前驱结点右孩子指针为空
		//则将右孩子指针规定为线索,连接其后继结点
		if(pre != NULL && pre->rChild == NULL)
		{
			pre->rChild = p;
			pre->rTag = 1;
		}
		//此次访问的结点作为新的前驱结点
		pre = p;
		//p指针移动到当前访问的结点的右孩子结点
		inThread(p->rChild,pre);
	}
}
  1. 二叉树先序线索化
void preThread(TBTNode *p, TBTNode *&pre)
{
	if(p != NULL)
	{
		if(p->lChild == NULL)
		{
			p->lChild = pre;
			p->lTag = 1;
		}
		if(pre != NULL && pre->rChild == NULL)
		{
			pre->rChild = p;
			pre->rTag = 1;
		}
		pre = p;
		//左指针和右指针不是线索时才进入递归,否则会出现死循环
		if(p->lTag ==0)
		 	preTheread(p->lChild,pre);
		if(p->rTag ==0)
		 	preTheread(p->rChild,pre); 
	}
}
  1. 前序线索二叉树遍历代码
void preOrder(TBTNode *tbt)
{
	if(tbt != NULL)
	{
		TBTNode *p = tbt;
		while(p != NULL)
		{
			while(p->lTag == 0)
			{
				Visit(p);
				p = p->lChild;
			}
			Visit(p);
			p = p->rChild;
		}
	}
}
  1. 二叉树后序线索化代码
void postThread(TBTNode *p, TBTNode *&pre)
{
	if(p != NULL)
	{
		postTheread(p->lChild,pre);
		postTheread(p->rChild,pre); 
		if(p->lChild == NULL)
		{
			p->lChild = pre;
			p->lTag = 1;
		}
		if(pre != NULL && pre->rChild == NULL)
		{
			pre->rChild = p;
			pre->rTag = 1;
		}
	}
}
  1. 已知先序遍历序列和中序遍历序列求二叉树代码
//返回一个指针,指向二叉树的根结点
//pre:先序序列   in:中序序列
//L1、R1:为先序序列控制范围的变量,代表当前操作的pre数组的元素下标范围为L1到R1
//L2、R2:为中序序列控制范围的变量,代表当前操作的in数组的元素下标范围为L2到R2
BTNode *CreateBT(char pre[],char in[],int L1,int R1,int L2,int R2)
{
	//递归出口,处理序列长度为0
	if(L1 > R1) return NULL;	
	//建立根结点,先序序列也就是pre数组的第一个元素
	BTNode *s = (BTNode*)malloc(sizeof(BTNode));
	s->lChild = s->rChild = NULL;
	s->data = pre[L1];
	//到中序遍历序列中找到根结点的位置,中序遍历序列被划分为两部分
	int i;
	for(i = L2;i <= R2;i++)
		if(in[i] == pre[L1])
			break;
	
	//递归入口
	s->lChild = CreateBT(pre,in,L1+1,L1+i-L2,L2,i-1);
	s->rChild = CreateBT(pre,in,L1+i-L2+1,R1,i+1,R2);
	return s;
}
  1. 已知后序遍历序列和中序遍历序列求二叉树代码
//返回一个指针,指向二叉树的根结点
//pre:后序序列   in:中序序列
//L1、R1:为后序序列控制范围的变量,代表当前操作的post数组的元素下标范围为L1到R1
//L2、R2:为中序序列控制范围的变量,代表当前操作的in数组的元素下标范围为L2到R2
BTNode *CreateBT2(char post[],char in[],int L1,int R1,int L2,int R2)
{
	//递归出口,处理序列长度为0
	if(L1 > R1) return NULL;	
	//建立根结点,后序序列也就是post数组的最后一个元素
	BTNode *s = (BTNode*)malloc(sizeof(BTNode));
	s->lChild = s->rChild = NULL;
	s->data = post[R1];
	//到中序遍历序列中找到根结点的位置,中序遍历序列被划分为两部分
	int i;
	for(i = L2;i <= R2;i++)
 		if(in[i] == post[R1])
			break;
	
	//递归入口
	s->lChild = CreateBT2(post,in,L1,L1+i-L2-1,L2,i-1);
	s->rChild = CreateBT2(post,in,L1+i-L2,R1-1,i+1,R2);
	return s;
}
  1. 已知层次遍历序列和中序遍历序列求二叉树代码
//将查找元素的代码提取出来
int search(char arr[],char key, int L,int R)
{
	int idx;
	for(idx = L; idx <= R; ++idx)
	{
		if(arr[idx] == key) return idx;
		return -1;
	}
}

//从层次遍历序列中挑出左右子树元素并存入数组的方法
//subLevel:用来存储层次序列中左子树部分或右子树部分元素的数组
//level:层次遍历序列
//in:中序遍历序列
//n:层次遍历序列的长度
//L,R:为中序序列控制范围的变量,代表当前操作的in数组的元素下标范围为L到R
//调整LR能够使方法查找左子树的元素或者右子树的元素
//方法逻辑:循环level数组,判断level数组是否包含in数组中L到R范围内的元素,
//是的话则存入新的数组
void getSubLevel(char subLevel[],char level,char in[],
				int n,int L,int R)
{
	int k = 0;
	for(int i = 0; i < n; i++)
	{
		if(search(in,level[i],L,R) != -1)
			subLevel[k++] = level[i];
	}
}

//返回一个指针,指向二叉树的根结点
//level:层次序列   in:中序序列
//n:层次序列的长度
//L、R:为中序序列控制范围的变量,代表当前操作的in数组的元素下标范围为L到R
BTNode *CreateBT3(char level[],char in[],int n,int L,int R)
{
	//递归出口,处理序列长度为0
	if(L > R) return NULL;	
	//建立根结点,先序序列也就是pre数组的第一个元素
	BTNode *s = (BTNode*)malloc(sizeof(BTNode));
	s->lChild = s->rChild = NULL;
	s->data = level[0];
	//到中序遍历序列中找到根结点的位置,中序遍历序列被划分为两部分
	int i = search(in,level[0],L,R);
	//新建两个数组,用以存放层次遍历中左右子树的元素
	int LN = i-L;char LLevel[LN];
	int RN = R-i;char RLevel[RN];
	
	//挑出层次遍历中左右子树元素两部分,存入数组中
	getSubLevel(LLevel,level,in,n,L,i-1);
	getSubLevel(RLevel,level,in,n,i+1,R);
	
	
	//递归入口
	s->lChild = CreateBT3(LLevel,in,LN,L,i-1);
	s->rChild = CreateBT3(Rlevel,in,RN,i+1,R);
	return s;
}
  1. 图的结构体
//边结点
typedef struct ArcNode
{
	//邻接顶点(这条边所指的顶点)在数组中的下标
	int adjV;
	//指向下一个边结点的指针
	struct ArcNode *next;
}ArcNode;

//顶点结点
typedef struct 
{
	//顶点所存的数据
	int data;
	//指向顶点相关的第一条边
	ArcNode *first;
}VNode;


//图的结构体
typedef struct
{
	//顶点数组
	VNode adjList[maxSize];
	//n:顶点个数 e:边的条数
	int n,e;
}AGraph;
  1. 图的十字链表结构体
//此代码考的极少
//边结点
typedef struct ArcNode
{
	//起点下标
	int start;
	//终点下标
	int end;
	//指向下一个入边的指针
	struct ArcNode *nextIn;
	//指向下一个出边的指针
	struct ArcNode *nextOut;
	
}ArcNode;

//顶点结点
typedef struct 
{
	//顶点所存的数据
	int data;
	//指向顶点相关的第一条入边
	ArcNode *firstIn;
	//指向顶点相关的第一条出边
	ArcNode *firstOut;
}VNode;

40.图的邻接多重表结构体

//此代码考的极少
//边结点
typedef struct ArcNode
{
	//起点下标
	int vi;
	//指向与vi相关的下一个边结点
	struct ArcNode *vinext;
	//终点下标
	int vj;
	//指向与vj相关的下一个边结点
	struct ArcNode *vjnext;
	
}ArcNode;

//顶点结点
typedef struct 
{
	//顶点所存的数据
	int data;
	//指向顶点相关的第一条边
	ArcNode *first;
}VNode;
  1. 图的深度优先遍历代码
//v初值为0,用来指向visit数组中的某一个元素
//v的值也是遍历顶点数组的当前顶点的下标
//G:图
//visit数组是一个全局变量
void DFS(int v,AGraph *G)
{
 	//第一次不需要判断是否访问过,直接访问顶点
	visit[v] = 1;
	Visit(v);
	//取v所指的顶点的第一条边
	ArcNode *q = G->adjList[v].first;
	//开始访问v所指顶点的所有的边结点
	while(q != NULL)
	{
		//以q的邻接点为起点执行递归遍历
		//判断q的邻接点是否被访问过
		if(visit[q->adjV] == 0)
			DFS(q->adjV,G);
		q = q->next;
	}
}
  1. 图的广度优先遍历代码
//G为图
//这里的visit数组作为参数传递进来
//v初值为0,用来指向visit数组中的某一个元素
//v的值也是遍历顶点数组的当前顶点的下标
void BFS(AGraph *G, int v, int visit[maxSize])
{
	ArcNode *p;
	int que[maxSize],front = 0, rear = 0;
	int j;
	//访问顶点
	Visit(v);
	visit[v] = 1;
	//顶点的下标入队
	rear = (rear + 1)%maxSize;
	que[rear] = v;
	//开始遍历
	while(front != rear)
	{
		//出队一个顶点下标赋值给j
		front = (front + 1) % maxSize;
		j = que[front];
		//取顶点的第一条边
		p = G->adjList[j].first;
		//扫描顶点的所有的边,并且判断这些与边相连的另一端的顶点是否访问过
		//没有访问过的话则访问并将其入队
		while(p != NULL)
		{
			if(visit[p->adjV]) == 0)
			{
				Visit(p->adjV);
				visit[p->adjV] = 1;
				rear = (rear + 1) % maxSize;
				que[rear] = p->adjV;
			}
			p = p->next;
		}
	}
}
  1. Prim算法求最小生成树
//n:顶点的个数
//MGraph:二维数组表示的带权图、图的简单顺序存储结构
//v0:构造生成树的起始顶点、初值为0
//sum:存储生成树的最小代价,代价指各边的权值之和
void Prim(int n,float MGraph[][n],int v0, float &sum)
{
	//lowCost:当前生成树到图中其余顶点的边最小权值,下标代表相应顶点
	/* vSet:当数组某一位置上的值被设置为1的时候
	 ,代表其对应的顶点已经被并入生成树中了,下标代表相应顶点*/
	int lowCost[n],vSet[n];
	//v:指向当前刚并入的顶点
	//k:
	//min:
	int v,k,min;
	for(int i = 0;i < n; ++i)
	{
		//给lowCost赋初值,初值为起始顶点vo到其他顶点的权值,
		//根据二维数组能够得到
		lowCost[i] = MGraph[v0][i];
		//初始化vSet
		vSet[i] = 0;
	}
	//并入起始顶点
	v = v0;
	vSet[v] = 1;
	sum = 0;
	//循环n-1次,处理剩下的n-1个顶点
	for(int i = 0;i < n -1; ++i)
	{
		//INF:我们自定义的一个比图中所有的边都要大的多的值
		//代表无穷大
		min = INF;
		//扫描lowCost数组和vSet数组
		//找出与当前生成树相关的最小边
		//用min存储最小边的权值,用k指向与最小边相连的顶点
		for(int j = 0;j < n -1; ++j)
			if(vSet[j] == 0 && lowCost[j] < min)
			{
				min = lowCost[j];
				k = j;
			}
		//代表找到的最小边相连的顶点被并入生成树中
		vSet[k] = 1;
		//v指向刚并入的顶点
		v = k;
		//权值和
		sum += min;
		//由于并入了新的顶点,生成树到图中剩余顶点的边的权值可能会发生变化
		//所以要更新lowCost数组的值
		//更新的原则是lowCost数组存储当前生成树到图中其余顶点权值最小的边的权值
		for(int j = 0;j < n -1; ++j)
			//用新并入的顶点到图中剩余顶点的边的权值与lowCost数组进行比较
			//留下小的
			if(vSet[j] == 0 && MGraph[v][j] < lowCost[j])
				lowCost[j] = MGraph[v][j];
	}
}
  1. 克鲁斯卡尔算法求最小生成树代码
//road:存储图的边的数组 
//n:顶点个数
//e:边的个数
//权值和
void Kruskal(Road road[],int n,int e,int &sum)
{
	int a,b;
	sum = 0;
	//初始并查集数组
	//每一个顶点都是根结点
	for(int i = 0; i < n; ++i)
		v[i] = i;
	//将存储图的边的数组按照从小到大的顺序排序
	//这样从左到右扫描到的就是当前未被并入的最短的边
	sort(road,e);
	//生成树构建过程
	for(int i = 0; i < e; ++i)
	{
		//获得边的两端的顶点所在树的根结点
		a = getRoot(road[i].a);
		b = getRoot(road[i].b);
		//判断根结点是否相等,即是否属于同一棵树
		if(a != b)
		{
			//不属于则
			v[a] = b;
			sum += road[i].w;
		}
	}
}
  1. 迪杰斯特拉代码求最短路径
//n:图的顶点个数
//MGraph:存储图的边信息的二维数组
//v0:要求的最短路径的起始顶点
//dist:存最短路径的长度
//path:存最短路径	
void Dijkstra(int n, float MGraph[][n], int v0,int dist[],int path[])
{
	int set[maxSize];
	int min,v;
	for(int i = 0; i < n; i++)
	{
		//初始化dist数组和set数组
		dist[i] = MGraph[v0][i];
		set[i] = 0;
		//初始化path数组
		if(MGraph[v0][i] < INF)
			path[i] = v0;
		else 
			path[i] = -1;
	}
	//并入起始顶点
	set[v0] = 1;path[v0] = -1;
	//对剩下n-1个顶点进行处理
	for(int i = 0; i < n-1; i++)
	{
		//从当前的没有被并入的顶点中挑选出距离起点最近的一个顶点并入
		min = INF;
		for(int j = 0; j < n; j++)
			if(set[j] == 0 && dist[j] < min)
			{
				v = j;
				min = dist[j];
			}
		set[v] = 1;
		//核心操作,对dist和path数组的更新
		for(int j = 0; j < n; j++)
			if(set[j] == 0 && dist[v] + MGraph[v][j] < dist[j])
			{
				dist[j] = dist[v] + MGraph[v][j];
				path[j] = v;
			}
	}
}
  1. 弗洛伊德代码求最短路径
//n:图中顶点的个数
//MGraph:图的邻接矩阵存储
void Floyd(int n, float MGraph[][n], int Path[][n])
{
	
	int i,j,v;
	int A[n][n];
	//对A数组和Path数组进行初始化
	for (i = 0; i < n; ++i;)
		for(j = 0; j < n; ++j)
		{
			A[i][j] = MGraph[i][j];
			Path[i][j] = -1;
		}
	
	//三层循环,最外层是选出所有的顶点作为中间点
	for(v = 0; v < n; ++v)
		//内两层的作用是选出所有的顶点对
		//根据当前的中间点v进行检测,更新A数组和Path数组
		for(i = 0; i < n; ++i)
			for(j = 0; j < n; ++j)
				if(A[i][j] > A[i][v] + A[v][j])
					{
						A[i][j] = A[i][v] + A[v][j];
						Path[i][j] = v;
					}
}

执行查找最短路径代码

//u,v:代表要查找从顶点v到顶点u的最短路径
//
void printPath(int u, int v, int path[][max])
{
	if(path[u][v] == -1)
	直接输出
	else
	{
		int mid = path[u][v];
		printPath(u,mid,path);
		printPath(mid,v,path);
	}
}
  1. 拓扑排序代码
//图的顶点结构体
typedef struct
{
	//指示当前此顶点的入度
	int count;
	int data;
	ArcNode *first;
}VNode

//G:图
/*返回值int:进行拓扑排序的图必须是一个有向无环图,如果含环的话,拓扑排序
  进行到某一时刻必定会出现不含有入度为0的顶点,而顶点又没有输出完,使得不能
  继续下去,因此需要返回一个标记来判定拓扑是否真正完成了
  */
int TopSort(AGraph *G)
{
	//i,j:循环变量
	//n:用来统计当前已经输出的拓扑序列中顶点的个数
	int i,j,n = 0;
	//用来保存当前图中所有入度为0的顶点,只是一个容器,换成队列或数组都可
	int stack[maxSize],top = -1;
	//用来遍历顶点后边链表的辅助变量
	ArcNode *p;
	
	//假设顶点中的count域已经有值
	//将入度为0的顶点入栈
	for(i = 0; i <G->n; ++i)
		if(G->adjList[i].count == 0)
		stack[++top] = i;
	
	while(top != -1)
	{
		//出栈一个顶点,等效于将顶点从图中删去
		i = stack[top--];
		//记录取出的顶点的个数
		++n;
		//输出当前取出的顶点
		std::count<<i<<" ";
		
		//遍历出栈顶点的所有边,调整其邻接顶点的count值
		//相当于将与顶点相关的边删去
		p = G->adjList[i].first;
		while(p != NULL)
		{
			j = p->adjV;
			--(G->adjList[j].count);
			if(G->adjList[j].count == 0)
				stack[++top] = j;
			p = p->next;
		}
	}

	//返回成功标记
	if(n == G->n)
		return 1;
	else
		return 0;
}
  1. 逆拓扑排序代码
//v初值为0,用来指向visit数组中的某一个元素
//v的值也是遍历顶点数组的当前顶点的下标
//G:图
//visit数组是一个全局变量
void DFS(int v,AGraph *G)
{
 	//第一次不需要判断是否访问过,直接访问顶点
	visit[v] = 1;
	//取v所指的顶点的第一条边
	ArcNode *q = G->adjList[v].first;
	//开始访问v所指顶点的所有的边结点
	while(q != NULL)
	{
		//以q的邻接点为起点执行递归遍历
		//判断q的邻接点是否被访问过
		if(visit[q->adjV] == 0)
			DFS(q->adjV,G);
		q = q->next;
	}
	Visit(v);
}
  1. 直接插入排序代码
//arr:待排序的关键字
//n:待排序的关键字个数
void insertSort(int arr[],int n)
{
	//temp:存储待插入的关键字
	//i,j:循环遍历
	int temp,i,j;
	//循环从1开始,将数组的第一个元素认为是有序序列
	for(i = 1; i < n; i++)
	{
		//取未排序的第一个
		temp  = arr[i];
		//j指向有序序列中最右边的元素
		j = i - 1;
		//从有序序列右边开始往左扫描
		//当扫描到的关键字大于待插入的关键字时则这个关键字右移一位
		//然后指针j左移一位,直至j<0或者扫描到的关键字小于待插入的关键字
		while(j >= 0 && temp < arr[j])
		{
			arr[j+1] = arr[j];
			--j;
		}
		//将待插入的关键字插入到指针的后一位位置
		arr[j+1] = temp;
	}
}
  1. 简单选择排序代码
//arr:关键字 n:关键字个数
void selectSort(int arr[],int n)
{
	//辅助变量
	int i,j,k;
	int temp;
	//一共有n个关键字,循环n次
	for(i = 0; i < n; i++)
	{
		//k用来存储最小值在数组中的下标
		k = i;
		for(j = i+1; j < n; j++)
			if(arr[k] > arr[j]) k = j;
		//将无序序列中的最小值与无序序列的第一个关键字交换位置
		//无序序列的第一个关键字也就是当前i所指的关键字
		temp = arr[i];
		arr[i] = arr[k];
		arr[k] = temp;
	}
}
  1. 冒泡排序代码
void bubleSort(int arr[].int n)
{
	//辅助变量
	int i,j,flag;
	int temp;
	//i指示无序序列的范围
	for(i = n-1; i >= 1; i--)
	{
		flag = 0;
		//扫描当前的无序序列
		for(j = 1; j <= i; j++)
			//当j当前所指的关键字小于j所指前一个关键字,则交换位置
			if(arr[j-1] > arr[j])
			{
				temp = arr[j];
				arr[j] = arr[j-1];
				arr[j-1] = temp;	
				flag = 1;
			}
		//flag仍为0则证明在扫描无序序列的时候没有发生交换
		//函数结束,排序完成
		if( flag == 0) return;
	}
}
  1. 希尔排序代码
void shellSort(int arr[],int n)
{
	int temp;
	//gap:增量
	for(int gap = n/2;gap > 0; gap/=2)
	{
		/*i用来取出无序序列(gap及其后面的关键字)中的一个关键字
		然后将它插入到其所在子序列的有序序列的合适位置中*/
		for(int i = gap; i <n; i++)
		{
			//取出i所指向的关键字
			temp = arr[i];
			//对i所指的关键字所在的子序列进行直接插入排序
			int j;
			for(j = i; j >= gap && arr[j-gap] > temp; j-=gap)
				arr[j] = arr[j-gap];
			arr[j] = temp;
		}
	}
}
  1. 快速排序代码
//arr:待处理的序列
//low,high:当前处理的序列的范围,初始的时候low为0,high为关键字个数n-1
void quickSort(int arr[], int low, int high)
{
	//辅助变量
	int temp;
	//i,j分别指向序列的头和序列的尾
	int i = low, j = high;
	//递归出口,当序列的长度大于1的时候才经行递归
	//等于1的时候就不用进行递归了,因为已经有序了
	if(low < high)
	{
		//开始划分
		//将序列的第一个元素作为枢轴
		//具体操作可参照线性表划分
		//将这个序列划分为两部分,左边部分比枢轴小,右边部分比枢轴大
		temp = arr[low];
		//当i,j相等时本次划分结束
		while(i < j)
		{
			while(i < j && arr[j] >= temp) j--;
			if(i < j)
			{
				arr[i] = arr[j];
				i++;
			}
			while(i < j && arr[i] < temp) i++;
			if(i < j)
			{
				arr[j] = arr[i];
				j--;
			}
		}
		//将枢轴赋值给i、j指向的元素
		arr[i] = temp;
		//对划分出来的子序列利用同样的方法进行处理
		quickSort(arr,low,i-1);
		quickSort(arr,i+1,high);
	}
}
  1. 二路归并排序代码
//arr:存储所有待排关键字的数组
//我们规定,把从low到mid之间的关键字算作待归并一个子表,
//从mid+1到high之间的关键字算作待归并的另外一个子表
//要求从low到mid,mid+1到high这两个子表是有序的
//归并的结果就存储在从low到high的范围内
void merge(int arr[], int low, int mid, int high)
{
	//循环变量
	int i,j,k;
	//从low到mid之间关键字的个数
	int n1 = mid - low + 1;
	//从mid+1到high之间关键字的个数
	int n2 = high - mid;
	//将划分出来的数组暂存在这两个数组中,
	//然后由这两个数组归并成一个数组放回原数组low到high范围内
	int L[n1],R[n2];
	for(i = 0; i < n1; i++)
		L[i] = arr[low + i];
	for(j = 0; j < n2; j++)
		R[j] = arr[mid + 1 + j];
	
	//归并的关键过程
	//i、j分别指向数组L、R的第一个存储位置
	i = 0;
	j = 0;
	//k指向待排序列的第一个关键字
	k = low;
	//遍历L、R数组
	while(i < n1 && j < n2)
	{
		//比较数组L和R的元素,将小的复制到原来的数组中去
		//进行了复制的位置的指针要后移
		if(L[i] <= R[j])
			arr[k] = L[i++];
		else
			arr[k] = R[j++];
		k++;
	}
	while(i < n1)
		arr[k++] = L[i++];
	while(j < n2)
		arr[k++] = R[j++];
}

void mergeSort(int arr[], int low, int high)
{
	if(low < high)
	{
		int mid = (low + high) / 2;
		//在low到mid范围进行归并排序
		mergeSort(arr,low,mid);
		//在mid+1到high范围进行归并排序
		mergeSort(arr,mid+1,high);
		//把得到的左右两个有序序列进行归并操作
		merge(arr,low,mid,high);
	}
}

56.堆排序代码

//建堆中涉及到的调整过程,以及删除根节点后涉及的调整过程,调整为大顶堆
//arr:存储完全二叉树的数组
//low,high:可能需要被调整的节点的范围
void sift(int arr[], int low, int high)
{
	//i:本次需要调整的节点的下标
	//j:指向i所指的节点的左孩子节点
	int i = low, j = 2*i + 1;
	//存储当前要调整的节点的关键字的值
	int temp = arr[i];
	//当i所指节点有左孩子节点时才执行下面的操作
	while(j <= high)
	{
		/*j<high的意思就是i所指节点有左右孩子,
		在i所指节点有左右孩子的情况下,
		将j指向i所指的节点的左右孩子节点中关键字较大的那一个*/
		if(j < high && arr[j] < arr[j+1])
			++j;
		//如果i所指节点的关键字小于其孩子节点中较大的关键字,则交换它们位置
		if(temp < arr[j])
		{
			//将关键字较大的孩子节点的值赋值给i所指位置
			arr[i] = arr[j];
			//i移动到j的位置
			i = j;
			//j继续指向i所指节点的左孩子节点的位置
			j = 2*i + 1;
		}
		//如果i所指节点的关键字大于其孩子节点中较大的关键字,则跳出循环
		else
			break;
	}
	//最后将要调整的节点的关键字放到正确的位置上
	arr[i] = temp;
}

//堆排序的主函数
void heapSort(int arr[], int n)
{
	int i;
	int temp;
	//对堆中的所有非叶节点进行调整的过程,也就是一个建堆的过程,得到一个大顶堆
	for(i = n/2 - 1; i >= 0; i--)
	//arr:存储完全二叉树的数组
	//i:本次循环需要调整的非叶节点的下标
	//n-1:堆中最后一个节点的下标,
		sift(arr,i,n-1);

	//每次挑出当前堆中根节点,进行调整得到新堆
	//i从堆的最后一个位置开始,每次将根节点位置的关键字交换到i位置
	//也就是每次都将堆中最大的关键字放到数组后面
	for(i = n - 1; i > 0; i--)
	{
		//挑出根节点与堆的最后一个节点交换位置,也就是从堆中删除根节点
		temp = arr[0];
		arr[0] = arr[i];
		arr[i] = temp;
		//对新的根节点进行调整,得到新堆,注意调整的范围应该是新堆的范围
		sift(arr,0,i-1);
	}
}
  1. 顺序查找代码
int Search(int arr, int n, int key)
{
	int i;
	for(i=0; i<n; i++)
		return i;
	return -1;
}

LNode *Search(LNode *head,int key)
{
	LNode *p = head->next;
	while(p != NULL)
	{
		if(p->data == key)
			return p;
		p = p->next;
	}
	return NULL;
}
  1. 折半查找代码
int BSearch(int arr[], int low, int high, int key)
{
	while(low <= high)
	{
		int mid = (low + high)/2;
		if(arr[mid] == key)
			return mid;
		else if(arr[mid > key)
			high = mid - 1;
		else 
			low = mid + 1;
	}
	return -1;
}
  1. 二叉排序树查找代码
BTNode *BSTSearch(BTNode *p, int key)
{
	while(p != NULL)
	{
		if(key == p->key)
			return p;
		else if(key < p->key)
			p = p->lChild;
		else 
			p = p->rChild;
	}
	return NULL;
}
BTNode *BSTSearch(BTNode *p, int key)
{
	if(p == NULL)
		return NULL;
	else
	{
		if(p->key == key)
			return p;
		else if(key < p->key)
			return BSTSearch(p->lChild, key);
		else
			return BSTSearch(p->rChild,key);
	}
}
  1. 二叉排序树插入代码(建树代码)
//参数p用了指针引用型,原因是p可能找到一个空指针位置,需要对这个空指针做一些改变,也就是给它连接上我们要插入的节点
int BSTInsert(BTNode *&p, int key)
{	
	//p为空说明找到了插入的位置,直接构造一个节点,申请节点空间,填上待插入的关键字,把它挂在p指针位置即可。
	if(p == NULL)
	{
		//由于p定义的是引用型,所以p这个位置的空指针就是指针的本体,也就是说这个指针是所要插入的位置的父节点的左孩子指针或右孩子指针
		//做出的改变也是直接作用到左孩子指针或右孩子指针的
		p = (BTNode*)malloc(sizeof(BTNode));
		p>lChild = p->rChild = NULL;
		p->key = key;
		return 1;
	}
	else
	{
		//如果想插入的关键字已经存在于二叉排序树中,就没必要插入这个关键字了,返回插入失败标记
		if(key == p->key)
			return 0;
		else if(key < p->key)
			return BSTInsert(p->lChild,key);
		else
			return BSTInsert(p->rChild,key);
	}
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值