数据结构代码题合集

代码题合集

顺序表

顺序表递增有序,插入元素x,仍递增有序

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

/*
	顺序表递增有序,插入元素x,仍递增有序

	2 5 8 11 19       此时插入一个9 插入的9插入的是原来10的数组下标
	2 5 8 9  11 19

	1、找位置 i
	2、元素右移


*/

/*
	1 3 5 7 9     9 7 5 3 1 
	2 4 6 8       8 6 4 2
*/
int find(Sqlist L, int x)//参数为:传入顺序表 和 要插入的那个数字
{
	int i = 0;                                                     //要声明一下 不然for循环的局部变量会被释放掉
	//for (; i < L.length; ++i)
	//{
	//	if (x < L.data[i])
	//		break;
	//}
	//return i;
	for (int i = 0; i < L.length; i++)
	{
		if (L.data[i]<x)
		{
			continue;
		}
		else
		{
			return i;
		}
	}

}

void insert(Sqlist &L, int x)//元素后移操作 这里需要加入引用符号 参数为:顺序表 和 插入的位置
{
	int j, p;//定义两个变量 p为记录找到的插入的位置 j的初值为顺序表末尾的数的下标
	p = find(L, x);
	for (j = L.length - 1; j >= p; --j)//从插入的位置开始(包括插入前的位置)依次往后进行移动
	{
		L.data[j + 1] = L.data[j];

	}
	L.data[p] = x;//插入数据
	++(L.length); //更新顺序表的长度
}

void insert23(Sqlist &L, int x)
{
	int pos = L.data[0];
	for (int i = 0; i < L.length - 1; i++)
	{
		if (L.data[i] < x) {
			pos = i;
		}
	}
	pos += 1;
	for (int j = L.length-1; j >=pos; j--)
	{
		L.data[j + 1] = L.data[j];
	}
	L.data[pos] = x;
	++L.length;
}

void insert233(Sqlist &L, int x)
{
	
	int i;
	for (i = 0; i < L.length - 1; i++)
	{
		if (L.data[i]>x)
		{
			break;//break掉的值就是第一个不满足的值
		}
	}
	cout << "i=" << i;
	cout << endl;
	for (int j = L.length - 1; j >= i; j--)
	{
		L.data[j + 1] = L.data[j];
	}
	L.data[i] = x;
	++L.length;
}


int main01()
{
	Sqlist L = { {1, 3, 5, 8, 9}, 5 };//定义了一个顺序表 和 5这个数 这个数代表着长度
	insert233(L, 6);
	for (int j = 0; j < L.length; ++j)
	{
		cout << L.data[j] << endl;
	}

	cout << endl;
	
	cout << L.length;
	
	return EXIT_SUCCESS;
}

用顺序表最后一个元素覆盖整个顺序表中最小元素,并返回该最小元素

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

/*
	用顺序表最后一个元素覆盖整个顺序表中最小元素,并返回该最小元素

	1、找最小元素的位置
	2、用最后一个元素覆盖掉最小元素

	5  13  3   7  10
	5  13  10  7
*/

int Del_Min(Sqlist &L)
{
	int min = L.data[0];//初始化最小值
	int pos = 0;//初始化记录位置的值
	for (int i = 0; i < L.length; ++i)
	{
		if (L.data[i] < min)
		{
			min = L.data[i];
			pos = i;
		}
		L.data[pos] = L.data[L.length - 1];
		L.length--;
	}
	return min;
}

int main02()
{
	Sqlist L = { {5,13,3,7,10}, 5 };
	int min = Del_Min(L);
	for (int j = 0; j < L.length; ++j)
	{
		cout << L.data[j] << endl;
	}

	cout << endl;

	cout << "" << min << endl;
	return EXIT_SUCCESS;
}

将顺序表的元素逆置

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;
/*
	将顺序表的元素逆置

	4  7  16  3  9
	9  3  16  7  4

	4 7 16 3 9 1
	1 9 3 16 7 4
*/
void Reverse(Sqlist &L)
{
	int temp, i = 0, j = L.length - 1;
	int mid = (i + j) / 2;
	//int temp;
	while (i <= mid && j >= mid)
	{
		temp = L.data[i];
		L.data[i] = L.data[j];
		L.data[j] = temp;
		i++;
		j--;
	}
	//for (int i = 0, j = L.length - 1; i < L.length / 2 && j >= L.length / 2; ++i, --j)
	//{
	//	temp = L.data[i];
	//	L.data[i] = L.data[j];
	//	L.data[j] = temp;
	//}
}

int main03()
{
	Sqlist L = { {4,7,16,3,9,1}, 6 };
	Reverse(L);
	for (int j = 0; j < L.length; ++j)
	{
		cout << L.data[j] << endl;
	}
	return EXIT_SUCCESS;
}

将a1,a2,a3……am b1,b2,b3……bn转换成b1,b2,b3……bn a1,a2,a3……am

#include <iostream>
using namespace std;
/*
	将a1,a2,a3……am b1,b2,b3……bn转换成b1,b2,b3……bn a1,a2,a3……am

	1、将左边的一组逆置	    am……a3,a2,a1
	2、将右边的一组逆置                        bm……b3,b2,b1
	3、将a1到bn所有的元素逆置  bm……b3,b2,b1 am……a3,a2,a1

	1 2 3 4 5 6 7 8 9 10
	3 2 1 4 5 6 7 8 9 10
	3 2 1 10 9 8 7 6 5 4 
	4 5 6 7 8 9 10 1 2 3
*/
void Reverse(int A[], int m, int n)
{
	int mid = (m + n) / 2;
	for (int i = m, j = n; i <= mid; ++i, --j)
	{
		int temp = A[i];
		A[i] = A[j];
		A[j] = temp;
	}
}

void change(int A[], int m, int n)
{
	Reverse(A, 0, m - 1);//起始位置为0 中止位置为m-1
	Reverse(A, m, m + n - 1);//左半边的初始位置为m 末端为m+n-1
	Reverse(A, 0, m + n - 1);//右半边的初始位置为0 末端为m+n-1
}

int main04()
{
	int A[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	change(A, 3, 7);//参数为 数组名 左边元素的个数 右边元素的个数
	for (int i = 0; i < 10; ++i)
	{
		cout << A[i] << " ";
	}
	return EXIT_SUCCESS;
}

删除顺序表中所有值为x的元素

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

/*
	删除顺序表中所有值为x的元素

	可以把这题理解为保留所有不为x的元素
	12 3 5 8 9 3
	12 5 8 9 3 3  没更新length前
	12 5 8 9      更新length之后
*/
void del(Sqlist &L, int x)//删除顺序表中所有值为x的元素
{
	int k = 0;//这里的k是用来记录顺序表中所有值不为x的元素的个数
	for (int i = 0; i <= L.length - 1; ++i)
	{
		if (L.data[i] != x)
		{
			L.data[k] = L.data[i];//覆盖操作 k和i的初始值都是0
			++k;
		}
	}
	L.length = k;//更新length 保留了所有不为x的元素 相当于删除了值为x的元素
}

void Del(Sqlist &L, int x)
{
	int k = 0;//这里的k是用来记录顺序表中所有值为x的元素的个数
	for (int i = 0; i <= L.length - 1; ++i)
	{
		if (L.data[i] == x)
			++k;
		else
			L.data[i - k] = L.data[i];
	}
	L.length = L.length - k;
}

int main05()
{
	Sqlist L = { {12, 3, 5, 8, 9, 3}, 6 };
	del(L, 3);
	for (int j = 0; j < L.length; ++j)
		cout << L.data[j] << endl;
	
	return EXIT_SUCCESS;
}

从顺序表中删除给定值再s到t之间(包括s和t)的所有元素

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

/*
	从顺序表中删除给定值再s到t之间(包括s和t)的所有元素
	12 13 14 18 19 17
	12          19             删除13~18
*/

bool del(Sqlist &L, int s, int t)
{
	int  k = 0;//k是用来记数的
	if (L.length == 0 || s >= t)//错误的情况直接排除
		return false;
	for (int i = 0; i < L.length; ++i)
	{
		if (L.data[i] >= s && L.data[i] <= t)
			++k;
		else
			L.data[i - k] = L.data[i];
	}
	L.length -= k;//更新length
	return true;
}

int main06()
{
	Sqlist L = { {12, 13, 15, 18, 19}, 5 };
	del(L, 13, 19);
	for (int j = 0; j < L.length; ++j)
		cout << L.data[j] << endl;
	return EXIT_SUCCESS;
}

删除有序表中所有值重复的元素

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;
/*
	删除有序表中所有值重复的元素

	可以理解为保留第一个重复的元素

	5 5 6 7 7 9
	5 6 7 9
*/
bool del(Sqlist &L)
{
	int i, j;
	for (i = 0, j = 1; j < L.length; ++j)//j负责遍历整个顺序表 不满足下面的if循环时 j++
	{
		if (L.data[i] != L.data[j])
		{
			L.data[++i] = L.data[j];//满足if循环i++,j++
		}
		else
		{
			continue;
		}
	}
	L.length = i + 1;
	return true;
}

int main07()
{
	Sqlist L = { {12, 13, 13, 13, 19}, 5 };
	del(L);
	for (int j = 0; j < L.length; ++j)
		cout << L.data[j] << endl;
	return EXIT_SUCCESS;
}

删除有序表中所有值重复的元素

 #include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;
/*
	删除有序表中所有值重复的元素

	可以理解为保留第一个重复的元素

	5 5 6 7 7 9
	5 6 7 9
*/
bool del(Sqlist &L)
{
	int i, j;
	for (i = 0, j = 1; j < L.length; ++j)//j负责遍历整个顺序表 不满足下面的if循环时 j++
	{
		if (L.data[i] != L.data[j])
		{
			L.data[++i] = L.data[j];//满足if循环i++,j++
		}
		else
		{
			continue;
		}
	}
	L.length = i + 1;
	return true;
}

int main07()
{
	Sqlist L = { {12, 13, 13, 13, 19}, 5 };
	del(L);
	for (int j = 0; j < L.length; ++j)
		cout << L.data[j] << endl;
	return EXIT_SUCCESS;
}

将两个递增有序表 合并为 一个递增有序表

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

/*
	将两个递增有序表 合并为 一个递增有序表
	
	3 7 10 18 25
	4 9 13

	3 4 7 9 10 13 18 25
*/

bool merge(Sqlist A, Sqlist B, Sqlist &C)
{
	int i = 0, j = 0, k = 0;
	while (i < A.length && j < B.length)
	{
		if (A.data[i] < B.data[j])
			C.data[k++] = A.data[i++];
		else
			C.data[k++] = B.data[j++];
	}
	//一个走完了 另外一个没走完 有下面两种
	while (i < A.length)
		C.data[k++] = A.data[i++];
	while (j < B.length)
		C.data[k++] = B.data[j++];
	C.length = k;
	return true;
}

int main08()
{
	Sqlist A = { {2, 5, 9, 13, 19}, 5 };
	Sqlist B = { {1, 6, 7, 10}, 4 };
	Sqlist C;
	merge(A, B, C);
	for (int j = 0; j < C.length; ++j)
		cout << C.data[j] << endl;
	return EXIT_SUCCESS;
}

求两个递增序列的中位数

#include <iostream>
using namespace std;
#define maxsize 100
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

/*
	求两个递增序列的中位数
	3 5 7 10
	4 9 15 20

	3 4 5 7 9 10 15 20 

	8

	1、先合并这个两个递增序列
	2、求其中位数 
	3、若该递增序列为奇数 则返回最中间的即可 
	4、若该递增序列为偶数 则返回中间的左右两边的算数平均数
*/
int Find(Sqlist &A, Sqlist &B)
{
	int i, j, k;
	i = j = k = 0;
	Sqlist C;
	while (i < A.length && j < B.length)
		if (A.data[i] < B.data[j])
			C.data[k++] = A.data[i++];
		else
			C.data[k++] = B.data[j++];
	while (i < A.length)
		C.data[k++] = A.data[i++];
	while (j < B.length)
		C.data[k++] = B.data[j++];

	if (C.length % 2 != 0)
	{
		return C.data[(A.length + B.length - 1) / 2];
	}
	if (C.length % 2 == 0)
	{
		return (C.data[(A.length + B.length - 1) / 2] + C.data[(A.length + B.length - 1) / 2 + 1])/2;
	}
}//法一

/* 

int find(Sqlist &A, Sqlist &B)
{
	int a0 = 0, b0 = 0, am, bm, an = A.length - 1, bn = B.length - 1;
	while (a0 != an || b0 != bn)
	{
		am = (a0 + an) / 2;
		bm = (b0 + bn) / 2;
		if (A.data[am] == B.data[bm])
			return A.data[am];
		else if (A.data[am] < B.data[bm])
		{
			a0 = a0 + bn - bm;
			bn = bm;
		}
		else
		{
			b0 = b0 + an - am;
			an = am;
		}
	}
	if (A.data[a0] > B.data[b0])
		return B.data[b0];
	else
		return A.data[a0];
} //法二

*/

int main09()
{
	Sqlist A = { {3,5,7,10}, 4 };
	Sqlist B = { {4,9,15,20}, 4 };
	cout << Find(A, B) << endl;
	
	return EXIT_SUCCESS;
}

设计一个时间上尽可能高效的算法,找出数组中未出现的最小正整数

#include <iostream>
//#include<stdlib.h> malloc头文件
using namespace std;
/*
	设计一个时间上尽可能高效的算法,找出数组中未出现的最小正整数

	由题意得 时间上尽可能高效的算法,就要空间换时间
	数组A:    1 2 4 -6 10  
	数组B:    0 0 0 0  0     初始化
	数组B存储:1 1 0 1  0     找未出现的最小正整数 要满足1、正整数 2、未出现的 3、最小

	数组B不为0的索引+1表示数组A存在的数(索引理解为数组下标)
	第一个出现的0就是未出现的最小正整数

	如果数组A:1 2 3 4 5
	那么数组B:1 1 1 1 1
*/
int find(int A[], int n)//传入的数组和数组的长度
{
	int i;
	int *B = new int[n];
	//int *B = (int*)malloc(sizeof(int) * 10); C语言写法
	for (int k = 0; k < n; ++k)
	{
		B[k] = 0;
	}
	for (i = 0; i < n; ++i)
	{
		if (A[i] > 0 && A[i] <= n)//A[i]<=n代表大于数组长度的元素直接不考虑了 这里存的是这范围里面的正整数
		{
			B[A[i] - 1] = 1;
		}
	}
	for (i = 0; i < n; ++i)
	{
		if (B[i] == 0)
		{
			break;
		}
	}
	cout << "i=" << i;
	cout << endl;
	delete[] B;
	//free(B); C语言写法
	return i + 1;
}

int main10()
{
	//int A[5] = { 5, -2, 1, 4, 5 };
	int A[5] = {1,2,3,4,5 };
	cout << find(A, 5) << endl;

	return EXIT_SUCCESS;
}

若一个整数序列中有过半相同元素,则称其为主元素设计算法找出数组A(a0,a1……an - 1)的主元素。(其中0 < ai < n)若存在主元素则输出,否则返回 - 1

#include <iostream>
using namespace std;
/*
	若一个整数序列中有过半相同元素,则称其为主元素
	设计算法找出数组A(a0,a1……an - 1)的主元素。
	(其中0 < ai < n)若存在主元素则输出,否则返回 - 1

	A:2 3 3 6 3 5 3 3
	B:0 1 5 0 1 1 0 0
	3是主元素(5>8/2)

	1、空间换时间 堆区申请一个数组
	2、由于ai是小于n的 对于出现的数进行记数 出现一次+1
	3、返回这个主元素 数组下标+1就为该元素
*/

int fun(int A[], int n)//参数为数组 n为数组的长度
{
	int *B = new int[n];
	for (int i = 0; i < n; ++i) 
	{
		B[i] = 0;
	}

	int i, k, max = 0;//max是用来记录B数组中最大的那个数(即A数组中出现频率最高的那个数) k是用来记录数组下标的
	for (i = 0; i < n; ++i) 
	{
		if (A[i] > 0 && A[i] <= n) 
		{
			B[A[i] - 1]++;
		}
	}

	for (i = 0; i < n; ++i) 
	{
		if (B[i] > max)
		{
			max = B[i];
			k = i;
		}
	}
	delete[] B;

	if (max > n / 2)//过半的元素
		return k + 1;
	else
		return -1;
}

int main11()
{
	int A[8] = {2,3,3,6,3,5,3,3};
	cout << fun(A, 8) << endl;
	return EXIT_SUCCESS;
}

链表

头文件

单链表的头文件 linklist.h

#include <iostream>
using namespace std;
typedef struct LNode
{
	int data;
	struct LNode *next;
} LNode, *Linklist;


//不带头节点的链表
Linklist aaaa();
//带头节点的链表
Linklist bbbb();

循环单链表的头文件 circlesinglefun.h

#include <iostream>
using namespace std;
//循环单链表
typedef struct LNode
{
	int data;
	struct LNode *next;
} LNode, *Linklist;

Linklist dddd();

循环双链表的头文件 circledoublefun.h

#pragma once
#include <iostream>
using namespace std;
//循环双链表
typedef struct DNode
{
	int data;
	struct DNode *next, *prior;
} DNode, *Dinklist;

Dinklist cccc();

头文件的实现

#include"linklist.h"
//不带头节点的链表
Linklist aaaa()
{
	LNode *L = new LNode;
	int a;
	cin >> a;
	L->data = a;
	LNode *p = L; //声明一个指针指向头结点,
	//生成链表
	cin >> a;
	while (a != 0)//输入0为循环的结束条件
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = NULL;
	return L;
}

//带头节点的链表
Linklist bbbb()
{
	LNode *L = new LNode; //创建一个头结点
	LNode *p = L;         //声明一个指针指向头结点
	//生成链表
	int a;
	cin >> a;
	while (a != 0)
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = NULL;
	return L;
}

#include"circlesinglefun.h"
Linklist dddd()
{
	LNode *L = new LNode;
	LNode *p = L;
	int a;
	cin >> a;
	while (a != 0)
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = L;
	return L;
}
#include"circledoublefun.h"
Dinklist cccc() {
	DNode *L = new DNode;
	DNode *p = L;
	int a;
	cin >> a;
	while (a != 0)
	{
		DNode *q = new DNode;
		q->data = a;
		q->next = NULL;
		q->prior = p;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = L;
	L->prior = p;
	return L;
}

设计一个递归算法,删除不带头节点的单链表L中所有值为x的结点

#include <iostream>
using namespace std;
#include"linklist.h"
/*
	设计一个递归算法,删除不带头节点的单链表L中所有值为x的结点

	5 2 4 6 2 0   0为for循环结束的标志
	5 4 6
*/

void del_x(LNode *&L, int x)//删除操作 参数是链表和要删除的结点的值
{
	LNode *p;
	if (L == NULL)	return;
	if (L->data == x)
	{
		p = L;//记录位置
		L = L->next;//后移操作 进行第二轮递归的操作时候 L->next=L->next->next 
		free(p);
		del_x(L, x);
	}
	else
		del_x(L->next, x);//递归函数 这里是不会断链的 (将L->next带入上述的操作时候)
}

int main01()
{
	LNode *L = aaaa();
	del_x(L, 2);
	while (L != NULL)
	{
		cout << L->data << " ";
		L = L->next;
	}
	return EXIT_SUCCESS;
}
/*
为什么这段代码不会导致链表断链呢?因为在递归过程中,只有当满足条件(L->data == x)时,才进行删除操作,并在删除操作之后再次递归调用del_x(L, x),这样保证了删除节点后,将正确的下一个节点连接到当前节点,不会造成链表断链。而对于不满足条件的节点,直接通过递归调用del_x(L->next, x)进行下一个节点的处理,也不会引起链表断链
*/

删除带头节点单链表中所有值为x的结点

#include <iostream>
using namespace std;
#include"linklist.h"
/*
	删除带头节点单链表中所有值为x的结点

	删除结点的话 要知道链表的前一个结点才能删除
	
	  p
	头节点-->3-->4-->7-->4

	  p      q	  
	头节点-->3-->4-->7-->4

*/

//方法1
void del(LNode *&L, int x)
{
	LNode *p = L->next, *pre = L;//初始化 
	LNode *q;
	while (p != NULL)
	{
		if (p->data == x)
		{
			q = p;//用q来保存要删除元素的地址 进行删除操作 p是要用来后面进行遍历
			pre->next = p->next;
			p = p->next;//继续往后遍历
			free(q);
		}
		else
		{
			pre = p;
			p = p->next;
		}
	}
}

//方法2
void Del(LNode *&L, int x)
{
	LNode *p = L;
	while (p->next != NULL)
	{
		if (p->next->data == x)
		{
			LNode *q = p->next;
			p->next = q->next;
			free(q);
		}
		else
			p = p->next;
	}
}

int main02()
{
	LNode *L = bbbb();
	Del(L, 4);
	LNode *q = L->next;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return EXIT_SUCCESS;
}

删除带头结点单链表中第一个值为x的结点

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	删除带头结点单链表中第一个值为x的结点

	3 4 2 3 2 2 2 
	3 4 3 2 2 2 
*/

//方法1
int finddelete(LNode *&C, int x)
{
	LNode *p, *q;
	p = C;
	while (p->next != NULL)
	{
		if (p->next->data == x)
			break;
		//break语句执行后 此时的p保留到下一次的操作、
		//执行break语句后,栈区的数据不会被立即释放。在程序执行到break语句时,会跳出当前循环并继续执行循环之后的代码,但是栈上的数据仍然存在,并且可以在后续代码中继续访问
		else
			p = p->next;
	}

	if (p->next == NULL)//到底了
		return 0;
	else
	{
		q = p->next;
		p->next = q->next;
		free(q);
		return 1;
	}
}

//方法2
void finddelete2(LNode *&C, int x)
{
	LNode *p, *q;
	p = C;
	while (p->next != NULL) 
	{
		if (p->next->data == x)
		{
			q = p->next;
			p->next = q->next;
			free(q);
			return;
		}
		else
			p = p->next;
	}
	return;
}

int main03()
{
	LNode *L = bbbb();
	//finddelete(L, 2);
	finddelete2(L, 2);
	LNode *q = L->next;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

从尾到头反向输出每个单链表的值

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	从尾到头反向输出每个单链表的值

	递归
	思想:将除了第一个结点的结点反向输出,然后再输出第一个结点
	                                                                                                      弱智
	3 8 7 2
	2 7 8 3
*/

void print(LNode *L)
{
	if (L->next != NULL)
	{
		print(L->next);
	}
	cout << L->data << " ";
}

int main04()
{
	LNode *L = bbbb();
	print(L->next);//递归操作

	return EXIT_SUCCESS;
}

编写一个算法让单链表就地逆置

#include <iostream>
#include "linklist.h"
using namespace std;
  
/*
	编写一个算法让单链表就地逆置

	1、头插法
	2、三指针法 让链表的结点依次变为 第一个结点的next指向null 5-->3 2-->5 10-->2 最后头节点指向10

	L-->3-->5-->2-->10

	L-->10-->2-->5-->3
*/

//方法1 头插法
void reverse(LNode *&L)
{
	LNode *p = L->next, *r;//r是用来记录p之后的下一个结点
	L->next = NULL;//头节点的next指针指向null 用于进行头插
	while (p != NULL)
	{
		r = p->next;
		p->next = L->next;
		L->next = p;
		p = r;//头插法 执行完了之后p的next指针指向的是null,因此需要r指针来记录原来的链表的p的next指针域指向的结点
	}
}

//方法2 三指针
void Reverse(LNode *&L)
{
	LNode *p = L->next, *r = p->next;
	LNode *pre;//初始值是p的位置 是用来记录p的前一个结点 用于怕p->next=pre
	p->next = NULL;//将第一个结点的next指针域指向置为null 作为出口
	while (r != NULL)
	{
		pre = p;
		p = r;
		r = r->next;
		p->next = pre;
	}
	L->next = p;
}

int main05()
{
	LNode *L = bbbb();
	reverse(L);
	LNode *q = L->next;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

从链表中删除给定值在s到t之间的所有元素(不包括s和t)

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	从链表中删除给定值在s到t之间的所有元素(不包括s和t)
	3 6 19 8 7 10 5

	3 19 10 5

*/

void del(LNode *&L, int min, int max)
{
	LNode *p = L;
	while (p->next != NULL)
	{
		if (p->next->data > min && p->next->data < max)
		{
			LNode *u = p->next;//指针u 便于删除
			p->next = u->next;
			free(u);
		}
		else
			p = p->next;
	}
}

int main06()
{
	LNode *L = bbbb();
	del(L, 5, 10);
	LNode *q = L->next;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return EXIT_SUCCESS;
}

删除带头节点的单链表中最小值



/*

	删除带头节点的单链表中最小值

	L-->4 10 2 12 7

	L-->4 10 12 7

*/

#include <iostream>
#include "linklist.h"
using namespace std;

void del_min2(LNode *&L)
{
	LNode *p = L;
	LNode *minp = L;
	while (p->next != NULL)
	{
		//第一次是不满足这个条件的  p往后移动
		if (p->next->data < minp->next->data)
			minp = p;
		p = p->next;
	}
	LNode *u = minp->next;
	minp->next = u->next;
	free(u);
}

int main07()
{ 
	LNode *L = bbbb();
	del_min2(L);
	LNode *q = L->next;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

删除不带头节点的单链表中最小的元素

#include <iostream>
#include"linklist.h"
using namespace std;
/*
	删除不带头节点的单链表中最小的元素
*/
void del_min(LNode *&L)
{
	LNode *minp = L;
	LNode *p = L->next;
	while (p != NULL)
	{
		if (p->data < minp->data)
			minp = p;
		p = p->next;
	}
	if (L == minp)
	{
		L = L->next;
		free(minp);
		return;
	}
	p = L;
	while (p->next != minp)
		p = p->next;
	p->next = minp->next;
	free(minp);

}

int main08()
{
	LNode *L = aaaa();
	del_min(L);
	LNode *q = L;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

给定一个单链表,按递增排序输出的单链表中各结点的数据元素,并释放节点所占空间

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	给定一个单链表,按递增排序输出的单链表中各结点的数据元素,并释放节点所占空间

	1、依次找到这个单链表最小的元素 
	2、依次进行释放操作

	3 4 2 1 5
	1 2 3 4 5
*/
void del_min10086(LNode *&head)
{
	while (head->next != NULL)//循环条件 head后面为null时 循环结束
	{
		LNode *pre = head;
		LNode *p = head->next;
		while (p->next != NULL)
		{
			if (p->next->data < pre->next->data)
			{
				pre = p;
			}
			p = p->next;
		}
		cout << pre->next->data << " ";
		LNode *u = pre->next;//u记录最小的元素
		pre->next = u->next;
		free(u);
	}
	free(head);
}

int main09()
{
	LNode *L = bbbb();
	del_min10086(L);
	return EXIT_SUCCESS;
}

将一个带头节点的单链表A分解成两个带头节点的单链表A和B使A中含奇数位置元素,B中含偶数位置元素,且相对位置不变

/*
	堆区申请一个数组
	c语言 int *A=(int *)malloc(sizeof(int)*n)
	c++   int *A=new int[n]
*/


#include<iostream>
using namespace std;
#include"linklist.h"
/*
	奇偶链表 这里的奇偶是数组下标的奇偶

	将一个带头节点的单链表A分解成两个带头节点的单链表A和B
	使A中含奇数位置元素,B中含偶数位置元素,且相对位置不变

	L-->4-->10-->7-->6-->15

	A-->4-->7-->15

	B-->10-->6
*/

Linklist create1(LNode *&A)
{
	LNode *B = new LNode;//堆区申请一个结点
	//c语言写法 LNode *B = (LNode*)malloc(sizeof(LNode));
	B->next = NULL;//将新建立的结点的next域置空
	LNode *ra = A, *rb = B, *p = A->next;//p记录A的头节点的下一个结点
	A->next = NULL;
	while (p != NULL)
	{
		ra->next = p;
		ra = p;
		p = p->next;
		rb->next = p;
		rb = p;
		//p = p->next; err 奇数链表的时候 p最后指向的是null null是没有next域的
		//偶数链表的时候不需要这样写if
		if (p != NULL)
			p = p->next;
	}
	ra->next = NULL;//奇数链表的时候ra->next=null本来就是存在的 偶数链表的时候要进行说明
	return B;
}

int main10()
{
	LNode *A = bbbb();
	LNode *B = create1(A);
	LNode *q = A->next;
	LNode *p = B->next;
	cout << "A: ";
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	cout << endl;
	cout << "B: ";
	while (p != NULL)
	{
		cout << p->data << " ";
		p = p->next;
	}
	return EXIT_SUCCESS;
}

将一个单链表{a1,b1,a2,b2……an,bn}拆分成{a1,a2,……,an}和{bn,bn-1,……,b1}

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	将一个单链表{a1,b1,a2,b2……an,bn}拆分成{a1,a2,……,an}和{bn,bn-1,……,b1}
	由题意得这个单链表是偶数个
	拆分的第一个是奇链表,拆分的第二个是逆序的偶链表(用头插法来进行表示)
*/

Linklist create(LNode *&A)
{
	LNode *B = new LNode;
	B->next = NULL;
	LNode *ra = A, *p = A->next, *q;
	A->next = NULL;
	while (p != NULL)
	{
		ra->next = p;
		ra = p;
		p = p->next;
		q = p;
		if (q == NULL)//如果是奇数链表的时候加上这句话 偶数则不用加入 指向null的时候就不需要进行头插了
			break;//??
		p = p->next;
		q->next = B->next;
		B->next = q;
	}
	ra->next = NULL;//把A链表断开
	return B;
}

int main11()
{
	LNode *A = bbbb();
	LNode *B = create(A);
	LNode *q = A->next;
	LNode *p = B->next;
	cout << "A ";
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	cout << "B ";
	while (p != NULL)
	{
		cout << p->data << " ";
		p = p->next;
	}
	return 0;
}

删除递增链表中重复的元素 并且保留这些重复的元素的其中一个

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	删除递增链表中重复的元素  并且保留这些重复的元素的其中一个
	3 4 4 4 5 5
	3 4 5
*/
void del111(LNode *&L)
{
	LNode *p = L->next;//指向第一个有元素的位置
	//LNode *q;
	if (p == NULL)
		return;
	while (p->next != NULL)
	{
		LNode* q = p->next;//指向第二个有元素的位置 保持在p的后一个位置就好了
		if (p->data == q->data)
		{
			p->next = q->next;
			free(q);
		}
		else
			p = p->next;
	}
}

int main12()
{
	LNode *A = bbbb();
	del111(A);
	LNode *q = A->next;
	cout << "A ";
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return EXIT_SUCCESS;
}

两个递增有序的单链表, 设计算法成一个非递减有序的链表

#include <iostream>
#include "linklist.h"
using namespace std;

/*
	两个递增有序的单链表, 设计算法成一个非递减有序的链表

	A-->2-->5-->9-->13
	B-->4-->7
*/

void fun10(LNode *&A, LNode *&B)
{
	LNode *p = A->next, *q = B->next;
	LNode *ra = A;//假设A为合并之后的链表
	A->next = NULL;
	B->next = NULL;
	while (p != NULL && q != NULL)
	{
		if (p->data <= q->data)
		{
			ra->next = p;
			//ra = p;
			//p = p->next;
			p = p->next;
			ra = ra->next;
		}
		else
		{
			ra->next = q;
			q = q->next;
			ra = ra->next;
		}
	}
	//两个链表之间的长度可能会不相等
	if (p != NULL)
		ra->next = p;
	if (q != NULL)
		ra->next = q;
}

int main13()
{
	cout << "A:";
	LNode *A = bbbb();
	cout << "B:";
	LNode *B = bbbb();
	fun10(A, B);
	LNode *q = A->next;
	cout << "A+B:";
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return EXIT_SUCCESS;
}

两个递增有序的单链表 设计算法成一个非递增有序的链表

#include <iostream>
#include "linklist.h"
using namespace std;

/*
	两个递增有序的单链表 设计算法成一个非递增有序的链表

	头插法

	A--2--5--9--13
	B--4--7
*/

void fun23(LNode *&A, LNode *&B)
{
	LNode *p = A->next, *q = B->next, *s;
	A->next = NULL;
	B->next = NULL;
	while (p != NULL && q != NULL)
	{
		if (p->data <= q->data)
		{
			s = p;
			p = p->next;
			s->next = A->next;
			A->next = s;
		}
		else
		{
			s = q;
			q = q->next;
			s->next = A->next;
			A->next = s;
		}
	}
	while (p != NULL)
	{
		s = p;
		p = p->next;
		s->next = A->next;
		A->next = s;
	}
	while (q != NULL)
	{
		s = q;
		q = q->next;
		s->next = A->next;
		A->next = s;
	}
}

int main14()
{
	cout << "A:";
	LNode *A = bbbb();
	cout << "B:";
	LNode *B = bbbb();
	fun23(A, B);
	LNode *q = A->next;
	cout << "A:";
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

A, B两个单链表递增有序,从A,B中找出公共元素产生单链表C,要求不破环A,B结点

#include <iostream>
#include "linklist.h"
using namespace std;

/*
	A, B两个单链表递增有序,从A,B中找出公共元素产生单链表C,要求不破环A,B结点

	1 3 4 5
	3 4 5

	这题是要新建结点的 不需要free原来的结点
	3 4 5
*/

Linklist common(LNode *A, LNode *B)
{
	LNode *p = A->next;
	LNode *q = B->next;
	LNode *C = new LNode;//创一个头节点
	LNode *r = C;// , *s;
	while (p != NULL && q != NULL)
	{
		if (p->data < q->data)//p小p右移
			p = p->next;
		else if (p->data > q->data)//q小q右移
			q = q->next;
		else//相等的情况
		{
			LNode* s = new LNode;
			s->data = p->data;
			r->next = s;
			r = s;
			p = p->next;//继续往后找
			q = q->next;
		}
	}
	r->next = NULL;
	return C;//要返回头节点 因此需要定义r指针来指针C进行操作
}

int main15()
{
	cout << "A:";
	LNode *A = bbbb();
	cout << "B:";
	LNode *B = bbbb();
	LNode *C = common(A, B);
	LNode *q = C->next;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

A, B两个单链表递增有序,从A,B中找出公共元素并存放于A

#include <iostream>
#include "linklist.h"
/*
	A, B两个单链表递增有序,从A,B中找出公共元素并存放于A
	
	A 4 6 7 10 19
	B 3 4 7 9
	
	A 4 7
	
*/
using namespace std;

void Union(LNode *&A, LNode *&B)
{
	LNode *p = A->next;
	LNode *q = B->next;
	LNode *ra = A, *u;//ra时刻处于最后一个结点的位置
	while (p != NULL && q != NULL)
	{
		if (p->data < q->data)
		{
			u = p;
			p = p->next;
			free(u);
		}
		else if (p->data > q->data)
		{
			u = q;
			q = q->next;
			free(u);
		}
		else
		{
			ra->next = p;//连接
			ra = p;
			p = p->next;//后移进行比较
			u = q;
			q = q->next;
			free(u);
		}
	}
	while (p != NULL)
	{
		u = p;
		p = p->next;
		free(u);
	}
	while (q != NULL)
	{
		u = q;
		q = q->next;
		free(u);
	}
	ra->next = NULL;
	free(q);
}

int main16()
{
	cout << "A:";
	LNode *A = bbbb();
	cout << "B:";
	LNode *B = bbbb();
	Union(A, B);
	LNode *q = A->next;
	while (q != NULL)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

两个序列分别为A、B,将其存放到链表中, 判断B是否是A的连续子序列

#include <iostream>
#include "linklist.h"
using namespace std;

/*
	两个序列分别为A、B,将其存放到链表中, 判断B是否是A的连续子序列
	
	A 3 7 9 12
	B 7 9 12
	B是A的连续子序列 序列为7 9 12

	A 4 15 10 4 15
	B 4 15 1
	无子序列
*/

int seq(LNode *A, LNode *B)
{
	LNode *p = A->next;
	LNode *pre = p;//是用来进行匹配失败操作时所定义的指针 因为匹配失败更新p的位置 
	LNode *q = B->next;//初始匹配的位置
	while (p != NULL && q != NULL)
	{
		if (p->data == q->data)
		{
			p = p->next;
			q = q->next;
		}
		else
		{
			//方法二
			//p = p->next;

			pre = pre->next;//匹配失败后从下一个结点开始
			p = pre;//p移动到pre的位置
			q = B->next;//q从头开始匹配
		}
	}
	if (q == NULL)//匹配成功
		return 1;
	else
		return 0;
}

int main17()
{
	cout << "A:";
	LNode *A = bbbb();
	cout << "B:";
	LNode *B = bbbb();
	cout << "A:" << seq(A, B);
	return 0;
}

查找单链表中倒数第k个结点,若成功,则输出该节点的data,并返回1,否则返回0

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	查找单链表中倒数第k个结点,若成功,则输出该节点的data,并返回1,否则返回0
	1、双指针
	2、暴力解法

	4 10 6 8

*/

//法一标准解
int find(LNode *head, int k)
{
	LNode *q = head->next;
	LNode *p = head;
	int i = 1;//i用来记录p和q之间的距离 初始值为1
	while (q->next != NULL)
	{
		q = q->next;
		++i;
		//if (i >= k)//为了保证p和q之间的距离为k 距离为k时候 在同时后移的情况就能解决此题
		//	p = p->next;
	}
	while (i >= k) {//为了保证p和q之间的距离为k 距离为k时候 在同时后移的情况就能解决此题
		p = p->next;
		--i;
	}
	//while (q != head->next)
	//{
	//	p = p->next;
	//	q = q->next->next;
	//	++i;
	//}
	if (p == head)
		return 0;
	else
	{
		cout << "倒数第3个节点为:" << p->data << endl;
		return 1;
	}
}

//法二暴力解
//倒数第k个结点就是正数第n-k+1个结点
int len(LNode *L)
{
	LNode *p = L->next;
	int n = 0;
	while (p != NULL)
	{
		p = p->next;
		++n;
	}

	cout << "n=" << n << endl;
	//return n;//返回的是结点的个数
}

int Find(LNode *L, int k)
{
	int i = 0, m;
	m = len(L) - k + 1;
	if (m <= 0)
	{
		return 0;
	}
	while (i < m)//正数第几个 如果0<2 就往后移动两次 就是正数第二个
	{
		L = L->next;
		++i;
	}
	cout << L->data;
	return 1;
}

int main()
{
	LNode *L = bbbb();
	int j = find(L, 3);
	//len(L);
	cout << "j=" << j << endl;
	return 0;
}

用单链表保存m个整数,并且|data|≤n, 要求设计时间复杂度尽可能高效的算法 对于data绝对值相等的点,仅保留第―次出现的点

/*
	用单链表保存m个整数,并且|data|≤n, 要求设计时间复杂度尽可能高效的算法
	对于data绝对值相等的点,仅保留第―次出现的点
	


	4 -3 -4 2 -3

	空间换时间
	4 -3 2
*/
#include <iostream>
#include "linklist.h"
using namespace std;

void fun(LNode *&head, int n)
{
	LNode *p = head;
	LNode *r;
	int *q = new int[n + 1];
	int m;//存储数据
	for (int i = 0; i < n + 1; ++i)
		q[i] = 0;
	while (p->next != NULL)
	{
		if (p->next->data > 0)
			m = p->next->data;
		else
			m = -p->next->data;
		//在数组中记数 如果绝对值相等的数出现了记为1 如果又出现了则删除后面一个
		if (q[m] == 0)
		{
			q[m] = 1;
			p = p->next;
		}
		else
		{
			//删除操作
			r = p->next;
			p->next = r->next;
			free(r);
		}
	}
	free(q);
}

int main19()
{
	LNode *L = bbbb();
	fun(L, 50);
	L = L->next;
	while (L != NULL)
	{
		cout << L->data << " ";
		L = L->next;
	}
	return EXIT_SUCCESS;
}

判断带头结点的循环双链表是否对称

#include <iostream>
#include "circledoublefun.h"
using namespace std;
/*
	判断带头结点的循环双链表是否对称

	循环双链表:

	   -------------------------------------------------
	prev head next ---- prev data next ----  prev data next
	   -------------------------------------------------
*/
int fun(DNode *L)
{
	DNode *p = L->next;
	DNode *q = L->prior;
	while (p != q && q->next != p)//分奇数和偶数进行判断 条件
		if (p->data == q->data)//判断对称的条件
		{
			//p往后移动 q往前移动
			p = p->next;
			q = q->prior;
		}
		else
			return 0;
	return 1;
}

int main20()
{
	DNode *A = cccc();

	cout << fun(A) << endl;
	return 0;
}

有两个循环单链表,链表头指针分别为h1,h2,试编写函数将h2链表接到h1之后,要求链接后仍保持循环链表形式

#include <iostream>
#include "circlesinglefun.h"
using namespace std;

/*
	有两个循环单链表,链表头指针分别为h1,h2,试编写函数将h2链表接到h1之后,要求链接后仍保持循环链表形式

	head next---data next----data next 
	 -------------------------------
*/

void link(LNode *&h1, LNode *&h2)
{
	LNode *p, *q;
	p = h1, q = h2;
	//p q走到循环单链表最后一个结点
	while (p->next != h1)
		p = p->next;
	while (q->next != h2)
		q = q->next;
	p->next = h2;//连接
	q->next = h1;//循环
}

int main21()
{
	LNode *A = dddd();
	LNode *B = dddd();
	link(A, B);
	LNode *q = A->next;
	while (q != A)
	{
		cout << q->data << " ";
		q = q->next;
	}
	return 0;
}

设有一个带头结点的循环单链表,其结点值为正整数设计算法反复找出链表内最小值并不断输出,并将结点从链表中删除,直到链表为空,再删除表头结点

#include <iostream>
#include "circlesinglefun.h"
using namespace std;
/*
	设有一个带头结点的循环单链表,其结点值为正整数
	设计算法反复找出链表内最小值并不断输出,并将结点从链表中删除,直到链表为空,再删除表头结点

	L--2--4--7--1--3
	L--2--4--7--3               输出1
*/


void del(LNode *&L)
{
	LNode *p, *minp, *u;
	while (L->next != L)
	{
		p = L->next;
		minp = L;
		while (p->next != L)//循环结束的条件
		{
			if (p->next->data < minp->next->data)
				minp = p;
			p = p->next;
		}
		cout << "依次输出为:";
		cout << minp->next->data << endl;
		u = minp->next;
		minp->next = u->next;
		free(u);
	}
	free(L);
}

int main22()
{
	cout << "输入A链表:";
	LNode *A = dddd();
	del(A);
	return 0;
}

判断单链表是否有环

#include <iostream>
#include "linklist.h" 
using namespace std;

/*
	判断单链表是否有环 

	用快慢指针法
	快指针走两步 慢指针走一步 相遇就证明是有环的

*/
int findloop(LNode *L)
{
	LNode *fast = L, *slow = L;
	while (fast != NULL && fast->next != NULL)
	{
		slow = slow->next;
		fast = fast->next->next;
		if (slow == fast)
			return 1;
	}
	return 0;
}

int main23()
{
	LNode *L = bbbb();
	cout << "A:" << findloop(L);
	return 0;
}

给定一个单链表L(a1,a2,a3,……,an)将其重新排列为(a1,an,a2,an-1,……)

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	给定一个单链表L(a1,a2,a3,……,an)将其重新排列为(a1,an,a2,an-1,……)
	
	1 2 3 4 5
	1 5 2 4 3

	1 2 3 4 5 6
	1 6 2 5 3 4
*/

//中点之后的结点的操作
Linklist divrev(LNode *&L)
{
	//快慢指针找到链表的中点
	LNode *p = L, *q = L;
	while (q != NULL && q->next != NULL)//奇链表和偶链表结束的条件
	{
		p = p->next;
		q = q->next->next;
	}
	LNode *L1 = new LNode;
	L1->next = p->next;//新的结点连接到中点的后面的结点
	p->next = NULL;//将中点后的next指向NULL
	//中点之后的链表结点进行逆置操作 用头插法
	LNode *p1 = L1->next, *r;
	L1->next = NULL;
	while (p1 != NULL)//逆置的操作
	{
		r = p1->next;
		p1->next = L1->next;
		L1->next = p1;
		p1 = r;
	}
	return L1;
}

/*
	经过上一步操作后 所得到的链表中间以后的链表是逆置的
	运用奇偶链表的思想

	L--1--2--3--4--5--6
	
	L--1--2--3
	L1--6--5--4

	L--1--6--2--5--3--4
*/

void merge(LNode *&L)
{
	LNode *r, *s;
	LNode *L1 = divrev(L);
	LNode *p = L->next, *q = L1->next;
	L1->next = NULL;
	while (q != NULL)//奇数下面的链表短 偶数一样短 就让q!=NULL满足条件
	{
		r = p->next;
		s = q->next;
		p->next = q;
		q->next = r;
		p = r;
		q = s;
	}
}

int main24()
{
	LNode *L = bbbb();
	merge(L);
	L = L->next;
	while (L != NULL)
	{
		cout << L->data << " ";
		L = L->next;
	}
	return 0;
}

设一个带头结点的单链表L.数据元素为整数.其中大部分为正数,少数为负数。编写函教实现将负数结点移到表尾部,并返回调整后链表中第一个负数结点的位置。

#include<iostream>
#include"0_linklistfun.h"
using namespace std;
/*
	设一个带头结点的单链表L.数据元素为整数.其中大部分为正数,少数为负数。
	编写函教实现将负数结点移到表尾部,并返回调整后链表中第一个负数结点的位置。
	
	原链表:
	L  1  -3  6  -2  5
	调整后的链表:
	L  1  6  5  -3  -2

	1、先将值为负数的结点插入一个新的结点的后面
	2、然后进行尾插
*/

Linklist func(Linklist &L)
{
	Linklist B = (Linklist)malloc(sizeof(LNode));//创立一个新的头节点
	B->next = NULL;
	LNode *q = B;
	LNode *p = L->next;
	LNode *pre = L;
	while (p)
	{
		if (p->data < 0)
		{
			pre->next = p->next;
			p->next = NULL;
			q->next = p;
			q = p;
			p = pre->next;
		}
		if (p->data > 0)
		{
			p = p->next;
			pre = pre->next;
			//pre = p;
			//p = p->next;
		}
		pre->next = B->next;
		free(B);
		return pre->next;//pre->next指向的是第一个负数
	}

}

int main03()
{
	Linklist L = bbbb();  // 创建带头结点的单链表L

	Linklist first_negative = func(L);  // 调用func函数进行负数节点的调整

	cout << "第一个负数结点的位置: " << first_negative << endl;  // 打印第一个负数节点的数据值

	return 0;
}

已知f为单链表的表头指针, 链表中存储的都是整型数据.写出实现下列运算的递归算法

/*
	已知f为单链表的表头指针, 链表中存储的都是整型数据.写出实现下列运算的递归算法
	求⑴链表中最大整数; (2〉所有整数的平均值。
*/

#include<iostream>
#include"0_linklistfun.h"
using namespace std;

//如果用带头结点的单链表 加一句LinkList fnew=f->next  传入参数时用fnew就行

//不带头节点的单链表
int Max(Linklist f)
{   
	//这个链表中只有一个元素
	if (f->next==NULL)
		return f->data;
	return f->data >= Max(f->next) ? f->data : Max(f->next);
}

int func(Linklist f)
{
	int res = 0;
	if (f!=NULL)
	{
		f = f->next;
		res += 1;
	}
	return res;
}

double Average(Linklist f,int n)//n为链表的长度
{
	if (f->next == NULL)
		return f->data;
	return	(f->data + Average(f->next, n - 1)*(n - 1)) / n;
}

int main()
{
	Linklist L = bbbb();
	func(L);
	Average(L, 5);
	return EXIT_SUCCESS;
}

栈和队列

头文件

链表的头文件 0_linklist.h

#include <iostream>
using namespace std;
typedef struct LNode
{
	int data;
	struct LNode *next;
} LNode, *Linklist;


//不带头节点的链表
Linklist aaaa();
//带头节点的链表
Linklist bbbb();

队列的头文件 0_queue.h

#include <iostream>
using namespace std;

#define maxsize 50
typedef struct
{
	int data[maxsize];
	int front, rear;
} queue;

//初始化
void init(queue &q);
bool enqueue(queue &q, int x);
int dequeue(queue &q);

栈的头文件 0_stack.h

#include <iostream>
using namespace std;
#define maxsize 50

typedef struct
{
	char data[maxsize];
	int top;
} stack;

//初始化
void Init(stack &s);

bool push(stack &s, int x);

int pop(stack &s);

共享栈的头文件 0_stack[].h

#include <iostream>
using namespace std;
#define maxsize 50
//共享栈
typedef struct
{
	int data[maxsize];
	int top[2];
} stack1;

头文件的实现

#include"0_linklist.h"
//不带头节点的链表
Linklist aaaa()
{
	LNode *L = new LNode;
	int a;
	cin >> a;
	L->data = a;
	LNode *p = L; //声明一个指针指向头结点,
	//生成链表
	cin >> a;
	while (a != 0)//输入0为循环的结束条件
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = NULL;
	return L;
}

//带头节点的链表
Linklist bbbb()
{
	LNode *L = new LNode; //创建一个头结点
	LNode *p = L;         //声明一个指针指向头结点
	//生成链表
	int a;
	cin >> a;
	while (a != 0)
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = NULL;
	return L;
}

#include"0_queue.h"
//初始化
void init(queue &q)
{
	q.rear = q.front = 0;
}
bool enqueue(queue &q, int x)
{
	//队列满的条件
	if ((q.rear + 1) % maxsize == q.front)
		return false;
	//先插入元素 再更新指针的位置
	q.data[q.rear] = x;
	q.rear = (q.rear + 1) % maxsize;
	return true;
}
int dequeue(queue &q)
{
	//队列空的条件
	if (q.rear == q.front)
		return -100;
	//先把元素保存 再移动指针
	int x = q.data[q.front];
	q.front = (q.front + 1) % maxsize;
	return x;
}
#include"0_stack.h"
//初始化
void Init(stack &s)
{
	s.top = -1;
}

bool push(stack &s, int x)
{
	if (s.top == maxsize - 1)
		return false;
	//先移动指针 再插入元素
	s.data[++s.top] = x;
	return true;
}

int pop(stack &s)
{
	if (s.top == -1)
		return false;
	//先返回元素 再移动指针
	return s.data[s.top--];
}

Q是一个队列,S是一个空栈,编写算法使得队列中元素逆置

void reverse(stack &s, queue &q)
{
	while (q.front != q.rear)//队列不为空时
		push(s, dequeue(q));//出队 入栈
	while (s.top != -1)//栈不为空时
		enqueue(q, pop(s));//出栈 入队
}

int main01()
{
	stack s;
	Init(s);
	queue q;
	init(q);
	int x;
	cin >> x;
	while (x != -1)
	{
		enqueue(q, x);
		cin >> x;
	}
	reverse(s, q);
	while (q.front != q.rear)
	{
		cout << q.data[q.front] << " ";
		q.front = (q.front + 1) % maxsize;
	}
	return EXIT_SUCCESS;
}

判断单链表的全部n个字符是否中心对称 用栈来实现

#include <iostream>
#include"0_queue.h"
#include"0_stack.h"
#include"0_linklist.h"
using namespace std;

/*
	判断单链表的全部n个字符是否中心对称 用栈来实现
	1 2 2 1
	1 2入栈 2 1出栈 与2 1比较

	1 2 3 2 1
	1 2入栈 3不管 2 1 出栈 与2 1比较
*/

int fun(LNode *L)
{
	int n = 0, j;//n是统计链表中元素的个数
	stack s;
	Init(s);//初始化栈
	LNode *p = L->next;
	//统计元素个数
	while (p != NULL)
	{
		++n;
		p = p->next;
	}
	//把p移动到第一个元素
	p = L->next;
	//把左边的元素放入栈中
	for (j = 0; j < n / 2; ++j)
	{
		push(s, p->data);
		p = p->next;//此时p移动到右边的第一个结点
	}
	//如果是奇数的话还要后移一位 因为此时的p指向的是中心的位置 不需要进行比较
	if (n % 2 != 0)
		p = p->next;
	while (p != NULL)
	{
		if (pop(s) == p->data)
			p = p->next;
		else
			return 0;
	}
	return 1;
}

int main02()
{
	stack s;
	LNode *L = bbbb();
	cout << fun(L) << endl;
	return EXIT_SUCCESS;
}

两个栈s1,s2都采用顺序存储,并共享一个存储区[0…,maxsize-1]。采用栈顶相向,迎面增长的存储方式,设计s1,s2入栈和出栈的操作。

#include <iostream>
#include "0_stack[].h"
using namespace std;
/*
	两个栈s1,s2都采用顺序存储,并共享一个存储区[0...,maxsize-1]。
	采用栈顶相向,迎面增长的存储方式,设计s1,s2入栈和出栈的操作。
	
	typedef struct
	{
		int data[maxsize];
		int top[2];
	} stack1;

*/

//共享栈的初始化
void Init(stack1 &s)
{
	//顺序存储
	s.top[0] = -1;
	s.top[1] = maxsize;
}

//x为入栈的元素 i表示0、1共享栈的两边进行操作的 x是插入的元素
bool push(stack1 &s, int i, int x)
{
	//非法数据
	if (i < 0 || i > 1)
		return false;
	//共享栈满了
	if (s.top[1] - s.top[0] == 1)
		return false;
	switch (i)
	{
	case 0:
		s.data[++s.top[0]] = x;
		break;
	case 1:
		s.data[--s.top[1]] = x;
		break;
	}
	return true;
}

int pop(stack1 &s, int i)
{
	//非法数据
	if (i < 0 || i > 1)
		return -1;
	switch (i)
	{
	case 0:
		if (s.top[0] == -1)
			return -1;
		else
			return s.data[s.top[0]--];
		break;
	case 1:
		if (s.top[1] == maxsize)
			return -1;
		else
			return s.data[s.top[1]++];
		break;
	}
	//return 0;
}

int main03()
{
	stack1 s;
	Init(s);
	push(s, 0, 15);
	push(s, 0, 13);
	push(s, 1, 10);
	pop(s, 0);
	cout << s.data[s.top[0]];
	return EXIT_SUCCESS;
}

判断一个表达式中括号是否配对(假设只包含圆括号)

#include <iostream>
#include"0_stack.h"
using namespace std;

/*
	判断一个表达式中括号是否配对(假设只包含圆括号)

	1、遍历整个字符串 遇到左括号入栈
*/

bool fun(stack &s, string str)
{
	int i = 0;
	while (str[i] != '\0')
	{
		switch (str[i])
		{
		case '(':
			push(s, '(');
			break;
		case '{':
			push(s, '{');
			break;
		case ')':
			//栈顶为(匹配成功 栈顶不为(则匹配失败
			if (pop(s) != '(')//如果不成立则进行了出栈操作
				return false;
			break;
		case '}':
			if (pop(s) != '{')
				return false;
			break;
		default:
			break;
		}
		++i;//数组下标后移
	}
	if (s.top == -1)
		return true;
	else
		return false;
}

int main04()
{
	stack s;
	Init(s);
	string S = "(15+()))";
	//string S = "(({{(1212})}))";err
	cout << "结果为:";
	bool q = fun(s, S);
	if (q == true)
		cout << "括号匹配!" << endl;
	else
		cout << "括号不匹配!" << endl;
	return EXIT_SUCCESS;
}

假设一个序列为HSSHHHS,运用栈的知识,编写算法将S全部提到H之前,即为SSSHHHH

#include <iostream>
#include "0_stack.h"
using namespace std;
/*
	假设一个序列为HSSHHHS,运用栈的知识,编写算法将S全部提到H之前,即为SSSHHHH

	1、定义一个字符串 如果遍历到H的时候入栈 
	2、如果遍历到S就加入定义的字符串中 进行覆盖操作
	3、定义的字符串就是SSS 进行出栈操作把HHHH放入其后就可以了
*/
void fun(string S) 
{
	stack s;
	Init(s);
	string newS = "0000000";
	int i = 0, j = 0;
	while (S[i] != '\0')
	{
		if (S[i] == 'H')
			push(s, S[i++]);
		else
			newS[j++] = S[i++];
	}
	while (s.top != -1)
		newS[j++] = pop(s);
	i = 0;
	while (newS[i] != '\0')
		cout << newS[i++];
}

int main05()
{
	string S = "HSSHHHS";
	fun(S);
	return EXIT_SUCCESS;
}

利用栈实现递归函数的非递归算法

#include <iostream>
using namespace std;
#define maxsize 50
/*
	利用栈实现递归函数的非递归算法
	利用一个栈实现以下递归函数的非递归计算:
	
	     =  1                          n=0
	Pn(x)=  2x                         n=1
	     =  2xPn-1(x)-2(n-1)Pn-2(x)   n>1


	栈存的是表达式top指针的0对应n
			      top指针的n对应0
*/

/*
	top     n

	7		0
	6		1
	5		2
	4		3
	3		4
	2		5
	1		6
	0		7
*/


double fun2(int n, double x) {
	int top = n - 2;//top的初始值为n-2   用于后面的中止条件
	double *p = new double[n];//动态数组的申请
	double fv1 = 1;
	double fv2 = 2 * x;
	n = 2;//设n=2初值 非递归算法循环进行递归函数
	while (top > -1)
	{
		p[top] = 2 * x * fv2 - 2 * (n - 1) * fv1;
		fv1 = fv2;
		fv2 = p[top];
		++n;
		top--;//top--进行下一次的递归
	}

	delete[] p;

	if (n == 0)
		return fv1;
	return fv2;
}
int main06()
{
	int n = 2;
	cout << fun2(n, 5);
	return EXIT_SUCCESS;
}

头文件

二叉树的头文件

文件名:0_BiTreefun.h

#include <iostream>
using namespace std;
#define maxsize 50
typedef struct CBNode
{
	char data;
	struct CBNode *lchild, *rchild;
} CBNode, *CBTree;

带有父亲指针的二叉树的头文件

#include <iostream>
using namespace std;
typedef struct BTNode
{
	char data;
	struct BTNode *lchild, *rchild, *parent;
} BTNode, *BiTree;

void aaaa(BTNode *&T, BTNode *p);

第一个头文件的实现

#include"0_BiTreefun.h"
/*
	输入:1 2 # # 3 # #
	树为:

				1
		2				3
	#		#		#		#

	输入:1 2 3 # # # #
	树为:
			
				1
		2				#			
	3		#
#		#

*/

BiTree aaaa()
{
	char x;
	cin >> x;
	if (x !='#')
	{
		BTNode *T = new BTNode;
		T->data = x;
		T->lchild = aaaa();
		T->rchild = aaaa();
		return T;
	}
	return NULL;
}

计算二叉树所有结点个数

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	计算二叉树所有结点个数
*/
int count(BTNode *p)
{
	int n1, n2;
	if (p == NULL)
		return 0;
	else
	{
		n1 = count(p->lchild);    
		n2 = count(p->rchild);
		return n1 + n2 + 1;
	}
}

//访问一次n++ n是用来记录访问的次数
//这是对于先序遍历的记数
void count2(BTNode *p, int &n)
{
	if (p != NULL)
	{
		++n;
		count2(p->lchild, n);
		count2(p->rchild, n);
	}
}

int main01()
{
	BTNode *T = aaaa();

	int n = count(T);
	/*
	int n = 0;//初始化是用来记数的
	count2(T, n);
	*/
	cout << "二叉树的结点的个数为:" << n << endl;
	return EXIT_SUCCESS;
}

计算二叉树所有的叶子结点

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;

/*
	计算二叉树所有的叶子结点
*/

int countleaf(BTNode *p)
{
	int n1, n2;
	if (p == NULL)
		return 0;
	else if (p->lchild == NULL && p->rchild == NULL)
		return 1;
	else
	{
		n1 = countleaf(p->lchild);
		n2 = countleaf(p->rchild);
		return n1 + n2;//这里不需要加一
	}
}

void countleaf2222(BTNode *p, int &n)
{
	if (p != NULL)
	{
		//叶子结点的条件 左孩子和右孩子为空时 进行记数
		if (p->lchild == NULL && p->rchild == NULL)
			++n;
		countleaf2222(p->lchild, n);
		countleaf2222(p->rchild, n);
	}
}

int main02()
{
	BTNode *T = aaaa();
	//int n = countleaf(T);
	 int n = 0;
	 countleaf2222(T, n);
	cout << "二叉树叶子结点的个数为:" << n << endl;
	return EXIT_SUCCESS;
}

二叉树双分支结点的个数

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	二叉树双分支结点的个数

	双分支结点就是度为2的结点

		A

	B		C

D		E	F             AB是双分支结点  C不是双分支结点

*/
int countdoublebranch(BTNode *p)
{
	int n1, n2;
	if (p == NULL)
		return 0;
	//左孩子和右孩子都存在的时   记数
	if (p->lchild && p->rchild)
	{
		n1 = countdoublebranch(p->lchild);
		n2 = countdoublebranch(p->rchild);
		return n1 + n2 + 1;
	}
	else
	{
		n1 = countdoublebranch(p->lchild);
		n2 = countdoublebranch(p->rchild);
		return n1 + n2;
	}
}
void countleaf2(BTNode *p, int &n)
{
	if (p != NULL)
	{
		//叶子结点的条件 左孩子和右孩子为空时 进行记数
		if (p->lchild && p->rchild )
			++n;
		countleaf2(p->lchild, n);
		countleaf2(p->rchild, n);
	}
}
int main03()
{
	int n = 0;
	BTNode *T = aaaa();
	//cout << "二叉树所有双分支结点的个数为:" << countdoublebranch(T);
	countleaf2(T, n);
	cout << "二叉树所有双分支结点的个数为:" << n;
	return 0;
}

计算二叉树的深度

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	计算二叉树的深度   深度是从上往下数 总共有几层

			1
		
		2		5

	3		4

	假设此时p指针指向的是2   
	p结点第一次离开的时候指向的是3     深度+1
	p结点第二次离开的时候指向的是4     深度在上次的操作之后已经加过了  因此不需要进行操作
	p结点第三次访问的时候又指回2了     深度--n 
*/
int getDepth(BTNode *p)//不推荐
{
	int LD, RD;
	if (p == NULL)
		return 0;
	else
	{
		LD = getDepth(p->lchild);
		RD = getDepth(p->rchild);
		return (LD > RD ? LD : RD) + 1;
	}
}

/*
	if(p!=NULL)
	{
		…………//第一次离开p结点所要做的事情
		递归p的左子树
		…………//第二次离开p结点所要做的事情
		递归p的右子树
		…………//第三次访问p结点之前做的事情
	}
*/

void getDepth2(BTNode *p, int &n, int &max)//n表示的是深度
{
	if (p != NULL)
	{
		++n;
		if (n >= max)
			max = n;
		getDepth2(p->lchild, n, max);
		getDepth2(p->rchild, n, max);
		--n;//第三次访问p结点所要做的事情
	}
}

int main04()
{
	BTNode *T1 = aaaa();
	//int n = getDepth(T1);
	int n = 0, max = 1;
	getDepth2(T1, n, max);
	//cout << "二叉树的深度为:" << n << endl;
	cout << "二叉树的深度为:" << max << endl;
	return 0;
}

(a-(b+c))*(d/e)存储在二叉树,遍历求值

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	(a-(b+c))*(d/e)存储在二叉树,遍历求值


	实际上是中序遍历的结果
						*
				
				-				/
			
			a		+		d		e
				
				  b	   c

	实际上运算的式子是有规律的
	
	叶子结点是值 双分支结点为符号 没有单分支结点
*/
int op(char A, char B, char C)
{
	switch (C) {
	case '+':
		return A + B;
		break;
	case '-':
		return A - B;
		break;
	case '*':
		return A * B;
		break;
	case '/':
		return A / B;
		break;
	default:
		break;
	}
	return -100;
}

int comp(BTNode *p)
{
	int A, B;
	if (p == NULL)
		return 0;
	if (p != NULL)
	{
		//如果是双分支结点的情况下
		if (p->lchild != NULL && p->rchild != NULL)
		{
			A = comp(p->lchild);
			B = comp(p->rchild);
			return op(A, B, p->data); //op函数定义为两个值的运算结果
		}
		else
		//如果是叶子结点的情况下 直接返回叶子结点的值
			return p->data-'0';
	}
}

//如果是根结点的话不用加() deep > 1
void func(BTNode *p, int deep) {
	if (p != NULL) {
		//如果结点是双分支结点加()
		if ((p->lchild&&p->rchild) && deep > 1)
			cout << '(';
		deep++;
		func(p->lchild, deep);
		cout << p->data;
		func(p->rchild, deep);
		deep--;
		if ((p->lchild&&p->rchild) && deep >1)
			cout << ')';
	}
}

int main05()
{
	BTNode *T = aaaa();
	int deep = 1;
	cout << "result1:";
	func(T, deep);
	cout << endl;
	int a = comp(T);
	cout << "result2:" << a << endl;
	return 0;
}

找出二叉树最大值的点

#include <iostream>
#include "0_BITreefun.h"
using namespace std; //填写元素值不要超过10,因为字符型
/*
	找出二叉树最大值的点
*/
void findMax(BTNode *p, char &max)
{
	if (p = NULL)
	{
		return;
	}
	if (p != NULL)
	{
		if (p->data > max)
			max = p->data;
		findMax(p->lchild, max);
		findMax(p->rchild, max);
	}
}
int main06()
{
	BTNode *T = aaaa();
	char max = '0';//初始化max的值
	findMax(T, max); //ASCII码的大小规则为0~9 < A~Z < a~z
	cout << "最大值为:" << max << endl;
	return EXIT_SUCCESS;
}

判断两个二叉树是否相似

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	判断两个二叉树是否相似(指都为空或者都只有一个根节点,或者左右子树都相似)

		1                4
	2       3		5         6     这两个二叉树是相似的

1##   2##   return 0
12### 2##   return 1

		1               2
	2      #        2		2
 #     #		 #     #  #    #  这两个二叉树是不相似的

*/
int fun(BTNode *T1, BTNode *T2)
{
	int left, right;//有1必须有0!!!有出口有结果!
	//如果两个二叉树都是NULL的  那么这两个二叉树是相似的
	if (T1 == NULL && T2 == NULL)
		return 1;
	//如果一个二叉树一个为NULL 一个二叉树不为NULL 则是不相似的
	if (T1 == NULL || T2 == NULL)
		return 0;
	//如果两个二叉树的结点都不为NULL 则向下递归
	else
	{
		left = fun(T1->lchild, T2->lchild);
		right = fun(T1->rchild, T2->rchild);
		return left && right;//返回1则相似  返回0则不相似
	}
}

int main07()
{
	BTNode *p = aaaa();
	BTNode *q = aaaa();
	cout << "两个树是否相似:" << fun(p, q) << endl;
	return EXIT_SUCCESS;
}

把二叉树的所有结点子树进行交换

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	把二叉树的所有结点子树进行交换
	1、先交换最底层的子树	
		3					3			    	   3

	 5     7			5		7	     	   7	   5

  1    2			2		1	     			    2      1	


	5					5

1		2		  2          1
    
*/
/*	
	2、先交换根节点的子树
	void swap2(BTNode *p)
{
	if (p != NULL)
	{		
		BTNode *temp = p->lchild;
		p->lchild = p->rchild;
		p->rchild = temp;
		swap2(p->lchild);
		swap2(p->rchild);
	}
}

*/

//先序遍历
void pre(BTNode *T)
{
	if (T != NULL)
	{
		cout << T->data << " ";
		pre(T->lchild);
		pre(T->rchild);
	}
}

//交换操作
//1、先交换最底层的子树

void swap1(BTNode *p)
{
	if (p != NULL)
	{
		swap1(p->lchild);
		swap1(p->rchild);
		BTNode *temp = p->lchild;
		p->lchild = p->rchild;
		p->rchild = temp;
	}
}

//void swapOddLevels(TreeNode* root, int level) {
//	if (root == nullptr) {
//		return;
//	}
//
//	if (level % 2 != 0) {
//		// 交换左右子树
//		TreeNode* temp = root->left;
//		root->left = root->right;
//		root->right = temp;
//	}
//
//	// 递归处理左右子树,层级加1
//	swapOddLevels(root->left, level + 1);
//	swapOddLevels(root->right, level + 1);
//}
int main08()
{
	BTNode *T = aaaa();
	cout << "原来的树:";
	pre(T);
	swap1(T);
	cout << endl
		<< "交换二叉树所有结点的子树后的树:";
	pre(T);
	return 0;
}

查找二叉树中data域等key的结点是否存在,若存在,将q指向它,否则q为空

#include <iostream>
#include"0_BiTreefun.h"
/*
	查找二叉树中data域等key的结点是否存在,若存在,将q指向它,否则q为空
*/
using namespace std;

void fun(BTNode *p, BTNode *&q, int key)
{
	if (p != NULL)
	{
		if (p->data == key)
			q = p;
		else
		{
			fun(p->lchild, q, key);
			fun(p->rchild, q, key);
		}
	}
}

int main09()
{
	BTNode *T = aaaa();
	BTNode *q = NULL;

	char key = '6';
	fun(T, q, key);
	if (q != NULL)
		cout << "key存在:" << q->data;
	else
		cout << "key不存在" << endl;
	return 0;
}

输出先序遍历第k个结点的值

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	输出先序遍历第k个结点的值
*/
void trave(BTNode *p, int k, int &n)//k是给定的数 n初始值为0
{
	if (p != NULL)
	{
		++n;
		if (k == n)
		{
			cout << p->data;
			return;
		}
		trave(p->lchild, k, n);
		trave(p->rchild, k, n);
	}
}

int main10()
{
	BTNode *T = aaaa();
	int k = 3, n = 0;
	cout << "值为:" << endl;
	trave(T, k, n);
	return 0;
}

求二叉树值为x的层号

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	求二叉树值为x的层号
*/
void fun(BTNode *p, char x, int L)//x是要查找的层号 L初始值为1表示层号
{
	if (p != NULL)
	{
		if (p->data == x)
			cout << "7所在的层数为:" << L << endl;
		fun(p->lchild, x, L + 1); //这里不可写L++
		fun(p->rchild, x, L + 1);
	}
}

void fun1(BTNode *p, char x, int L)
{
	if (p != NULL)
	{
		if (p->data == x)
			cout << "7所在的层数为:" << L;
		++L;
		fun1(p->lchild, x, L);
		fun1(p->rchild, x, L);
		--L;
	}
}

int main11()
{
	BTNode *T = aaaa();
	int L = 1;
	fun(T, '7', L);
	return 0;
}

树中元素为x的结点,删除以它为根的子树

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
	树中元素为x的结点,删除以它为根的子树
*/
void del23(BTNode *&bt, char key)
{
	if (bt != NULL)
	{
		if (bt->data == key)
		{
			bt = NULL;//将结点指向空 即删除根的子树 保留根结点
			return;
		}
		del23(bt->lchild, key);
		del23(bt->rchild, key);
		//return;
		//这个 return 语句并非必需,因为它只是在函数结束时返回控制权给调用者。由于没有进行任何删除操作,函数的行为等同于到达了函数的自然结束点,而 return 的作用就是提前结束函数的执行。因此,在这种情况下,最后一个 return 语句可以被省略,因为函数会自动返回。
	}
}

void pre111(BTNode *T)
{
	if (T != NULL)
	{
		cout << T->data << " ";
		pre111(T->lchild);
		pre111(T->rchild);
	}
}

int main12()
{
	BTNode *T = aaaa();
	del23(T, '5');
	pre111(T);
	return 0;
}

利用结点的右孩子指针将一个二叉树的叶子节点从左向右连接成一个单链表(head指向第一个,tail指向最后一个)

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	利用结点的右孩子指针将一个二叉树的叶子节点从左向右连接成一个单链表(head指向第一个,tail指向最后一个)

			1
		1     2
	4     3              输出:4 3 2
*/
void link(BTNode *p, BTNode *&head, BTNode *&tail)//head tail会变化
{
	if (p != NULL)
	{
		//如果是叶子结点的情况执行下面第一个if
		if (!p->lchild && !p->rchild)
		{
			if (head = NULL)
			{
				head = p;
				tail = p;
			}
			else
			{
				tail->rchild = p;
				tail = p;
			}
		}
		else {
			link(p->lchild, head, tail);
			link(p->rchild, head, tail);
		}
	}
}

int main13()
{
	BTNode *T = aaaa();
	BTNode *head = NULL, *tail = NULL;
	link(T, head, tail);
	while (head != NULL)
	{
		cout << head->data << " ";
		head = head->rchild;
	}
	return 0;
}

输出根节点到每个叶子节点的路径

#include <iostream>
#include "0_BiTreefun.h"
#define maxsize 50
using namespace std;
/*
	输出根节点到每个叶子节点的路径
				1
			2		3
		4     #    #   #
	#     #

	输出 124   13

	这里是树的二叉链表表示法
*/
void allpath(BTNode *p, char pathstack[], int top)//传入参数分别为树 栈 top
{
	if (p != NULL)
	{
		pathstack[top] = p->data;
		if (!p->lchild && !p->rchild) //叶子结点
		{
			for (int i = 0; i <= top; ++i)//从top[0]开始打印 即从根节点开始打印124  而不是421
				cout << pathstack[i] << " ";
			cout << endl;
		}
		allpath(p->lchild, pathstack, top + 1);
		allpath(p->rchild, pathstack, top + 1);
	}
}
int main14()
{
	int k = 0;
	int n = 4;
	while (n >= 1)
	{
		for (int i = 1; i <= n; ++i)
		{
			k += 1;
			n /= 2;
			cout << i << " ";
		}
	}

	return 0;
}

已知满二叉树先序序列存在于数组中,设计算法将其变成后序序列

#include <iostream>
using namespace std;
/*
	已知满二叉树先序序列存在于数组中,设计算法将其变成后序序列
		1
	
	2		3

  4  5	  6   7
	   L1    R1
  先序:1245367    根1 左子树245 右子树367

	   L2    R2
  后序:4526731    左子树452 右子树673 根1


  中序:4251637    左子树425 根1 右子树637

  先序序列转化为后序序列  
  把先序的第一个结点放入后序的最后一个结点 //因为先序序列的第一个是根节点

*/

/*
	 N     L R

	 L R	 N

*/
void change(char pre[], int L1, int R1, char post[], int L2, int R2)
{
	if (L1 <= R1 && L2 <= R2)
	{
		//将先序的第一个结点放入后序的最后一个结点
		post[R2] = pre[L1];
		//再对左子树进行递归
		change(pre, L1 + 1, (L1 + R1 + 1) / 2, post, L2, (L2 + R2 - 1) / 2);
		//对右子树进行递归
		change(pre, (L1 + R1 + 1) / 2 + 1, R1, post, (L2 + R2 - 1) / 2 + 1, R2 - 1);
	}
}//先->后

/*
	L R		N
	N	  L R
*/

void change1(char post[], int L1, int R1, char pre[], int L2, int R2)
{
	if (L1 <= R1 && L2 <= R2)
	{
		pre[L2] = post[R1];//后序的最后一个结点放入到前序的第一个结点
		change1(post, L1, (L1 + R1 - 1) / 2, pre, L2 + 1, (L2 + R2 + 1) / 2);
		change1(post, (L1 + R1 - 1) / 2 + 1, R1 - 1, pre, (L2 + R2 + 1) / 2 + 1, R2);
	}
}//后->先

/*
	
*/

void change2(char pre[], int L1, int R1, char mid[], int L2, int R2)
{
	if (L1 <= R1 && L2 <= R2)
	{
		mid[(L2 + R2) / 2] = pre[L1];
		change2(pre, L1 + 1, (L1 + R1 + 1) / 2, mid, L2, (L2 + R2) / 2 - 1);
		change2(pre, (L1 + R1 + 1) / 2 + 1, R1, mid, (L2 + R2 + 1) / 2 + 1, R2);
	}
}//先->中

 int main15()
 {
	char pre[8] = "abdecfg";
	char post[8] = "0000000";
   change(pre, 0, 6, post, 0, 6);
   int i = 0;
   while (post[i] != '\0')
   {
     cout << post[i];
     ++i;
   }
   return 0;
 }

先序与中序遍历分别存在两个一维数组A,B中,试着建立二叉链表

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	先序与中序遍历分别存在两个一维数组A,B中,试着建立二叉链表

	这里返回的是根节点
	先序序列1243   中序序列2413
	根据这两个序列构建的二叉树如下所示:
		1
	  
	 2     3

	   4 
*/
BiTree create(char A[], char B[], int L1, int R1, int L2, int R2)
{
	BTNode *root = new BTNode;
	root->data = A[L1];
	int i;
	//找中序序列的根结点所在的位置
	for (i = L2; B[i] != root->data; i++);
	//存储中序序列的数组 根节点的左边还存储数据 证明它是有左子树的
	if (i > L2)
		//由中序序列可知 左子树个数为i-L2 右子树个数为R2-i
		root->lchild = create(A, B, L1 + 1, L1 + i - L2, L2, i - 1);
	//不满足左子树有结点	
	else
		root->lchild = NULL;
	//根节点的右边存储数据 证明它是有右子树的
	if (i < R2)
		root->rchild = create(A, B, i - L2 + L1 + 1, R1, i + 1, R2);
	else
		root->rchild = NULL;
	return root;
}

void post(BTNode *T)
{
	if (T != NULL)
	{
		cout << T->data << " ";
		post(T->lchild);
		post(T->rchild);
	}
}

int main()
{
	char A[7] = "abcdef";
	char B[7] = "cbdaef";
	BTNode *T = create(A, B, 0, 6, 0, 6);
	post(T);
	return 0;
}

二叉树以顺序方式存在于数组A的中,设计算法以二叉链表表示

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	二叉树以顺序方式存在于数组A的中,设计算法以二叉链表表示
	123456
			1
		
		2		3

	  4	 5    6

假设根结点的索引为i  左子树的索引为2i+1 右子树的索引为2i+2

*/
BiTree create(char A[], int i, int n)//i是索引的位置  n是数组的长度
{
	BTNode *t;
	
	if (i < n)
	{
		t = new BTNode;
		t->data = A[i];
		t->lchild = create(A, 2 * i + 1, n);
		t->rchild = create(A, 2 * i + 2, n);
		return t;
	}
	return NULL;
}
void pre233(BTNode *T)
{
	if (T != NULL)
	{
		cout << T->data << " ";
		pre233(T->lchild);
		pre233(T->rchild);
	}
}
int main17()
{
	char A[] = "abcde";
	BTNode *T = create(A, 0, 6);
	pre233(T);
	//char site[] = "RUNOOB";
	//printf("菜鸟教程: %s\n", site[6]);这样定义字符串时 打印出来的时null
	return 0;
}

第二个头文件的实现

#include"018_treefun.h"
void aaaa(BTNode *&T, BTNode *p)
{
	char x;
	cin >> x;
	if (x == '#')
		T = NULL;
	else
	{
		T = new BTNode;
		T->data = x;
		T->parent = p;
		p = T;
		T->lchild = NULL;
		T->rchild = NULL;
		aaaa(T->lchild, p);
		aaaa(T->rchild, p);
	}
	return;
}

增加一个指向双亲节点的parent 指针输出所有节点到根节点的路径

#include <iostream>
#include "018_treefun.h"
using namespace std;
/*
	增加一个指向双亲节点的parent 指针输出所有节点到根节点的路径
			a
	
		b		c
	
	d		e

	输出所有结点到根节点的路径
	a
	ba
	ca
	dba
	eba
*/
void printpath(BTNode *p)
{
	while (p != NULL)
	{
		cout << p->data << " ";
		p = p->parent;
	}
}

void allpath(BTNode *p)
{
	if (p != NULL)
	{
		cout << "路径分别为:";
		printpath(p);//这里p执行完 移动到p->parent之后的操作在printpath里面释放掉了 结束这句语句 p是原来的p
		allpath(p->lchild);
		allpath(p->rchild);
	}
}

int main18()
{
	BTNode *T, *p = NULL;//p的初值是根节点的父亲
	aaaa(T, p);
	allpath(T);
	return 0;
}

先序非递归遍历二叉树

/*
	先序非递归遍历二叉树
*/
#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
	abdcef

		 a

	 b	     c

       d	e  f

弹出一个结点就要把它的右孩子和左孩子依次入栈

a入栈 a出栈 c、b入栈 b出栈 d入栈 d出栈 c出栈 e、f入栈 f出栈 e出栈 

	输出是先输出左再输出右
	因此入栈是先把右孩子入栈,再把左孩子入栈	
*/
void Nonpre(BTNode *bt)
{
	BTNode *Stack[maxsize];
	int top = -1;
	if (bt != NULL)
	{
		Stack[++top] = bt;
		while (top != -1)
		{
			bt = Stack[top--];
			cout << bt->data;
			if (bt->rchild != NULL)
				Stack[++top] = bt->rchild;
			if (bt->lchild != NULL)
				Stack[++top] = bt->lchild;
		}
	}
}

/*
	先把根节点入栈 
	1、有左孩子 打印输出
	2、无左孩子出栈 并且判断出栈的点有无右孩子
		2_1、有右孩子 入栈
		2_2、无右孩子 继续出栈
*/
void Nonpre2(BTNode *bt)
{
	BTNode *Stack[maxsize];
	int top = -1;
	while (bt || top != -1)                                                    //不写bt||  循环都进不去
	{
		if (bt != NULL)
		{
			cout << bt->data;
			Stack[++top] = bt;
			bt = bt->lchild;
		}
		else
		{
			bt = Stack[top--];
			bt = bt->rchild;
		}
	}
}

int main19()
{
	BTNode *T = aaaa();
	Nonpre2(T);
	return 0;
}

中序非递归遍历二叉树

/*
	中序非递归遍历二叉树
*/
#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50

/*
	中序非递归遍历  

	有左子树就入栈
	遍历到没有左子树的时候  进行出栈  然后进行打印  然后在找结点的右子树
*/
void Nonin(BTNode *bt)
{
	BTNode *Stack[maxsize];
	int top = -1;
	while (top != -1 || bt)
	{
		if (bt != NULL)
		{
			Stack[++top] = bt;
			bt = bt->lchild;
		}
		else
		{
			//中序是出栈的时候打印
			bt = Stack[top--];
			cout << bt->data << " ";
			bt = bt->rchild;
		}
	}
}

int main20()
{
	BTNode *T = aaaa();
	Nonin(T);
	return 0;
}

后序非递归遍历

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
	后序非递归遍历

		1
	 2	  3
	   4              后序遍历结果:4 2 3 1

	先将根结点入栈
	先看有没有左子树 如果有左子树 把左子树入栈
	如果没有左子树 则看有没有右子树 如果有右子树 则把右子树入栈
	如果既没有左子树也没有右子树 则出栈 打印

	1入栈 有左子树 2入栈 2没左子树 看右子树 4入栈 4无左右子树 4出栈 打印4 2出栈 打印2 然后看1右子树 3入栈 3无左右子树 3出栈 1出栈
*/  
void Nonpost(BTNode *bt)
{
	BTNode *St[maxsize] , *tag = NULL;
	int top = -1;
	while (bt || top != -1)
	{
		if (bt != NULL)
		{
			St[++top] = bt;
			bt = bt->lchild;
		}
		else
		{ 
			//bt没有左子树 那么访问右子树 此时的bt是栈顶元素
			bt = St[top];//bt所指向的是栈顶元素
			if (bt->rchild&& bt->rchild != tag)//tag指向上一个后序输出的结点
				bt = bt->rchild;
			else
			{
				bt = St[top--];
				cout << bt->data << " ";
				tag = bt;
				//为了使if循环结束
				//实际上,bt = NULL; 将指针 bt 设置为指向NULL,而不是将原来bt指向的节点本身变成NULL
				bt = NULL;
			}
		}
	}
}

/*
	后序是:左右根
	前序是:根左右

	实际上  先将左子树和右子树进行逆序(根右左) 再整体逆序(左右根)

		1
	 2	   3
	   4              后序遍历结果:4 2 3 1

*/
void Nonpost2(BTNode *bt)
{
	if (bt != NULL)
	{
		BTNode *Stack1[maxsize];
		BTNode *Stack2[maxsize];//用来输出最后的结果的
		int top1 = -1, top2 = -1;
		//根结点入第一个栈
		Stack1[++top1] = bt;
		while (top1 != -1)
		{
			//根结点出第一个栈
			bt = Stack1[top1--];
			//根结点入第二个栈 栈底是根节点 然后依次把孩子结点入栈按照左右孩子的顺序入栈 放入第二个栈中 打印时就是逆序的
			Stack2[++top2] = bt;
			if (bt->lchild != NULL)
				Stack1[++top1] = bt->lchild;
			if (bt->rchild != NULL)
				Stack1[++top1] = bt->rchild;
		}
		//遍历第二个栈
		while (top2 != -1)
		{
			bt = Stack2[top2--];
			cout << bt->data << " ";
		}
	}
}
void Nonpost3(BTNode *T)
{
	BTNode *stack[maxsize];
	BTNode *tag = NULL;
	int top = -1;
	while (T != NULL || top != -1)
	{
		if (T!=NULL)
		{
			stack[++top] = T;
			T = T->lchild;
		}
		else
		{
			T = stack[top];
			if (T->rchild&&T->rchild != tag)
			{
				T = T->rchild;
			}
			else
			{
				T = stack[top--];
				cout << T->data;
				tag = T;
				T = NULL;
			}
		}
	}
}

int main21()
{
	BTNode *T = aaaa();
	Nonpost2(T);
	return 0;
}

在二叉树中查找值为x的结点,打印出值为x的所有祖先

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
	在二叉树中查找值为x的结点,打印出值为x的所有祖先
*/
void Nonpost(BTNode *bt, char x)
{
	BTNode *St[maxsize], *tag = NULL;
	int top = -1;
	while (bt || top != -1)
	{
		if (bt != NULL)
		{
			St[++top] = bt;
			bt = bt->lchild;
		}
		else
		{
			bt = St[top];
			if (bt->rchild && bt->rchild != tag)
				bt = bt->rchild;
			else
			{
				//取栈顶元素 出栈
				bt = St[top--];
				if (bt->data == x)
					while (top != -1)
						cout << St[top--]->data << " ";
				tag = bt;
				bt = NULL;
			}
		}
	}
}
 
//void Nonpost2(BTNode *T)
//{
//	BTNode *stack[maxsize];
//	BTNode *tag = NULL;
//	int top = -1;
//	while (top != -1 || T != NULL) {
//		if (T != NULL)
//		{
//			stack[++top] = T;
//			T = T->lchild;
//		}
//		else {
//			T = stack[top];
//			if (T->rchild && T->rchild != tag)
//			{
//				T = T->rchild;
//			}
//			else {
//				T = stack[top--];
//				if (T->data==x)
//				{
//					while (top!=-1)
//					{
//						cout << stack[top--]->data;
//					}
//				}
//				tag = T;
//				T = NULL;
//			}
//		}
//	}
//}
int main22()
{
	BTNode *T = aaaa();
	Nonpost(T, '3');
	return 0;
}

找到p和q最近公共祖先结点r

/*
	找到p和q最近公共祖先结点r
*/

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
			a
		
		b		c

	d	   e
	
		 f
	
	找d和f的公共祖先 是b
	把d和f结点的所有祖先打印出来 然后进行对比 找到它们最近的公共祖先结点
	b a
	e b a
	发现最近的是b
*/
BiTree Nonpost(BTNode *bt, BTNode *p, BTNode *q)
{
	BTNode *St[maxsize], *tag = NULL;
	BTNode *s1[maxsize], *s2[maxsize];
	int top = -1, top1 = -1, top2 = -1;
	while (bt || top != -1)
	{
		if (bt != NULL)
		{
			St[++top] = bt;
			bt = bt->lchild;
		}
		else
		{
			bt = St[top];
			if (bt->rchild && bt->rchild != tag)
				bt = bt->rchild;
			else
			{
				bt = St[top--];
				//判断是否为p指针所指向的结点
				if (bt == p)
				{
					//这里不能直接用top 不然直接循环结束了
					int temp = top;
					while (temp != -1)
						//把入栈的元素放入到s1栈中
						s1[++top1] = St[temp--];
				}
				if (bt == q)
				{
					int temp = top;
					while (temp != -1)
						s2[++top2] = St[temp--];
				}
				tag = bt;
				bt = NULL;
			}
		}
	}
	//这里的循环是初始值为0的 代表从栈的底部开始遍历的 最底下相同的就是最近的公共祖先
	for (int i = 0; i <= top1; ++i)
		for (int j = 0; j <= top2; ++j)
			if (s1[i] == s2[j])
				return s1[i];
	return NULL;
}

int main23()
{
	BTNode *T = aaaa();
	BTNode *p = T->lchild->lchild;
	BTNode *q = T->lchild->rchild;
	cout << Nonpost(T, p, q)->data;
	return 0;
}

层次遍历

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
	层次遍历 

	用队列进行实现

				1

			2		3

			   4       6

			5                           结果为123465

根节点入队 1入队 1出队 然后2、3入队 2出队 4入队 3出队 6入队 4出队 5入队 5没有左右子树 6出队 5出队
*/
void level(BTNode *p)
{
	int front = 0, rear = 0;
	BTNode* que[maxsize];//BTNode **que  BTNode *p
	if (p != NULL)
	{
		que[++rear] = p;
		while (front != rear)
		{
			p = que[++front];
			cout << p->data << " ";
			if (p->lchild != NULL)
				que[++rear] = p->lchild;
			if (p->rchild != NULL)
				que[++rear] = p->rchild;
		}
	}
}
/*
	void test01(){
	int **pArray = malloc(sizeof(int *) * 5);
	//在栈上去开辟数据
	int a1 = 100;
	int a2 = 200;
	int a3 = 300;
	int a4 = 400;
	int a5 = 500;
	//堆区数组维护 栈上数据的地址 建立关系
	pArray[0] = &a1;
	pArray[1] = &a2;
	pArray[2] = &a3;
	pArray[3] = &a4;
	pArray[4] = &a5;
	//打印输出
	//int len = sizeof(pArray) / sizeof(int *);  4/4=1
	//printArray(pArray, len);err
	printArray(pArray, 5);
	//释放堆区的空间
	if (pArray != NULL)
	{
		free(pArray);
		pArray = NULL;
	}
}
*/

int main24()
{
	BTNode *T = aaaa();
	level(T);
	return 0;
}

试给出自下而上从右到左的层次遍历

/*
	试给出自下而上从右到左的层次遍历
	层次遍历是从上到下 从左往右进行遍历的 题目实际上是让你把层次遍历进行逆置

	用栈和队列进行实现  把队列中进行层次遍历出队的元素压入栈中 然后从栈顶进行输出

	12345  54321
*/
#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
   从下而上   从右到左 的层次遍历
*/
void level2(BTNode *p)
{
	BTNode *stack[maxsize];
	int top = -1;
	int front = 0, rear = 0;
	BTNode *que[maxsize];
	if (p != NULL)
	{
		que[++rear] = p;
		while (front != rear)
		{
			p = que[++front];
			stack[++top] = p;
			if (p->lchild != NULL)
				que[++rear] = p->lchild;
			if (p->rchild != NULL)
				que[++rear] = p->rchild;
		}
	}
	for (int i = top; i > -1; --i)
	{
		cout << stack[i]->data << " ";
	}
}

int main25()
{
	BTNode *T = aaaa();
	level2(T);
	return 0;
}

求解二叉树的宽度

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50
/*
	求解二叉树的宽度
	实际上二叉树的宽度就是二叉树哪一层的元素最多的层号

	层次遍历的思想

			a

		b		c

	d	     f    g       
			
		 e

	a b c d f g e 
	1 2 2 3 3 3 4

*/

//递归
void LevelWidth(BiTree T, int a[], int h)//int a[]数组是用来存储树所在层号的结点的个数 h表示层数
{
	if (T == NULL) {
		return;
	}
	else{
		a[h] += 1;
		LevelWidth(T->lchild, a, h + 1);
		LevelWidth(T->rchild, a, h + 1);
	}
}

int width(BiTree T)
{
	int a[maxsize], h = 1;
	for (int i = 0; i <= maxsize; i++)
		a[i] = 0;
	LevelWidth(T, a, h);
	int wid = a[0];
	for (int i = 1; i <= maxsize; i++)
		if (a[i] > wid)
			wid = a[i];
	return wid;
}

//如果我们想要用非递归的办法来解决的话,就需要设置一个数组来存储每层的结点数,然后引用一个max来记录最大结点数。 
typedef struct
{
	BTNode *p;//数据
	int lno;//层号
}St[maxsize];

int width2(BTNode *boot)//传入根节点
{
	St que;
	int front = 0, rear = 0;
	int Lno, i = 1, max = 0;
	if (boot != NULL)
	{
		//初始化  根节点入队
		que[++rear].p = boot;//把BTNode *boot结点放入到que[maxsize]这个数组里面 代替了原来的BTNode *p
		que[rear].lno = 1;

		while (front != rear)
		{
			BTNode *q = que[++front].p;//出队操作  实际上并没有出去
			Lno = que[front].lno;//初始的时候Lno的值为1
			if (q->lchild != NULL)
			{
				que[++rear].p = q->lchild;
				que[rear].lno = Lno + 1;
			}
			if (q->rchild != NULL)
			{
				que[++rear].p = q->rchild;
				que[rear].lno = Lno + 1;
			}
		}
		while (i <= rear)
		{
			int n = 0;//n是用来统计某一层的元素的个数
			int k = que[i].lno;
			//循环统计层数
			while (i <= rear && que[i].lno == k)
			{
				++i;
				++n;
			}
			//遍历每一层的max进行更新 大的则赋值给max
			if (n > max)
				max = n;
		}
	}
	return max;
}


int main26()
{
	BTNode *T = aaaa();
	cout << "二叉树的宽度为:" << width2(T) << endl;
	return 0;
}

层次遍历求二叉树的深度

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50

/*
	层次遍历求二叉树的深度

	初始化level为0
	层次遍历到每一层最右边的结点时 level++
*/

int depth(BTNode *boot)
{
	if (boot == NULL)
		return 0;
	int front = 0, rear = 0;
	int last = 1, level = 0;//last初值为1 表示的是最后一个结点 第last个结点是最后一个结点
	BTNode *q[maxsize];
	//根结点入队
	q[++rear] = boot;
	BTNode *p;
	while (front < rear)
	{
		//出队
		p = q[++front];
		if (p->lchild)
			q[++rear] = p->lchild;
		if (p->rchild)
			q[++rear] = p->rchild;
		if (front == last)
		{
			level++;
			last = rear;
		}
	}
	return level;
}

int main27()
{
	BTNode *T = aaaa();
	cout << "层次遍历法求得得二叉树深度为:" << depth(T) << endl;
	return 0;
}

判断二叉树是否为完全二叉树

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50

/*
	判断二叉树是否为完全二叉树
	运用队列的层次遍历

	       1

		2	 3

	  4     5              入队的队列数组:1234#5###

	如果当前出队的结点为null,如果后面不全为null,则代表这个二叉树不是完全二叉树
*/

bool fun(BTNode *p)
{
	BTNode *q[maxsize];
	int front = 0, rear = 0;
	//如果这个二叉树是空二叉树 这个二叉树也是完全二叉树
	if (p == NULL)
		return true;
	//根节点入队
	q[++rear] = p;
	//队列不为空
	while (front != rear)
	{
		//根节点出队
		p = q[++front];
		//出队的结点不为null的情况 左右子树入队
		if (p != NULL)
		{
			q[++rear] = p->lchild;
			q[++rear] = p->rchild;
		}
		//当前遍历的结点为null时 出队的时候判断
		else
			while (front != rear)
			{
				//将后面的元素出队 如果出队的元素有不为null的结点 则判断不是完全二叉树
				p = q[++front];
				if (p != NULL)
					return false;
			}
	}
	return true;
}

int main28()
{
	BTNode *T = aaaa();
	if (fun(T))
		cout << "是完全二叉树!";
	else
		cout << "不是完全二叉树!";
	return 0;
}

计算二叉树的带权路径长度(叶子节点)

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
#define maxsize 50

/*
	计算二叉树的带权路径长度(叶子节点)

				3

			  2	    7

				  5    1   

	二叉树的带权路径长度:2*1+(5+1)*2=14
*/
 
int fun(BTNode *p)
{
	BTNode *que[maxsize];
	int front = 0, rear = 0;
	int wpl = 0, last = 1, deep = 0;//last=1 是用来计算高度的从front=last的时候 deep++
	//根节点入队
	que[++rear] = p;
	while (front != rear)
	{
		//出队
		p = que[++front];
		//判断是不是叶子结点
		if (!p->lchild && !p->rchild)
			wpl += deep * (p->data - '0');//1的ASCII码时49 0的ASCII码为48 相减就为1
		if (p->lchild != NULL)
			que[++rear] = p->lchild;
		if (p->rchild != NULL)
			que[++rear] = p->rchild;
		if (front == last)
		{
			deep++;//deep代表路径的长度
			last = rear;
		}
	}
	return wpl;
}

int fun2(BTNode *p, int deep)
{
	int A, B;
	if (p == NULL)
		return 0;
	if (!p->lchild && !p->rchild) 
		return deep * (p->data - '0');
	A = fun2(p->lchild, deep + 1);
	B = fun2(p->rchild, deep + 1);
	return A + B;
}

int fun3(BTNode *p, int deep)
{
	if (p == NULL)
		return 0;
	int A, B;
	if (!p->lchild && !p->rchild)
		return (p->data - '0') * deep;
	++deep;
	A = fun3(p->lchild, deep);
	B = fun3(p->rchild, deep);
	--deep;
	return A + B;
}

int main29()
{
	BTNode *T = aaaa();
	int x = 0;
	cout << "wpl:" << fun3(T, x);
	return 0;
}

将给定的二叉树转化为等价的中缀表达式

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
/*
	将给定的二叉树转化为等价的中缀表达式
*/
void fun(BTNode *p, int deep)
{
	if (p != NULL)
	{
		if ((p->lchild || p->rchild) && deep > 1)
			cout << "(";
		if (p->lchild != NULL)
			fun(p->lchild, deep + 1);
		cout << p->data;
		if (p->rchild != NULL)
			fun(p->rchild, deep + 1);
		if ((p->lchild || p->rchild) && deep > 1)
			cout << ")";
	}
}

void fun2(BTNode *p, int deep)
{
	if (p != NULL)
	{
		if ((p->lchild || p->rchild) && deep > 1)
			cout << "(";
		++deep;
		if (p->lchild != NULL)
			fun2(p->lchild, deep);
		cout << p->data;
		if (p->rchild != NULL)
			fun2(p->rchild, deep);
		--deep;
		if ((p->lchild || p->rchild) && deep > 1)
			cout << ")";
	}
}

int main30()
{
	BTNode *T = aaaa();
	fun2(T, 1);
	return 0;
}

用孩子兄弟表示法来求所有的叶子结点的个数

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;

/*
	用孩子兄弟表示法来求所有的叶子结点的个数

	//用孩子兄弟表示法表示
	//用这种表示法表示 左孩子为空的结点就是树的叶子结点
		
*/

//int fun273(BTNode *p)
//{
//	if (p == NULL)
//		return 0;
//	if (p->lchild == NULL)
//	{
//		return fun273(p->rchild) + 1;
//	}
//	return fun273(p->lchild) + fun273(p->rchild);
//}

void func123(BTNode *T, int &n)
{
	if (T)
	{
		if (T->lchild == NULL)
		{
			++n;
		}
		else
		{
			func123(T->lchild, n);
			func123(T->rchild, n);
		}
	}
}

/*
	用孩子兄弟表示法求单分支结点的个数
*/
//int func(BTNode *p)
//{
//	if (p == NULL)
//	{
//		return 0;
//	}
//	if (!p->lchild && !p->rchild)
//	{
//		return 0;
//	}
//	if (p->lchild && p->rchild == NULL)
//	{
//		return 1 + func(p->lchild);
//	}
//	if (p->lchild == NULL && p->rchild)
//	{
//		return 1 + func(p->rchild);
//	}
//	return func(p->lchild) + func(p->rchild);
//}


// 计算树的所有单分支结点个数的函数
int countSingleBranchNodes(BTNode* node) {
	if (node == nullptr) {
		return 0; // 空结点,不是单分支结点
	}

	int count = 0;

	// 只有一个孩子,是单分支结点
	if (node->lchild != nullptr && node->lchild->rchild == nullptr) {
		count = 1;
	}

	// 递归计算孩子和兄弟结点的单分支结点个数
	count += countSingleBranchNodes(node->lchild) + countSingleBranchNodes(node->rchild);

	return count;
}
 
int main35()
{
	//int n = 0;
	BTNode *T = aaaa();
	//func123(T, n);
	//cout << "叶子节点个数为:" << n;
	/*cout << "叶子节点个数为:" << fun273(T);*/
	cout << " " << countSingleBranchNodes(T);
	return 0;
}

孩子兄弟表示法求树的深度

#include <iostream>
#include "0_BiTreefun.h"
using namespace std;
//孩子兄弟表示法求树的深度

/*
	用孩子兄弟表示法来求所有的叶子结点的个数

	//树为
		  a
		
	b     c     d

			  e     f

	//用孩子兄弟表示法表示
	//用这种表示法表示 左孩子为空的结点就是树的叶子结点
		  a
	  b
		 c
			d
		 e
			f

*/

void fun(BTNode *T, int n, int &max)//max是会改变的
{
	if (max < n)
		max = n;
	//左孩子不为NULL 树的高度+1
	if (T->lchild != NULL)
		fun(T->lchild, n + 1, max);
	//右孩子不为NULL 树的高度不变
	if (T->rchild != NULL)
		fun(T->rchild, n, max);
}
int main36()
{
	int n = 1;
	int max = 0;
	BTNode *T = aaaa();
	fun(T, n, max);
	cout << max << endl;
	return EXIT_SUCCESS;
}

已知一棵树的层次序列和每个节点的度(出度), 编写算法构造此树的孩子兄弟链表

/*	
	已知一棵树的层次序列和每个节点的度(出度), 编写算法构造此树的孩子兄弟链表。
				a

			b	c	d
			
				   e f


		abcdef
		300200
*/


#include <iostream>
#include "037_Bitree.h"
#include "0_BiTreefun.h"
using namespace std;

void create(CBNode *&T, char e[], int degree[], int n)
//char e[]是存放树的结点例如abcd  int degree[]存放的是度的数组 n表示结点的个数
{
	CBNode *p = new CBNode[maxsize]; //这里p不是指针而是数组对象
	int i, j, d, k = 0;//i j d是没有初值的
	//创建结点初始化 还没有进行链接
	for (i = 0; i < n; ++i)
	{ 
		p[i].data = e[i];
		p[i].lchild = NULL;
		p[i].rchild = NULL;
	}
	//链接操作
	for (i = 0; i < n; ++i)
	{
		d = degree[i];

		if (d)//如果d是存在的 即不为0 证明这个结点是有孩子的 不是叶子结点
		{
			p[i].lchild = &p[++k];

			for (j = 2; j <= d; ++j)
			{
				++k;
				p[k - 1].rchild = &p[k];
			}
		}
	}
	T = p;
	//free(p);
}

void pre(CBNode *T)
{
	if (T != NULL)
	{
		cout << T->data << " ";
		pre(T->lchild);
		pre(T->rchild);
	}
}

int main37()
{
	char e[7] = "123456";
	int degree[6] = { 3, 0, 2, 0, 0, 0 };
	CBNode *T;
	create(T, e, degree, 6);
	for (int i = 0; i < 6; ++i)
		cout << T[i].data << endl;
	pre(T);
	free(T);
	return 0;
}

设树的存储结果为孩子兄弟链表,试编写算法,输出树中所有从根到叶子的路径

/*
	设树的存储结果为孩子兄弟链表,试编写算法,输出树中所有从根到叶子的路径
	
	这里是孩子兄弟链表表示法

	假设孩子兄弟表示法为:    

			A

		B

	C		D

	二叉链表表示法:
		
			A
	
		B		D
	
	C

*/

#include <iostream>
#include"0_Bitreefun.h"
using namespace std;

void allpath(BTNode *p, char pathstack[], int top)//传入参数分别为树 栈 top
{
	if (p!=NULL)
	{
		pathstack[++top] = p->data;
		if (!p->lchild)//孩子兄弟法的叶子结点
			for (int i = 0; i <= top; ++i)//从top[0]开始打印 即从根节点开始打印124  而不是421
				cout << pathstack[i] << " ";
		cout << endl;
		allpath(p->lchild, pathstack, top);
		allpath(p->lchild->rchild, pathstack, top);//????????
	}
}

int main02()
{
	int top = -1;
	char pathstack[maxsize];
	BTNode *T = bbbb();
	allpath(T, pathstack, top);
	return 0;
}

头文件

邻接表的头文件

#include <iostream>
using namespace std;
#define maxsize 100
/*
	邻接表存储
*/
typedef struct ArcNode
{
	int adjvex; //索引值 不是data域
	struct ArcNode *nextarc;//指向下一条边的指针
} ArcNode, *Node; //边结点结构体

typedef struct
{
	int data;//顶点信息   ???
	ArcNode *firstarc;//指向第一条边
} Vnode; //顶点结构体

typedef struct
{
	Vnode adjlist[maxsize];
	int numver, numedg;//图的顶点个数 图的边的个数
} AGraph; //图

//创建一个无向图
AGraph *aaaa(int v, int e);

邻接矩阵的头文件

#include <iostream>
using namespace std;
#define maxsize 100

typedef struct
{
	char verticle[maxsize];//顶点表
	int Edge[maxsize][maxsize];//边表
	int numver, numedg;//顶点数 边数
} mgraph;
//x的取值为1/0 1表示与偶边 0表示没边
mgraph aaaa();

邻接表的头文件的实现

#include"0_graph1.h"
/*
	创建一个无向图
	1、根据点个数来确定左框个数
	2、根据便个数来确定右框个数
*/
AGraph *aaaa(int v, int e)
{
	AGraph *G = new AGraph;
	G->numver = v;              //顶点数
	G->numedg = e;              //边数
	for (int i = 0; i < v; ++i) //初始化顶点后面的边结点为NULL 表示是没有路径的 
		G->adjlist[i].firstarc = NULL;
	
	for (int i = 0; i < e; ++i)
	{
		//v1和v2连接  因为是无向图  也要v2和v1连接 所以要建立两次头插
		cout << "输入:";
		int v1, v2;//v1为待插入的边结点 v2为
		cin >> v1;
		cin >> v2;
		ArcNode *p = new ArcNode; 
		p->adjvex = v2;           
		p->nextarc = G->adjlist[v1].firstarc;//firstarc初始的时候是null 后面就是前一个刚插入的边结点
		G->adjlist[v1].firstarc = p;
		
		ArcNode *q = new ArcNode; 
		q->adjvex = v1;           
		q->nextarc = G->adjlist[v2].firstarc;
		G->adjlist[v2].firstarc = q;
	}
	cout << "完成!" << endl;
	return G;
}

邻接矩阵的头文件的实现

#include"0_graph2.h"
mgraph aaaa()
{
	int x;
	mgraph M;
	M.numver = 5;
	M.numedg = 5;
	for (int i = 0; i < M.numver; ++i)
		for (int j = 0; j < M.numver; ++j)
		{
			cin >> x;
			M.Edge[i][j] = x;
		}
	return M;
}

己知无向连通图G由顶点集V和边集E组成,[EI>0当G中度为奇数的顶点个数为不大于2的偶数时,G存在包含所有边且长度为|E|的路径(称为EL路径)。设图G采用邻接矩阵存储,设计算法判断图中是否存在EL路径,若存在返回1,否则返回0。

/*
	己知无向连通图G由顶点集V和边集E组成,[EI>0
	当G中度为奇数的顶点个数为不大于2的偶数时,G存在包含所有边且长度为|E|的路径(称为EL路径)。
	设图G采用邻接矩阵存储,设计算法判断图中是否存在EL路径,若存在返回1,否则返回0。
*/
#include <iostream>
#include "0_graph2.h"
using namespace std;
int IsExistEL(mgraph G)
{
	int degree, i, j, count = 0;
	for (i = 0; i < G.numver; ++i)//顶点数
	{
		degree = 0;
		for (j = 0; j < G.numver; ++j)
			degree += G.Edge[i][j];//Edge是矩阵
		if (degree % 2 != 0)
			count++;
	}
	if (count == 0 || count == 2)
		return 1;
	else
		return 0;
}

int main01()
{
	mgraph M = aaaa();
	if (IsExistEL(M))
		cout << "1";
	else
		cout << "0";
	return 0;
}

广度优先(图的层次遍历)

#include <iostream>
#include"0_graph1.h"
using namespace std;
/*
	广度优先(图的层次遍历)
	输入:0 1
	输入:0 2
	输入:1 2
	输入:1 3
	完成!
	0 2 1 3
*/
void BFS(AGraph *G, int v, int visit[])//v是序号表示从哪个顶点开始 v也是索引值
{
	for (int i = 0; i < G->numver; ++i) //若G不是指针则用G.numver
		visit[i] = 0;//visit[i]=0表示没有被访问过 visit[i]=1表示访问过了
	int que[maxsize];
	int front = 0, rear = 0;
	cout << v << " ";
	visit[v] = 1;
	que[++rear] = v;
	while (front != rear)
	{
		int v = que[++front];
		ArcNode *p = G->adjlist[v].firstarc;
		while (p != NULL)
		{
			if (visit[p->adjvex] == 0)
			{
				cout << p->adjvex << " ";
				visit[p->adjvex] = 1;
				que[++rear] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
} 

int main02()
{
	AGraph *G = aaaa(4, 4); //输入从0开始,例如输入四个节点依次为0,1,2,3
	int visit[maxsize];
	BFS(G, 0, visit);
	return 0;
}

BFS求最短路径问题

/*
	BFS求最短路径问题
*/
void BFSmin(AGraph *G, int v, int d[])//v是起始点 d[]表示最短路径 d[1]表示的是0到1的最短路径
{
	int visit[maxsize];
	for (int i = 0; i < G->numver; ++i)
		d[i] = INT16_MAX; //是个无穷大值,#define INT16_MAX 32767     
	for (int i = 0; i < G->numver; ++i)
		visit[i] = 0;
	int que[maxsize];
	int front = 0, rear = 0;
	visit[v] = 1;
	d[v] = 0;
	que[++rear] = v;
	while (front != rear)
	{
		v = que[++front];
		ArcNode *p = G->adjlist[v].firstarc;
		while (p != NULL)
		{
			if (visit[p->adjvex] == 0)
			{
				d[p->adjvex] = d[v] + 1;
				visit[p->adjvex] = 1;
				que[++rear] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
}

int main03()
{
	AGraph *G = aaaa(3, 3);
	int d[maxsize];
	BFSmin(G, 0, d);
	cout << d[2];
	return 0;
}

图的深度优先遍历 递归

#include <iostream>
#include "0_graph1.h"
using namespace std;
// DFS

/*
	图的深度优先遍历 递归
*/
void DFS_DFS(AGraph *G, int v, int visit[])
{
	visit[v] = 1;
	cout << v << " ";
	ArcNode *p = G->adjlist[v].firstarc;
	while (p != NULL)
	{
		if (visit[p->adjvex] == 0)//没有被访问
			DFS_DFS(G, p->adjvex, visit);
		p = p->nextarc;
	}
}

int main04()
{
	int visit[maxsize];
	AGraph *G = aaaa(4, 4);
	for (int i = 0; i < G->numver; ++i)
		visit[i] = 0;
	DFS_DFS(G, 2, visit);
	return 0;
}

判断i j结点之间是否有路径(图采用邻接表存储)

#include <iostream>
#include "0_graph1.h"
using namespace std;
/*
	判断i j结点之间是否有路径(图采用邻接表存储)
*/
void DFS33(AGraph *G, int v, int visit[])
{
	visit[v] = 1;
	// cout << v << " ";
	ArcNode *p = G->adjlist[v].firstarc;
	while (p != NULL)
	{
		if (visit[p->adjvex] == 0)
			DFS33(G, p->adjvex, visit);
		p = p->nextarc;
	}
}

bool DFS1(AGraph *G, int i, int j)//i是起始点 j是终点
{
	int k;
	int visit[maxsize];
	for (k = 0; k < G->numver; ++k)
		visit[k] = 0;
	DFS33(G, i, visit);//从i开始进行深度优先遍历
	if (visit[j] == 1)//如果进行深度优先遍历后 终点被访问过 表示是有路径的
		return true;
	else
		return false;
}
int main05()
{
	AGraph *G = aaaa(4, 3);
	if (DFS1(G, 0, 2))
		cout << "1";
	else
		cout << "0";
	return 0;
}

判断 一个无向图是不是一颗树

#include <iostream>
#include "0_graph1.h"
using namespace std;
/*
	判断 一个无向图是不是一颗树

	图满足以下两个条件就是一棵树
	1、顶点个数-边数=1
	2、连通图
*/

void fun(AGraph *G, int v, int &vn, int visit[])//vn统计的进行深度优先遍历后顶点的个数
{
	visit[v] = 1;
	++vn;
	ArcNode *p = G->adjlist[v].firstarc;
	while (p != NULL)
	{
		if (visit[p->adjvex] == 0)
			fun(G, p->adjvex, vn, visit);
		p = p->nextarc;
	}
}
bool GisTree(AGraph *G)
{
	int vn = 0;//, en = 0;
	int visit[maxsize];
	for (int i = 0; i < G->numver; ++i)
		visit[i] = 0;
	fun(G, 0, vn, visit);//0表示从0顶点开始访问
	//从vn开始进行深度优先遍历 如果遍历的结点个数等于这个图的个数那么就是连通图
	if (vn == G->numver && G->numver - 1==G->numedg)
		return true;
	else
		return false;
}
int main06()
{
	AGraph *G = aaaa(4, 3);
	if (GisTree(G))
		cout << "1";
	else
		cout << "0";
	return 0;
}

设计一个算法,求无向连通图距离顶点V最远的一个结点(即路径长度最大)

#include <iostream>
#include "0_graph1.h"
using namespace std;
/*
	设计一个算法,求无向连通图距离顶点V最远的一个结点(即路径长度最大)

	连通图:任意两个顶点都是有路径的
		1
	0		3	  4     
		2

	以0为起点 距离顶点0最远的结点是4 即(0~4路径是最长的)
	用广度优先遍历进行实现 最后一个出队列的顶点就是距离最远的顶点
*/
int BFS(AGraph *G, int v)
{
	int que[maxsize];
	int front = 0, rear = 0;
	int visit[maxsize];
	for (int i = 0; i < G->numver; ++i)//numver顶点个数
		visit[i] = 0;
	que[++rear] = v;
	visit[v] = 1;
	while (front != rear)
	{
		v = que[++front];
		ArcNode *p = G->adjlist[v].firstarc;//顶点第一个邻接点
		while (p != NULL)
		{
			if (visit[p->adjvex] = 0)
			{
				visit[p->adjvex] = 1;
				que[++rear] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
	return v;//最后一个结束的v就是要得到的v 此时的v就是距离0最大的路径的顶点
}

int main07()
{
	AGraph *G = aaaa(4, 4);
	cout << BFS(G, 0);
	return 0;
}

写出深度优先遍历的非递归算法

#include <iostream>
#include "0_graph1.h"
using namespace std;
/*
	写出深度优先遍历的非递归算法

	用栈实现
*/
void DFS1(AGraph *G, int v)//v为初始的顶点
{
	int visit[maxsize];
	for (int i = 0; i < G->numver; ++i)
		visit[i] = 0;
	int stack[maxsize];
	int top = -1;

	cout << v << " ";
	visit[v] = 1;
	stack[++top] = v;
	while (top != -1)
	{
		int k = stack[top];//访问栈顶的元素 
		ArcNode *p = G->adjlist[k].firstarc;
		//p不为NULL 而且p是被访问过了 p指向p的下一个结点
		while (p != NULL && visit[p->adjvex] == 1)
			p = p->nextarc;
		//p为NULL 则出栈
		if (p == NULL)
			--top;
		//p不为NULL 则入栈
		else
		{ 
			cout << p->adjvex << " ";
			visit[p->adjvex] = 1;
			stack[++top] = p->adjvex;
		}
	}
}
int main08()
{
	AGraph *G = aaaa(4, 4);
	DFS1(G, 2);
	return 0;
}

简单路径

#include <iostream>
#include "0_graph1.h"
using namespace std;
/*


	简单路径是指没有经过重复的路

		1
	0		2
		3
	
	0到3的简单路径为:
	(0,3) (0,1,3) (0,1,2,3)  

	而(0,1,0,3)就不是简单路径
*/

/*
	例如:
		1
	0		2
		3
	求1到3的简单路径

	path[0]=1 表示整个路径的起点为1
	path[1]=3
	那么路径就为1~3

	path[0]=1
	path[1]=0
	path[2]=3
	那么路径就为1~0~3
	
	注意path[0]是不会改变的 表示的是整个路径的起点
*/
void findpath(AGraph *G, int u, int v, int path[], int d, int visit[])//d的初值=-1
{
	int w, i;
	path[++d] = u;
	visit[u] = 1;
	//遍历过程中起始点和终点相等的时候 输出路径
	if (u == v)
	{ 
		for (i = 0; i <= d; ++i)
			cout << path[i] << " ";
	}
	ArcNode *p = G->adjlist[u].firstarc;
	while (p != NULL)
	{
		w = p->adjvex;
		if (visit[w] == 0)
		{
			//起始点变成了w
			findpath(G, w, v, path, d, visit);
		}
		p = p->nextarc;
	}
	visit[u] = 0;
}

int main()
{
	AGraph *G = aaaa(4, 5);
	int visit[maxsize];
	for (int i = 0; i < G->numver; ++i)
		visit[i] = 0;
	int path[maxsize];
	findpath(G, 0, 3, path, -1, visit);
	return 0;
}

求无向图的连通分量个数

#include <iostream>
#include "0_graph1.h"
using namespace std;
#define maxsize 50
/*
	求无向图的连通分量个数
	
	无向图的极大连通子图称为连通分量
*/

//深度优先遍历遍历连通分量是把整个连通分量都遍历了一边 每访问一个连通分量count只+1
void DFS(AGraph *G, int v, int visit[])
{
	visit[v] = 1;
	// cout << v << " ";
	ArcNode *p = G->adjlist[v].firstarc;
	while (p != NULL)
	{
		if (visit[p->adjvex] == 0)
			DFS(G, p->adjvex, visit);
		p = p->nextarc;
	}
}
int func(AGraph *G)
{
	int visit[maxsize];
	for (int i = 0; i < G->numver; ++i)
		visit[i] = 0;
	int count = 0;
	for (int j = 0; j < G->numver; ++j)
		if (visit[j] == 0)
		{
			DFS(G, j, visit);
			count++;
		}
	return count;
}
int main10()
{
	AGraph *G = aaaa(4, 3);
	cout << "" << func(G);
	return 0;
}

邻接表转化成邻接矩阵

/*
	邻接表转化成邻接矩阵

*/

void invert2(mgraph G1, AGraph *g2)//G1是邻接矩阵 g2是邻接表
{
	G1.numver = g2->numver;//图的顶点的个数
	G1.numedg = g2->numedg;
	for (int i = 0; i < g2->numver; ++i)//i表示顶点的索引值
	{
		ArcNode *p = g2->adjlist[i].firstarc;//获取g2的边结点
		while (p != NULL)
		{
			G1.Edge[i][p->adjvex] = 1;
			p = p->nextarc;
		}
	}
}
/*
	图为:

		0

	1		2

		3

	0~1 0~2 1~2 1~3

	邻接表为:
	0--1--2--NULL
	1--0--2--3--NULL
	2--0--1--NULL
	3--1--NULL

	邻接矩阵二维数组为1表明有路径 0表明没有路径

		0  	  1	    2	   3
	0

	1

	2

	3
*/

邻接矩阵转邻接表

void invert(mgraph G1, AGraph *g2)//G1是邻接矩阵 g2是邻接表
{
	g2->numver = G1.numver;
	g2->numedg = G1.numedg;
	for (int i = 0; i < g2->numver; ++i)
	{
		//先让邻接表的结点顶点都指向NULL
		g2->adjlist[i].firstarc = NULL;
	}
	for (int i = 0; i < G1.numver; i++)
	{
		for (int j = 0; j < G1.numver; j++)
		{
			if (G1.Edge[i][j] != 0)
			{
				ArcNode *p = new ArcNode;
				p->adjvex = j;
				//头插
				p->nextarc = g2->adjlist[i].firstarc;
				g2->adjlist[i].firstarc = p;
			}
		}
	}
}

查找

头文件

树的头文件 Bitree.h

#include <iostream>
using namespace std;

typedef struct BTNode
{
	char data;
	struct BTNode *lchild, *rchild;
} BTNode, *BiTree;

BiTree bbbb();

链表的头文件 linklist.h

#include <iostream>
using namespace std;
typedef struct LNode
{
	int data;
	struct LNode *next;
} LNode, *Linklist;


//不带头节点的链表
Linklist aaaa();
//带头节点的链表
Linklist bbbb();

顺序表的头文件 sqlist.h

#include <iostream>
using namespace std;
#define maxsize 50
typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

顺序表递增有序,设计算法在最少的时间内查找值为x的元素。若找到,则将其于后继元素位置交换,否则按照递增顺序插入顺序表

#include <iostream>
using namespace std;
#define maxsize 100
/*
	顺序表递增有序,设计算法在最少的时间内查找值为x的元素。
	若找到,则将其于后继元素位置交换,否则按照递增顺序插入顺序表

	查找值为5的元素

	2 5 7 10 15 19
	2 7 5 10 15 19

*/

typedef struct
{
	int data[maxsize];
	int length;
} Sqlist;

//二分法
void search(Sqlist &L, int x)
{
	int low = 0, high = L.length - 1, mid, temp, i;
	while (low <= high)
	{
		//计算数组的中间的元素
		mid = (low + high) / 2;
		if (L.data[mid] == x)
			break;
		else if (L.data[mid] > x)
			//如果中间的元素比查找的元素要小
			high = mid - 1;
		else
			//如果中间的元素比查找的元素要大
			low = mid + 1;
	}
	//题目要求找到的元素与后面一个元素进行交换 所以这个mid不等于L.length-1
	//交换操作
	if (L.data[mid] == x && mid != L.length - 1)
	{
		temp = L.data[mid];
		L.data[mid] = L.data[mid + 1];
		L.data[mid + 1] = temp;
	}
	if (low > high)
	{
		for (i = L.length - 1; i > high; --i)//high在左 low在右
			L.data[i + 1] = L.data[i];//把大于high的右移一位 然后把值附上去
		//这里的i执行完上一次的for循环-1 所以这里插入要+1
		L.data[i + 1] = x;
		L.length++;
	} 
}

int main01()
{
	Sqlist A = { {2, 5, 9, 13, 19}, 5 };
	search(A, 6);
	for (int j = 0; j < A.length; ++j)
		cout << A.data[j] << endl;
	return 0;
}

链表头文件的实现

#include"linklist.h"
//不带头节点的链表
Linklist aaaa()
{
	LNode *L = new LNode;
	int a;
	cin >> a;
	L->data = a;
	LNode *p = L; //声明一个指针指向头结点,
	//生成链表
	cin >> a;
	while (a != 0)//输入0为循环的结束条件
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = NULL;
	return L;
}

//带头节点的链表
Linklist bbbb()
{
	LNode *L = new LNode; //创建一个头结点
	LNode *p = L;         //声明一个指针指向头结点
	//生成链表
	int a;
	cin >> a;
	while (a != 0)
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = NULL;
	return L;
}

找到单链表中值为key的元素,将其与前一个结点位置互换

#include <iostream>
#include "linklist.h"
using namespace std;
/*
	2、找到单链表中值为key的元素,将其与前一个结点位置互换。

	假设key为4

	L 6 4 10 3 5
	L 4 6 10 3 5
*/
void fun(LNode *&L, int k)
{
	LNode *l = L;
	//如果这个是一个结点 与头节点是不能交换的 所以return
	if (l->next->data == k)
		return;
	while (l->next->next)
		if (l->next->next->data != k)
			l = l->next;
		else
			break;
	if (l->next->next != NULL)
	{
		LNode *p = l->next;
		LNode *q = p->next;
		//与前一个元素互换
		p->next = q->next;
		l->next = q;
		q->next = p;
	}
}

int main02()
{
	LNode *L = bbbb();
	fun(L, 3);
	while (L->next != NULL)
	{
		cout << L->next->data;
		L = L->next;
	}
	return 0;
}

在顺序表(有序的)二分查找值为key的元素

/*
	在顺序表(有序的)二分查找值为key的元素
*/
#include <iostream>
using namespace std;
#include "sqlist.h"
int binsearch(Sqlist L, int key)
{
	int low = 0, high = L.length - 1, mid;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (L.data[mid] == key)	
			return mid;
		else if (L.data[mid] < key)
			low = mid + 1;
		else
			high = mid - 1;
	}
	return -1;
}

//递归
int bi(Sqlist L, int key, int low, int high)
{
	if (low > high)
		return -1;
	int mid = (low + high) / 2;
	if (L.data[mid] < key)
		bi(L, key, mid + 1, high);
	else if (L.data[mid] > key)
		bi(L, key, low, mid - 1);
	else
		return mid;
}
int main03()
{
	Sqlist L = { {1, 3, 5, 8, 9}, 5 };
	cout << "result is:" << bi(L, 8, 0, 4);
	return 0;
}

树头文件的实现

#include"BiTree.h"

BiTree bbbb()
{
	char x;
	cin >> x;
	if (x != '#')
	{
		BTNode *T = new BTNode;
		T->data = x;
		T->lchild = bbbb();
		T->rchild = bbbb();
		return T;
	}
	return NULL;
}

寻找二叉排序树的最大值和最小值

/*
	寻找二叉排序树的最大值和最小值
*/
#include <iostream>
#include "BiTree.h"
using namespace std;
BiTree Min(BTNode *bt)
{
	while (bt->lchild != NULL)
		bt = bt->lchild;
	return bt;
}
BiTree Max(BTNode *bt)
{
	while (bt->rchild != NULL)
		bt = bt->rchild;
	return bt;
}
int main04()
{
	BTNode *T = bbbb();
	cout << Min(T)->data << endl;
	cout << Max(T)->data << endl;
	return 0;
}

判断给定的二叉树是否为二叉排序(搜索)树

#include <iostream>
#include "BiTree.h"
using namespace std;
//int pre = -INT_MAX;//pre的初始值是左子树中最大的值
//int JudgeBST(BTNode *root)
//{
//	//空树一定是二叉排序树
//	if (root == NULL)
//		return 1;
//
//	int a = JudgeBST(root->lchild);
//	if (root->data <= pre || a == 0)
//		return 0;
//	else
//		pre = root->data;
//	int b = JudgeBST(root->rchild);
//	return b;
//}

/*
	判断给定的二叉树是否为二叉排序(搜索)树

	二叉排序树的中序遍历是递增的 
*/
int low = INT_MIN;
int high = INT_MAX;

int func(BTNode *root, int low, int high)
{
	if (root == NULL)
	{
		return 1;
	}
	if (root->data >= high || root->data <= low)
	{
		return 0;
	}
	int a = func(root->lchild, low, root->data);//左子树肯定是要比根节点小的
	int b = func(root->rchild, root->data, high);
	return a && b;
}



int main05()
{
	BTNode *T = bbbb();
	if (func(T, low, high)==1)
		cout << "是二叉排序树!";
	else
		cout << "不是二叉排序树!";
	return 0;
}

求出指定结点在二叉排序树的层次

#include <iostream>
#include "BiTree.h"
using namespace std;
/*
	求出指定结点在二叉排序树的层次

			5
		
		 3	   8

	  1	   4

	  4在第三层
*/
int level(BTNode *bt, int k)
{
	int n = 1;//初始的层数
	if (bt != NULL)
	{
		while (bt->data != k)
		{
			if (bt->data < k)
				bt = bt->rchild;
			else
				bt = bt->lchild;
			++n;
		}
	}
	return n;
}
int main06()
{
	BTNode *T = bbbb();
	cout << "二叉树所在的层数是:" << level(T, '5');
	return 0;
}

输出二叉搜索树中所有值大于key的结点

#include <iostream>
#include "BiTree.h"
using namespace std;
/*
	输出二叉搜索树中所有值大于key的结点

	中序遍历后的二叉排序树是增序的
*/
void fun(BTNode *T, char key)
{
	if (T != NULL)
	{
		fun(T->lchild, key);
		if (T->data > key) 
		{
			cout << T->data;
		}
		fun(T->rchild, key);
	}
}
int main07()
{
	BTNode *T = bbbb();
	char key = '5';
	fun(T, key);
	return 0;
}

判断二叉树是否为平衡二叉树

/*
	判断二叉树是否为平衡二叉树

	时间和空间复杂度是O(n)

	1、对左子树进行递归 判断是否为平衡二叉数
	2、对右子树进行递归 判断是否为平衡二叉数
	3、高度满足平衡二叉树的条件(<=1)
*/
#include <iostream>
#include<stdbool.h>
#include "BiTree.h"
using namespace std;
//void fun(BTNode *bt, int &balance, int &h)
//{
//	int bl = 0, br = 0, hl = 0, hr = 0;
//	if (bt == NULL)
//	{
//		h = 0;
//		balance = 1;
//	}
//	else if (!bt->lchild && !bt->rchild)
//	{
//		h = 1;
//		balance = 1;
//	}
//	else
//	{
//		fun(bt->lchild, bl, hl);
//		fun(bt->rchild, br, hr);
//		h = (hl > hr ? hl : hr) + 1; 
//		if (abs(hl - hr) < 2)
//			balance = bl && br;
//		else
//			balance = 0;
//	}
//}

int func(BTNode *root)//return返回的是树的深度
{
	if (root == NULL)
	{
		return 0;
	}
	int left = func(root->lchild);
	int right = func(root->rchild);
	//条件1\2 ------左右子树都不是平衡二叉树
	//条件3 ------两边的子树高度的绝对值大于1
	if (/*left == -1 || right == -1||*/abs(left-right)>1)//abs绝对值 
	{
		return -1;
	}
	else
	{
		return fmax(left, right) + 1;//如果是平衡二叉树 返回的是树的深度
	}
}


//int get_highg(BTNode* T)
//{
//	int left, right;
//	if (T == NULL)
//	{
//		return 0;
//	}
//	 left = get_highg(T->lchild) + 1;
//	 right = get_highg(T->rchild) + 1;
//	if (left > right)
//	{
//		return left + 1;
//	}
//	else {
//		return right + 1;
//	}
//
//}
//
//bool judge(BTNode* T)
//{
//	int left;
//	int right;
//	if (T == NULL)
//	{
//		return true;
//	}
//	else
//	{
//		left = get_highg(T->lchild);
//		right = get_highg(T->rchild);
//		if (abs(left - right) <= 1)
//		{
//			return judge(T->lchild) && judge(T->rchild);
//		}
//		else {
//			return false;
//		}
//	}
//}

int main()
{
	BTNode *T = bbbb();
	if (!func(T))
	{
		cout << "不是平衡二叉树";
	}
	else
	{
		cout << "是平衡二叉树";
	}


	return 0;
}

排序

链表头文件

#include <iostream>
using namespace std;
typedef struct LNode
{
	int data;
	struct LNode *next;
} LNode, *Linklist;

Linklist aaaa()
{
	LNode *L = new LNode; //创建一个头结点
	LNode *p = L;         //声明一个指针指向头结点,
	//生成链表
	int a;
	cin >> a;
	while (a != 0)
	{
		LNode *q = new LNode;
		q->data = a;
		q->next = NULL;
		p->next = q;
		p = p->next;
		cin >> a;
	}
	p->next = NULL;
	return L;
}

直接插入排序

#include <bits/stdc++.h>
#include"linklist.h"
using namespace std;
#define maxsize 50
/*
	直接插入排序 
	  //数组下标所对应的数
	    0 4 2 6 1 3     

		0 2 4 6 1 3
		0 2 4 6 1 3
		0 1 2 4 6 3 
		0 1 2 3 4 6

		空间复杂度:O(1)
		最好时间复杂度:12345678 需要n-1趟处理 O(n)
		最坏时间复杂度:87654321               O(n^2)
		平均时间复杂度:                       O(n^2)

		稳定
*/

//哨兵法
void InsertSort(int R[], int n)
{
	int i, j;
	for (i = 2; i <= n; ++i)
	{
		R[0] = R[i];
		for (j = i - 1; R[0] < R[j]; --j)
			R[j + 1] = R[j];
		R[j + 1] = R[0];
	}
} 

void linksort(LNode *&L)
{
	LNode *p = L->next;
	LNode *r = p->next;
	p->next = NULL;
	p = r;
	while (p != NULL)
	{
		r = p->next;
		LNode *pre = L;
		while (pre->next != NULL && pre->next->data < p->data)
			pre = pre->next;
		p->next = pre->next;
		pre->next = p;
		p = r;//p往后面移动
	}
}

// int main()
// {
//   int R[] = {-1, 8, 3, 6, 15, 2};
//   InsertSort(R, 5);
//   for (int i = 1; i < 6; i++)
//   {
//     cout << R[i] << ' ';
//   }
//   return 0;
// }

int main01()
{
	LNode *head = aaaa();
	linksort(head);
	LNode *p = head->next;
	while (p != NULL)
	{
		cout << p->data << " ";
		p = p->next;
	}
	return 0;
}

折半插入排序

#include <bits/stdc++.h>
using namespace std;
#define maxsize 50
/*
	折半插入排序
	  low         high i
	0  2  5  6  8  10  3  13 
*/
void BinInsert(int A[], int n)//n表示待排序元素的个数 
{
	int i, j;
	int low, high, mid;
	for (i = 2; i <= n; ++i)
	{
		A[0] = A[i];
		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循环后high和low的关系   :   high+1=low
		for (j = i - 1; j >= high + 1; --j)
			A[j + 1] = A[j];
		A[high + 1] = A[0];
	}
}
int main02()
{
	int A[] = { 0, 12, 6, 9, 2, -6 };
	//-6 2 6 9 12
	BinInsert(A, 5);
	for (int i = 1; i < 6; i++)
	{
		cout << A[i] << ' ';
	}
	return 0;
}

希尔排序

#include <bits/stdc++.h>
using namespace std;
#define maxsize 50
/*
	希尔排序  步长
	4 2 7 1 8 5 3 6  原数据
	4 2 3 1 8 5 7 6  步长为8/2=4   48 25 73 16 ----->48 25 37 16
	3 1 4 2 7 5 8 6  此时的步长为4/2=2  4387 2156----->3478 1256
	1 2 3 4 5 6 7 8  此时的步长为2/2=1  31427586----->12345678

	空间复杂度:0(1)
	时间复杂度:?????????? 0(n^1.3)~O(n^2)
*/
void shellsort(int arr[], int n)
{
	int temp;
	for (int gap = n / 2; gap > 0; gap /= 2)
	{
		for (int i = gap; i < n; ++i)
		{
			temp = arr[i];
			int j = i;
			//j>=gap条件是进行最后步长计算的时候跳出循环的条件
			while (j >= gap && arr[j - gap] > temp)
			{
				arr[j] = arr[j - gap];
				j -= gap;
			}
			arr[j] = temp;
			cout << endl;
		}
	}
}

int main03()
{
	int A[] = { 12, 6, 9, 2, 4 };
	shellsort(A, 5);
	for (int i = 0; i < 5; i++)
	{
		cout << A[i] << ' ';
	}
	return 0;
}

冒泡排序

#include <bits/stdc++.h>
using namespace std;
/*
	冒泡排序
	把最大的数往后丢
	4 2 7 1 5 3 6

	第一次:
	2 4 7 1 5 3 6
	2 4 7 1 5 3 6
	2 4 1 7 5 3 6
	2 4 1 5 7 3 6
	2 4 1 5 3 7 6
	2 4 1 5 3 6 7

	空间复杂度:O(1)
	时间复杂度:最好:12345678 比较次数n-1 交换次数0 1趟		 0(n)
	           最坏:87654321 比较次数=n(n-1)/2=交换次数 n趟 O(n^2)
			   平均:										 0(n^2)

	稳定的

*/
void Bubblesort(int R[], int n)
{
	int i, j, flag, temp;
	for (i = n - 1; i >= 1; --i)
	{
		flag = 0;
		for (j = 1; j <= i; ++j) {
			if (R[j - 1] > R[j])
			{
				temp = R[j];
				R[j] = R[j - 1];
				R[j - 1] = temp;
				flag = 1;
			}
		}
		if (flag == 0)
			return;
	}
}

int main04()
{
	int A[] = { 12, 6, 9, 2, 4 };
	Bubblesort(A, 5);
	for (int i = 0; i < 5; i++)
	{
		cout << A[i] << ' ';
	}
	return 0;
}

快速排序

#include <bits/stdc++.h>
using namespace std;
/*
	快速排序

	6 4 10 2 5 8 11
	low:6
	high:11
	1、先以6为基准元素用一个变量进行存储
	2、从右往左进行指针移动 如果小 与基准元素交换(其实是覆盖操作)
	3、交换后从左往右进行指针移动 如果大 与基准元素交换(……)

	
*/
int part(int A[], int low, int high)
{
	int pivot = A[low];
	while (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 = part(A, low, high);
		Quicksort(A, low, pivotpos - 1);//基准元素左边快排
		Quicksort(A, pivotpos + 1, high);//基准元素右边快排
	}
}

int main05()
{
	//int A[] = { 12, 6, 9, 2, 4 };
	//int A[] = { 14,28,17,9,7,21,13,4,11 };
	//int A[] = { 72,73,71,23,94,16,05,68 };
	int A[] = {05,16,23,68,71,72,96,73};
	Quicksort(A, 0, 7);
	for (int i = 0; i < 8; i++)
	{
		cout << A[i] << ' ';
	}
	return 0;
}
/* 
	初始序列: 
	49 38 65 97 76 13 27 49      

	第一次快排后:
	27 38 13 49 76 97 65 49    

	第二次快排后:
	13 27 38 49 49 65 76 97

	第三次快排后:
	13 27 38 49 49 65 76 97

	第四次快排后:
	13 27 38 49 49 65 76 97

	每一层的快排只需要处理待排序的元素 时间复杂度不会超过O(n)
	时间复杂度:O(n*递归层数)
	空间复杂度:O(递归层数)

			49

		27		76

	 13  38	   49  97

				65
	把n个元素组织成二叉树,二叉树的层数就是递归调用的层数
	而对于n个结点的二叉树 最小高度为=log2n向下取整+1
						   最大高度为=n
	最好的时间复杂度为:O(nlog2n)
	最坏的时间复杂度为:O(n^2)      12345678
	平均时间复杂度为:O(nlog2n)

	最好的空间复杂度为:O(log2n)
	最坏的空间复杂度为:O(n)

	2_ 2 1
	1  2 2_
	不稳定
*/

简单选择排序算法

#include <bits/stdc++.h>
using namespace std;
/*
	简单选择排序算法
	49 38 65 97 76 13 27 49

	13 38 65 97 76 49 27 49
	13 27 65 97 76 49 38 49
	13 27 38 97 76 49 65 49
	13 27 38 49 76 97 65 49
	13 27 38 49 49 97 65 76
	13 27 38 49 49 65 97 76
	13 27 38 49 49 65 76 97

	对n个元素进行简单选择排序需要n-1趟处理(不管顺序如何)
	总共需要对比关键字:n-1+n-2+……+1=n(n-1)/2次
	元素交换次数<n-1

	空间复杂度:O(1)
	时间复杂度:O(n^2)
	2 2_ 1
	1 2_ 2
	1 2_ 2
	因此简单选择排序是不稳定的算法

*/
void SelectSort(int R[], int n)
{
	int i, j, k, temp;
	for (i = 0; i < n; ++i)
	{
		k = i;
		for (j = i + 1; j < n; ++j)
		{
			if (R[k] > R[j])
			{
				k = j;//k指向的是整个数组中最小的数
			}
		}
		temp = R[i];
		R[i] = R[k];
		R[k] = temp;
	}
}
int main06()
{
	int A[] = { 12, 6, 9, 2, 4 };
	SelectSort(A, 5);
	for (int i = 0; i < 5; i++)
	{
		cout << A[i] << ' ';
	}
	return 0;
}

堆排序

#include <bits/stdc++.h>
using namespace std;
/*
	堆排序
	堆排序是选择排序
	8 10 5 3 21 7

	对于一棵完全二叉树
	树中父亲结点都比孩子结点小称为小根堆(小顶堆)
	树中父亲结点都比孩子结点大称为大根堆

	用数组实现
	二叉树一开始还不是堆,我们的首要目标是将其变成一个大顶堆。那么怎么将这棵二叉树变成一个大顶堆呢?
	1、从最后一个非叶子结点(从上往下的顺序)开始进行调整
	2、如果其孩子结点大于它,那么需要将最大的那个孩子交换上来
	3、如果其孩子结点小于它,那么不需要进行调整

	例:
				8
			
			10		5

		  3   21    7        

		5为该树的最后一个非叶子结点 看它的孩子结点 它的孩子结点比他大那么进行交换(7)

				8

			10		7

		  3   21    5
		
		10为该树的倒数第二个非叶子结点 10与21进行交换

				8

			21		7

		  3   10    5

		  最后看根节点 

				21

			8		7

		  3   10    5

				21

			10		7

		  3   8     5

		  建立完大顶堆后 让大顶(21)与最后一个叶子结点进行交换

				5

			10		7

		  3   8     21

		  然后对除了最后一个叶子结点的结点的树进行构造大顶堆 重复上述操作
		  最后建立的树为:
				3

			5		7

		  8  10		
		    
		  然后对它进行层次遍历就是堆排序的结果(3 5 7 8 10)
		  大顶堆对应的顺序是递增的
*/
void sift(int arr[], int low, int high)
{
	int i = low, j = 2 * i + 1;//j表示low的左子树
	int temp = arr[i];
	while (j <= high)
	{
		if (j < high && arr[j] < arr[j + 1])//找大的那个孩子进行比较
			++j;
		if (temp < arr[j])
		{
			arr[i] = arr[j];//覆盖操作
			i = j;
			j = 2 * i + 1;
		}
		else
			break;
	}
	arr[i] = temp;
}
/*
	堆排序顺序是先对左右子树进行堆排序 然后对根节点进行堆排序  
*/
void heapSort(int arr[], int n)
{
	//建立初始大根堆
	for (int i = n / 2 - 1; i >= 0; --i)//最后一个非叶子结点的个数=总结点的个数/2-1
		sift(arr, i, n - 1);
	
	for (int i = n - 1; i > 0; --i)
	{
		//将建立好的大根堆的根节点与最后一个叶子节点进行交换  对除了大根堆其它的元素进行建立大根堆操作
		int temp = arr[0];
		arr[0] = arr[i];
		arr[i] = temp;
		
		sift(arr, 0, i - 1);
	}
}
 

int main()
{
	//int A[] = { 12, 6, 9, 2, 4 };
	int A[] = { 10,27,5,50,60,7,40,43,75 };
	heapSort(A, 9);
	for (int i = 0; i < 9; i++)
	{
		cout << A[i] << ' ';
	}
	return 0;
}

/*
	如果一个结点的下方有两个孩子,则"下坠"一层,需要对比关键字2次
	如果一个结点的下方有两个孩子,则"下坠"一层,需要对比关键字1次
	若树高为h,某结点在第i层,则将这个结点向下调整最多只需要"下坠"h-i层,对比关键字的次数<=2(h-i)

	n个结点的完全二叉树树高h=log2n向下取整+1
	第i层最多有2^i-1个结点,而只有第1~(h-1)层的结点才有可能需要"下坠"

	第一层需要下坠的次数
	1*2*(h-1)
	第二层需要下坠的次数
	2*2*(h-2)
	综上所述:
	建堆的过程,关键字对比次数不超过4n,      建堆的时间复杂度=O(n)

	每一趟排序的复杂度不超过树的高度O(h)=O(log2n)
	总共n-1趟 总的时间复杂度O(nlog2n)
	空间复杂度:O(1)

	堆排序 如果左右孩子一样大,则优先和左孩子进行交换

	不稳定的算法
*/
   
//快希选一堆     不稳定

归并排序

#include <bits/stdc++.h>
using namespace std;
/*
	归并排序

	4 5 10 19 2 6 8 9

	i	                 j
	4  5  10  19         2  6  8  9
*/

//将两个小的递增序列合并成大的递增序列
void fun(int A[], int low, int mid, int high)//low的初值为0 high的初值为n-1   
{
	int *B = new int[high - low + 1];//新建一个B的数组  空间
	int i = low, j = mid + 1;
	for (int k = low; k <= high; ++k)
		B[k] = A[k];
	int k = i;
	for (i = low; i <= mid && j <= high; ++k)
	{
		if (B[i] <= B[j])
			A[k] = B[i++];
		else
			A[k] = B[j++]; 
	}
	while (j <= high)
		A[k++] = B[j++];
	while (i <= mid)
		A[k++] = B[i++];
}  
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);
		fun(A, low, mid, high);
	}
}
int main08()
{
	int A[] = { 12, 6, 9, 2, 4 };
	MergeSort(A, 0, 4);
	for (int i = 0; i < 5; i++)
	{
		cout << A[i] << ' ';
	}
	return 0;
}

/*
	二路归并:
	初始序列:
	49 38 65 97 76 13 27

	一趟归并:
	38 49 65 97 13 76 27

	二趟归并:
	38 49 65 97 13 27 76

	三趟归并:
	13 27 38 49 65 76 97
	
	2路归并的“归并树”一一形态上就是一棵倒立的二叉树

	假设树高为h 那么归并排序的趟数就是h-1
	二叉树的第h层最多有2^h-1个结点
	若树高为h,则满足n<=2^h-1
	即h-1=log2n 向上取整

	结论:n个元素进行2路归并排序,归并趟数=log2n向上取整       对于N个元素进行k路归并排序,排序趟数m=logkN向上取整
    每趟归并时间复杂度为O(n),则算法
    时间复杂度为O(nlog2n)
	空间复杂度为O(n)

	稳定的
	12  13	12	15   
	12  12  13  15
*/

基数排序

/*
	
	基数排序

	链表+链式队列数组来实现

	520  211  438  888  007  111  985  666  996  233  168

	1、以个位进行分配
	Q9   Q8   Q7   Q6   Q5   Q4   Q3   Q2   Q1   Q0        由上到下
		 438  007  666  985       233       211  520		队头
		 888       996                      111
		 168
															队尾
	
	第一趟收集后,得到了按照"个位"递减排序的序列
	438  888  168  007  666  996  985  233  211  111  520

	2、以十位进行分配
	以第一趟收集后的序列进行十位的分配 即
	438  888  168  007  666  996  985  233  211  111  520

	Q9   Q8   Q7   Q6   Q5   Q4   Q3   Q2   Q1   Q0       由上到下
    996  888       168            438  520  211  007       队头
		 985	   666            233       111

															队尾

    第二趟收集结束:得到按"十位"递减排序的序列,"十位"相同的按"个位"递减排序
	996  888  985  168  666  438  233  520  211  111  007

	3、以百位进分配
	……………………………………………………………………
	……………………………………………………………………

	最终会得到递减的下序列

	
	r指 关键字位取值  d指 数能被拆分几个部分(例如888可以被拆分3个部分 即个位十位百位)
	假设序列有n个数
	把序列都扫一遍需要O(n)的时间复杂度
	而且总共有r个队列 收集一个队列的时间复杂度位O(1)
	收集r个队列需要O(r)的时间复杂度



	因此
	空间复杂度:O(r)     需要r个辅助队列来实现
	时间复杂度为:O(d(n+r))

	12 12
	分配的时候也是12 12
	因此基数排序是稳定的算法
	
	擅长处理 d较小
		     r较小
			 n较大

	MSD 百位开始-----个位结束
	LSD 个位开始-----百位结束
*/
  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值