动态数组实现顺序表,折半查找,二叉排序树建树,删除

数据结构的学习笔记

目录

1.用动态数组实现顺序表

2.折半查找

3.二叉排序树建树

4.二叉排序树删除


1.用动态数组实现顺序表

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//用动态数组实现顺序表

typedef int ElemType;

//顺序表
typedef struct SqList {
	ElemType* data;//指针,指向一块内存的起始地址
	int length;//存储动态数组的长度
}SqList;

//顺序表初始化
void initSqList(SqList& L, int len) {
	L.length = len;
	L.data = (ElemType*)malloc(sizeof(ElemType) * L.length);//分配空间
	srand(time(NULL));//随机数生成
	for (int i = 0; i < L.length; i++)
	{
		L.data[i] = rand() % 100;//随机生成数字存入顺序表,对100取余是为了规范存入的数据是0-99
	}
}

//顺序表打印
void printSqList(SqList L) {
	for (int i = 0; i < L.length; i++)
	{
		printf("%3d", L.data[i]);
	}
	printf("\n");
}

//顺序查找顺序表中的元素
int searchElemInSqList(SqList L, ElemType e) {
	int i;
	for (i = 0; i < L.length; i++) {
		if (L.data[i] == e)
		{
			break;
		}
	}
	return i + 1;//返回的位置刚好是下标对应的位置
}

int main() {
	SqList L;//定义一个顺序表
	initSqList(L, 10);//初始化顺序表,分配10个空间
	printSqList(L);//打印顺序表中的值
	ElemType e;//需要查询的元素
	printf("请输入要搜索的元素值:");
	scanf_s("%d", &e);
	int pos;//存储查询元素的位置
	pos = searchElemInSqList(L, e);//查询元素
	if (pos)
	{
		printf("查找成功,位置为:%d\n", pos);
	}
	else
	{
		printf("查找失败\n");
	}
	return 0;
}

这段代码实现了使用动态数组来创建和操作顺序表的功能,包括顺序表的初始化、打印,以及顺序查找功能。代码的功能和执行步骤如下:

1. 定义顺序表结构体

  • 定义了一个结构体 SqList,包含了一个指针 data,用于指向动态分配的内存空间,用于存储顺序表中的元素;另一个成员变量 length 用于表示顺序表的当前长度。

2. 顺序表初始化函数

  • initSqList(SqList& L, int len) 函数用于初始化顺序表。它的步骤包括:
    • 设置顺序表的长度 length 为用户指定的长度 len
    • 使用 malloc 函数为顺序表的 data 指针分配内存空间,以存储顺序表中的元素。
    • 使用 srand(time(NULL)) 初始化随机数生成器。
    • 通过 rand() 函数生成随机数,并将其对 100 取余后的值(0-99)存入顺序表。

3. 顺序表打印函数

  • printSqList(SqList L) 函数用于打印顺序表中的所有元素。
    • 使用循环遍历顺序表的 data 数组,将每个元素按顺序输出到控制台。

4. 顺序查找函数

  • searchElemInSqList(SqList L, ElemType e) 函数用于在顺序表中查找指定的元素 e
    • 该函数通过遍历顺序表中的每个元素,如果找到匹配的元素,则返回其位置(下标加 1),如果没有找到,则返回 L.length + 1,即大于顺序表长度的位置。

5. 主函数

  • main() 函数是程序的入口,包含以下步骤:
    • 定义一个顺序表 L
    • 调用 initSqList(L, 10) 函数,初始化顺序表,并为其分配 10 个元素空间。
    • 使用 printSqList(L) 函数打印顺序表中的所有元素。
    • 通过控制台输入用户需要查找的元素值,并存储在 e 变量中。
    • 调用 searchElemInSqList(L, e) 函数查找该元素,并返回其在顺序表中的位置 pos
    • 根据查找结果,输出成功或失败的消息。

总结

这段代码通过动态内存分配,实现了一个简单的顺序表操作,并具备随机初始化、打印及顺序查找的功能。用户可以通过输入一个数字,查看其在顺序表中的位置。

2.折半查找

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

//用动态数组实现顺序表

typedef int ElemType;

//顺序表
typedef struct SqList {
	ElemType* data;//指针,指向一块内存的起始地址
	int length;//存储动态数组的长度
}SqList;

//顺序表初始化
void initSqList(SqList& L, int len) {
	L.length = len;
	L.data = (ElemType*)malloc(sizeof(ElemType) * L.length);//分配空间
	
	for (int i = 0; i < L.length; i++)
	{
		L.data[i] = i + 1;//从小到大放入一些数据
	}
}

//顺序表打印
void printSqList(SqList L) {
	for (int i = 0; i < L.length; i++)
	{
		printf("%3d", L.data[i]);
	}
	printf("\n");
}

//顺序查找顺序表中的元素
int searchElemInSqList(SqList L, ElemType e) {
	int i;
	for (i = 0; i < L.length; i++) {
		if (L.data[i] == e)
		{
			return i + 1;//返回的位置刚好是下标对应的位置
		}
	}
	return -1;//查找失败
}

//折半查找
int binarySearch(SqList L, ElemType e) {
	int low = 0, high = L.length - 1;//指向第一个结点和最后一个结点
	int mid;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (L.data[mid] == e) {
			return mid + 1;//返回的是位置,下标+1
		}
		else if (L.data[mid] < e) {
			low = mid + 1;
		}
		else
		{
			high = mid - 1;
		}
	}
	return -1;//查找失败
}

//折半查找顺序表中的元素

int main() {
	SqList L;//定义一个顺序表
	initSqList(L, 10);//初始化顺序表,分配10个空间
	printSqList(L);//打印顺序表中的值
	ElemType e;//需要查询的元素
	printf("请输入要搜索的元素值:");
	scanf_s("%d", &e);
	int pos;//存储查询元素的位置
	//pos = searchElemInSqList(L, e);//顺序查询元素
	pos = binarySearch(L, e);//折半查询元素
	if (pos != -1)
	{
		printf("查找成功,位置为:%d\n", pos);
	}
	else
	{
		printf("查找失败\n");
	}
	return 0;
}

这段代码实现了使用动态数组来创建和操作顺序表的功能,包含顺序表的初始化、打印、顺序查找和折半查找。代码的功能和执行步骤如下:

1. 定义顺序表结构体

  • 定义了一个结构体 SqList,包含一个指针 data,指向动态分配的内存空间,用于存储顺序表中的元素;另一个成员变量 length 用于表示顺序表的当前长度。

2. 顺序表初始化函数

  • initSqList(SqList& L, int len) 函数用于初始化顺序表。它的步骤包括:
    • 设置顺序表的长度 length 为用户指定的长度 len
    • 使用 malloc 函数为顺序表的 data 指针分配内存空间,以存储顺序表中的元素。
    • 将顺序表中的数据从 1 开始按顺序填充,即 L.data[i] = i + 1

3. 顺序表打印函数

  • printSqList(SqList L) 函数用于打印顺序表中的所有元素。
    • 使用循环遍历顺序表的 data 数组,将每个元素按顺序输出到控制台。

4. 顺序查找函数

  • searchElemInSqList(SqList L, ElemType e) 函数用于在顺序表中顺序查找指定的元素 e
    • 通过遍历顺序表中的每个元素,如果找到匹配的元素,则返回其位置(下标加 1),如果没有找到,则返回 -1

5. 折半查找函数

  • binarySearch(SqList L, ElemType e) 函数用于在顺序表中使用折半查找(即二分查找)来查找指定的元素 e。前提是顺序表中的数据必须是有序的。
    • 初始化 lowhigh 指针分别指向顺序表的第一个和最后一个元素。
    • 使用 while 循环进行查找,每次通过计算中间位置 mid 来比较目标元素 e 与中间元素 L.data[mid] 的大小关系:
      • 如果 L.data[mid] 等于 e,则返回位置(下标加 1)。
      • 如果 L.data[mid] 小于 e,则调整 low 指针。
      • 如果 L.data[mid] 大于 e,则调整 high 指针。
    • 如果查找失败,返回 -1

6. 主函数

  • main() 函数是程序的入口,包含以下步骤:
    • 定义一个顺序表 L
    • 调用 initSqList(L, 10) 函数,初始化顺序表,并为其分配 10 个元素空间。
    • 使用 printSqList(L) 函数打印顺序表中的所有元素。
    • 通过控制台输入用户需要查找的元素值,并存储在 e 变量中。
    • 使用 binarySearch(L, e) 函数在顺序表中进行折半查找,并返回元素的位置 pos
    • 根据查找结果,输出成功或失败的消息。

总结

这段代码通过动态内存分配实现了一个简单的顺序表操作,并具备初始化、打印、顺序查找和折半查找的功能。特别注意的是,在使用折半查找之前,顺序表中的数据必须是有序的。

3.二叉排序树建树

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

// 二叉排序树建树

typedef int KeyType;

typedef struct BSTNode {
	KeyType key;
	struct BSTNode* lchild, * rchild;
}BSTNode, * BSTree;

//排序二叉树插入结点(非递归)
int BSTInsert(BSTree& T, KeyType key) {
	BSTNode* newNode = (BSTNode*)calloc(1, sizeof(BSTNode)); //为新结点分配空间
	newNode->key = key;
	if (T == NULL) { //树为空,新结点作为树的根
		T = newNode;
		return 1; //插入成功
	}
	BSTNode* p, * parent; //p用来查找树结点,parent用来保存其父亲
	p = parent = T; //从树根开始查
	while (p)
	{
		parent = p;
		if (key < p->key) //key小于当前结点的值,进入左孩子
		{
			p = p->lchild;
		}
		else if (key > p->key) //key大于当前结点的值,进入右孩子
		{
			p = p->rchild;
		}
		else //key等于当前元素的值,不插入
		{
			return 0;
		}
	}
	if (key < parent->key)
	{
		parent->lchild = newNode; //新结点作为父亲的左孩子
	}
	else
	{
		parent->rchild = newNode; //新结点作为父亲的右孩子
	}
	return 1; //插入成功
}

//排序二叉树插入结点(递归)
int BSTInsert2(BSTree& T, KeyType key) {
	if (T == NULL)
	{	//给新结点分配空间,树为空,新结点作为树的根
		T = (BSTree)calloc(1, sizeof(BSTNode));
		T->key = key;
		return 1; //插入成功
	}
	if (key == T->key) //相同元素,不插入
		return 0;
	else if (key < T->key)//key小于当前结点的值
		return BSTInsert2(T->lchild, key);
	else
		return BSTInsert2(T->rchild, key);
}

//创建二叉排序树
void createBST(BSTree& T, KeyType* arr, int len) {
	int i;
	for (i = 0; i < len; i++)//把结点一个一个的放进二叉排序树
	{
		BSTInsert2(T, arr[i]);
	}
}

// 查找结点
bool BSTSearch(BSTree T, KeyType key, BSTNode*& search, BSTNode*& parent) {
	while (T != NULL && T->key != key)
	{
		parent = T; //获取查找结点的父结点
		if (key < T->key) {
			T = T->lchild;
		}
		else
		{
			T = T->rchild;
		}
	}
	search = T; //获取查找到的树结点
	if (search == NULL) //查找失败search一定等于NULL
	{
		return false;
	}
	return true;
}

//中序遍历,用来验证二叉排序树是否建立正确
void midOrder(BSTree T) {
	if (T)
	{
		midOrder(T->lchild);
		printf("%3d", T->key);
		midOrder(T->rchild);
	}
}

int main() {
	BSTree bst = NULL; //定义二叉排序树
	KeyType arr[7] = { 48,14,60,34,22,73,52 }; //将要放入二叉排序树的元素
	createBST(bst, arr, 7); //建立二叉排序树
	midOrder(bst); //中序遍历二叉排序树
	printf("\n");
	BSTNode* search = NULL, * parent = NULL;
	bool result;
	result = BSTSearch(bst, 48, search, parent);
	if (result)
	{
		printf("%d查找成功\n", search->key);
	}
	else
	{
		printf("查找失败\n");
	}
	return 0;
}

这段代码实现了二叉排序树(Binary Search Tree, BST)的基本操作,包括插入节点、查找节点和中序遍历。代码的功能和执行步骤如下:

1. 定义二叉排序树节点结构体

  • 定义了一个结构体 BSTNode,包含以下成员:
    • key:存储节点的关键值。
    • lchildrchild:指向左右子节点的指针。
  • BSTreeBSTNode* 的别名,表示树的根节点。

2. 排序二叉树插入节点(非递归)

  • BSTInsert(BSTree& T, KeyType key) 函数用于在二叉排序树中插入一个新的节点。步骤包括:
    • 为新节点分配内存,并设置其 key 值。
    • 如果树为空,新节点作为树的根节点。
    • 否则,从根节点开始查找合适的位置,将新节点插入到正确的位置。
    • 如果找到相同的关键值,则不插入节点。
    • 根据新节点的值决定将其插入到父节点的左子树还是右子树。

3. 排序二叉树插入节点(递归)

  • BSTInsert2(BSTree& T, KeyType key) 函数用于在二叉排序树中递归插入一个新的节点。步骤包括:
    • 如果树为空,新节点作为树的根节点。
    • 如果关键值与当前节点相同,则不插入。
    • 根据关键值的大小,递归地在左子树或右子树中插入新节点。

4. 创建二叉排序树

  • createBST(BSTree& T, KeyType* arr, int len) 函数用于从数组中创建一个二叉排序树。步骤包括:
    • 遍历数组中的每个元素,使用 BSTInsert2 函数将元素插入到树中。

5. 查找节点

  • BSTSearch(BSTree T, KeyType key, BSTNode*& search, BSTNode*& parent) 函数用于在二叉排序树中查找指定的节点。步骤包括:
    • 从树的根节点开始查找,更新 parent 指针以记录当前节点的父节点。
    • 如果找到匹配的节点,设置 search 指针指向该节点。
    • 如果未找到节点,search 将为 NULL,函数返回 false

6. 中序遍历

  • midOrder(BSTree T) 函数用于中序遍历二叉排序树。步骤包括:
    • 递归遍历左子树,打印当前节点的关键值,然后递归遍历右子树。
    • 中序遍历可以验证二叉排序树的节点是否按顺序排列。

7. 主函数

  • main() 函数是程序的入口,包含以下步骤:
    • 定义一个空的二叉排序树 bst
    • 定义一个数组 arr,包含要插入到二叉排序树中的元素。
    • 调用 createBST(bst, arr, 7) 函数创建二叉排序树。
    • 使用 midOrder(bst) 函数打印中序遍历的结果,以验证树的正确性。
    • 查找关键值为 48 的节点,并输出查找结果。

总结

这段代码实现了一个简单的二叉排序树的构建、节点插入、节点查找和中序遍历功能。二叉排序树的插入操作可以通过递归或非递归方式实现,查找操作通过中序遍历可以验证树的结构。

4.二叉排序树删除

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

// 二叉排序树建树

typedef int KeyType;

typedef struct BSTNode {
	KeyType key;
	struct BSTNode* lchild, * rchild;
}BSTNode, * BSTree;

//排序二叉树插入结点(非递归)
int BSTInsert(BSTree& T, KeyType key) {
	BSTNode* newNode = (BSTNode*)calloc(1, sizeof(BSTNode)); //为新结点分配空间
	newNode->key = key;
	if (T == NULL) { //树为空,新结点作为树的根
		T = newNode;
		return 1; //插入成功
	}
	BSTNode* p, * parent; //p用来查找树结点,parent用来保存其父亲
	p = parent = T; //从树根开始查
	while (p)
	{
		parent = p;
		if (key < p->key) //key小于当前结点的值,进入左孩子
		{
			p = p->lchild;
		}
		else if (key > p->key) //key大于当前结点的值,进入右孩子
		{
			p = p->rchild;
		}
		else //key等于当前元素的值,不插入
		{
			return 0;
		}
	}
	if (key < parent->key)
	{
		parent->lchild = newNode; //新结点作为父亲的左孩子
	}
	else
	{
		parent->rchild = newNode; //新结点作为父亲的右孩子
	}
	return 1; //插入成功
}

//排序二叉树插入结点(递归)
int BSTInsert2(BSTree& T, KeyType key) {
	if (T == NULL)
	{	//给新结点分配空间,树为空,新结点作为树的根
		T = (BSTree)calloc(1, sizeof(BSTNode));
		T->key = key;
		return 1; //插入成功
	}
	if (key == T->key) //相同元素,不插入
		return 0;
	else if (key < T->key)//key小于当前结点的值
		return BSTInsert2(T->lchild, key);
	else
		return BSTInsert2(T->rchild, key);
}

//创建二叉排序树
void createBST(BSTree& T, KeyType* arr, int len) {
	int i;
	for (i = 0; i < len; i++)//把结点一个一个的放进二叉排序树
	{
		BSTInsert2(T, arr[i]);
	}
}

// 查找结点
bool BSTSearch(BSTree T, KeyType key, BSTNode*& search, BSTNode*& parent) {
	while (T != NULL && T->key != key)
	{
		parent = T; //获取查找结点的父结点
		if (key < T->key) {
			T = T->lchild;
		}
		else
		{
			T = T->rchild;
		}
	}
	search = T; //获取查找到的树结点
	if (search == NULL) //查找失败search一定等于NULL
	{
		return false;
	}
	return true;
}

// 删除二叉排序树的结点
bool deleteBSTNode(BSTree& T, KeyType key) {
	if (T == NULL) {
		return false;
	}
	if (key < T->key) { //key小于当前树结点的值,往左子树找
		deleteBSTNode(T->lchild, key);
	}
	else if (key > T->key) { //key大于当前树结点的值,往右子树找
		deleteBSTNode(T->rchild, key);
	}
	else { //相等,找到要删除的结点
		if (T->lchild == NULL) { //要删除的结点左子树为空,右子树直接顶上去
			BSTNode* tempNode = T; //存放要删除的结点
			T = T->rchild; //右子树顶上去
			free(tempNode); //释放要删除结点的空间
			return true;
		}
		else if (T->rchild == NULL) { //要删除的结点右子树为空,左子树直接顶上去
			BSTNode* tempNode = T; //存放要删除的结点
			T = T->lchild; //左子树顶上去
			free(tempNode); //释放要删除结点的空间
			return true;
		}
		else { //要删除的结点左右子树都不为空
			   //一般的删除策略是用左子树的最大数据(最右结点) 或 右子树的最小数据代替
			   //这里采用查找左子树最大数据来代替
			BSTNode* tempNode = T->lchild; //保存要删除结点的左子树
			while (tempNode->rchild != NULL) //循环找到左子树最右结点
			{
				tempNode = tempNode->rchild;
			}
			T->key = tempNode->key; //将左子树最右结点的值赋给要删除的结点
			deleteBSTNode(T->lchild, tempNode->key); //递归删除左子树的最右结点
			return true;
		}
	}
}

//中序遍历,用来验证二叉排序树是否建立正确
void midOrder(BSTree T) {
	if (T)
	{
		midOrder(T->lchild);
		printf("%3d", T->key);
		midOrder(T->rchild);
	}
}

int main() {
	BSTree bst = NULL; //定义二叉排序树
	KeyType arr[7] = { 48,14,60,34,22,73,52 }; //将要放入二叉排序树的元素
	createBST(bst, arr, 7); //建立二叉排序树
	midOrder(bst); //中序遍历二叉排序树
	printf("\n");
	BSTNode* search = NULL, * parent = NULL;
	bool result;
	result = BSTSearch(bst, 48, search, parent);
	if (result)
	{
		printf("%d查找成功\n", search->key);
	}
	else
	{
		printf("查找失败\n");
	}
	
	result = deleteBSTNode(bst, 34);
	if (result)
	{
		printf("删除成功\n");
	}
	else
	{
		printf("删除失败\n");
	}
	midOrder(bst);
	return 0;
}

这段代码实现了一个二叉排序树(Binary Search Tree, BST)的基本操作,包括节点插入、查找、删除和中序遍历。代码的功能和执行步骤如下:

1. 定义二叉排序树节点结构体

  • BSTNode 结构体定义了二叉排序树的节点,包含以下成员:
    • key:存储节点的关键值。
    • lchildrchild:指向左子节点和右子节点的指针。
  • BSTreeBSTNode* 的别名,表示树的根节点。

2. 排序二叉树插入节点(非递归)

  • BSTInsert(BSTree& T, KeyType key) 函数用于在二叉排序树中插入一个新的节点。步骤包括:
    • 为新节点分配内存,并设置其 key 值。
    • 如果树为空,新节点作为树的根节点。
    • 否则,从根节点开始查找合适的位置,将新节点插入到正确的位置。
    • 如果找到相同的关键值,则不插入节点。
    • 根据新节点的值决定将其插入到父节点的左子树还是右子树。

3. 排序二叉树插入节点(递归)

  • BSTInsert2(BSTree& T, KeyType key) 函数用于在二叉排序树中递归插入一个新的节点。步骤包括:
    • 如果树为空,新节点作为树的根节点。
    • 如果关键值与当前节点相同,则不插入。
    • 根据关键值的大小,递归地在左子树或右子树中插入新节点。

4. 创建二叉排序树

  • createBST(BSTree& T, KeyType* arr, int len) 函数用于从数组中创建一个二叉排序树。步骤包括:
    • 遍历数组中的每个元素,使用 BSTInsert2 函数将元素插入到树中。

5. 查找节点

  • BSTSearch(BSTree T, KeyType key, BSTNode*& search, BSTNode*& parent) 函数用于在二叉排序树中查找指定的节点。步骤包括:
    • 从树的根节点开始查找,更新 parent 指针以记录当前节点的父节点。
    • 如果找到匹配的节点,设置 search 指针指向该节点。
    • 如果未找到节点,search 将为 NULL,函数返回 false

6. 删除节点

  • deleteBSTNode(BSTree& T, KeyType key) 函数用于删除二叉排序树中的指定节点。步骤包括:
    • 如果树为空,返回删除失败。
    • 如果关键值小于当前节点的值,递归删除左子树中的节点。
    • 如果关键值大于当前节点的值,递归删除右子树中的节点。
    • 如果找到要删除的节点,处理删除操作:
      • 如果要删除的节点没有左子树,将右子树顶替到要删除节点的位置。
      • 如果要删除的节点没有右子树,将左子树顶替到要删除节点的位置。
      • 如果要删除的节点有左右子树,找到左子树中的最大节点(最右节点),用其值替代要删除的节点,并递归删除该最大节点。

7. 中序遍历

  • midOrder(BSTree T) 函数用于中序遍历二叉排序树。步骤包括:
    • 递归遍历左子树,打印当前节点的关键值,然后递归遍历右子树。
    • 中序遍历可以验证二叉排序树的节点是否按顺序排列。

8. 主函数

  • main() 函数是程序的入口,包含以下步骤:
    • 定义一个空的二叉排序树 bst
    • 定义一个数组 arr,包含要插入到二叉排序树中的元素。
    • 调用 createBST(bst, arr, 7) 函数创建二叉排序树。
    • 使用 midOrder(bst) 函数打印中序遍历的结果,以验证树的正确性。
    • 查找关键值为 48 的节点,并输出查找结果。
    • 删除关键值为 34 的节点,并输出删除结果。
    • 再次使用 midOrder(bst) 函数打印中序遍历的结果,验证删除操作的正确性。

总结

这段代码实现了二叉排序树的基本操作,包括节点的插入、查找、删除和中序遍历。通过这些操作,可以创建一个二叉排序树,维护树的结构,并执行基本的树操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

juechen333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值