减治法实现插入排序,减治法实现二叉查找树(二叉搜索数,二叉排序数)的创建、插入与查找(含解析与代码实现)

 🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨,经典算法的解析✨都在这儿,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏

🪔本系列专栏 -  数据结构与算法_勾栏听曲_0

🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️

📌个人主页 - 勾栏听曲_0的博客📝

🔑希望本文能对你有所帮助,如有不足请指正,共同进步吧🏆

🎇非淡泊无以明志,非宁静无以致远。📈

减治法

⚫ 减治技术:利用一个问题给定实例的解与同样问题较小实例的解之间的某种关系,可将原问题从顶至下,或从底至上地解决。从顶至下导致递归算法,从底至上导致增量法(注:从求解问题的一个较小实例开始,迭代实现,往往要好于递归)。

⚫减治法的三种变化形式:减去一个常量、减去一个常量因子、减去的规模可变。

        减常量:每次迭代总是从实例中减去一个相同的常量(一般来说,这个常量为1)。
                例如,计算a"的值,f(n)=a"

                 乘法为基本操作,上述减常量算法时间效率为O(n)。
                

        减常因子:每次迭代总是从实例的规模中减去一个相同的常数因子(一般来说,这个常数因子为2)。

                和上述同样的例子,计算a"的值,f(n)=a"
                乘法为基本操作,上述减常因子算法效率为O(log n)。

        减可变规模: 算法在每次迭代时,规模减小的模式可变。例如,欧几里得算法:

gcd(m,n) = gcd(n,m mod n)

插入排序

        减治法最典型的案例之一便是插入排序。

        插入排序思想:假设较小数组A[O..n-2]已排序好,为了得到一个大小为n的有序数组,在A[0..n-2]中找到一个合适位置,将A[n-1]插入该位置。迭代实现的插入排序伪代码如下:

InsertionSort(A[O..n-1])
//用插入排序对给定数组排序
//输入:n个可排序元素构成的一个数组A[0..n一1]

//输出:非降序排列的数组A[0..n一1]
for i <- 1 to n-1 do

        v <- A[i]
        j <- i-1
        while j ≥ 0 and A[j] > v  do

                A[j + 1] <- A[j]
                j <- j-1
                A[j + 1] <- v

        例子:对数组89,45,68,90,29,34,17排序:

        视频演示:

插入排序

        代码实现:

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

void insort(int *a,int n)
{
	printf("排序前为:");
	for(int i = 0; i < n;i++)
		printf("%d ",*(a + i));
	}
	for(int i = 1; i < n;i++)
	{
		for(int j = i-1;j >= 0;j--)
		{
			if(*(a+j+1) < *(a+j))		//如果前面的数比后面大,就交换
			{
				int t = *(a+j+1);
				*(a+j+1) = *(a+j); 
				*(a+j) = t;
			}
		}
		printf("\n排序中:");			//显示每循环一次之后的排序结果
		for(int i = 0; i < n;i++)
		{
			printf("%d ",*(a + i));
		}
	}
	printf("\n排序后为:");
	for(int i = 0; i < n;i++)
	{
		printf("%d ",*(a + i));
	}
	printf("\n");
}


int main(int argc,char * argv[])
{
	int *str = NULL;	//存储要排序的数组
	int n;				//存储排序数组个数
	printf("请输入要排序的个数:");
	scanf("%d",&n);
	str = (int *)malloc(n * sizeof(int));	//获取个数后,给str分配空间
	printf("请输入要排序的数据(以空格隔开):");
	for(int i = 0; i < n;i++)				//循环将数据写入str中
	{
		scanf("%d",(str + i));
	}

	insort( str , n);		//调用排序算法
}

二叉查找数

        二叉树的节点包含排序项集合的元素,每个节点一个元素,对于每个节点,其所有左子树的元素都小于这个节点,其所有右子树的元素都大于这个节点。
        二叉查找树查找一个键值v的过程:将v与树的根节点进行比较,若相等,直接返回,若小于,在左子树中继续查找,若大于,在右子树中继续查找。
        算法的每次迭代,都简化为在一棵更小的二叉查找子树中查找(注:由于子树的高度是不一样的,因此,每次减少的规模可能是不一样的)。

        在二叉查找树中查找与插入键具有相等的时间效率。最坏时间效率为0(n)(例如:当连续插入的键是一个递增或递减序列时),平均时间效率为0(log n)。

        创建

        算法思路:

二叉排序树的创建过程,实际上就是把一个结点加入到一颗二叉排序数中,并且保证其二叉排序性过程。
        不断重复二叉排序树的插入操作。
        二叉排序树的插入操作:
                1.找插入位置
                2.执行插入操作

/* 
create_sotr_tree:创建一颗二叉排序树
	返回值:
		二叉排序树的根节点指针
 */
BiTNode *create_sort_tree()
{
    //保存根结点的指针
    BiTNode *r = NULL;
    //step1 从键盘上获取数据
    int i = 0;
    char str[64] = {0};
    //gets(str);
	/*for(int i = 0;i<64;i++)
	{
		scanf("%s",&str[i]);
		if(str[i] == '0')
			break;
	}*/
	scanf("%s",str);
    while(str[i])
    {
        //step2 创建新的数据结点 并且把数据写进去
        BiTNode *pnew = malloc(sizeof(*pnew));
        pnew->data = str[i];
        pnew->lchild = NULL;
        pnew->rchild = NULL;
        r = inset_node(r,pnew);
        i++;
    }
    return r;
}

        插入与删除节点

        插入与删除都有多种情况需要考虑

插入

        二叉数是空数

        遍历找到应该挂的位置,子树为空时挂上去

删除

        删除的是叶子节点,直接删除

        删除的节点有右子树

        删除的节点有左子树

        删除的节点有左右子树

//在一棵二叉排序树中增加结点
BiTNode *inset_node(BiTNode *r, BiTNode *pnew)
{
    BiTNode *p = r;//遍历指针 用来查找挂结点的位置
    if(r == NULL)//从无到有  这棵树是一颗空树 那么新插入的结点就是数本身
    {
        return pnew;
    }
    if(pnew == NULL)
    {
        return r;
    }
    while(1)
    {
        if(pnew->data < p->data)
        {
            if(p->lchild == NULL)//如果p左孩子为空 直接挂上去
            {
                p->lchild = pnew;
                break;
            }
            p = p->lchild;
        }
        else if(pnew->data > p->data)
        {
            if(p->rchild == NULL)//如果p右孩子为空 直接挂上去
            {
                p->rchild = pnew;
                break;
            }
            p = p->rchild;
        }
        else
        {
            printf("data repeated\n");
            break;
        }

    }
    return r;
}


BiTNode *delete_node(BiTNode *r,u4 x)
{
	//step1 找到要删除的节点px,以及他的父节点pf
	BiTNode *px = r;
	BiTNode *pf = NULL;
	while(px)
	{
		if(px->data == x+48)
		{
			break;
		}
		else if(px->data > x)
		{
			pf = px;	//确保pf指向px 的父节点
			px = px->lchild;
		}
		else 	//px->data < x
		{
			pf = px;
			px = px->rchild;
		}
	}
	if(px == NULL)
	{
		return r;
	}

	//分情况删除
	if(px == r && px->lchild == NULL && px->rchild == NULL)	//根节点且左右节点都为空
	{
		free(r);
		printf("删除节点后,树为空!\n");
		return NULL;
	}
	else if(px == r && px->lchild == NULL)	//根节点且左节点为空
	{
		r = r->rchild;
		free(px);
	}
	else if(px == r && px->rchild == NULL)	//根节点且右节点为空
	{
		r = r->lchild;
		free(px);
	}
	else if(px->lchild == NULL && px->rchild == NULL)	//为叶子节点
	{
		if(pf->lchild == px)
		{
			pf->lchild = NULL;
			free(px);
		}
		else
		{
			pf->rchild = NULL;
			free(px);
		}
	}
	else if(px->lchild != NULL && px->rchild == NULL)	//只有右孩子
	{
		if(pf->lchild == px)
		{
			pf->lchild = px->lchild;
			px->lchild = NULL;
			free(px);
		}
		else
		{
			pf->rchild = px->lchild;
			px->lchild = NULL;
			free(px);
		}
	}
	else if(px->lchild == NULL && px->rchild != NULL)	//只有左孩子
	{
		if(pf->lchild == px)
		{
			pf->lchild = px->rchild;
			px->rchild = NULL;
			free(px);
		}
		else
		{
			pf->rchild = px->rchild;
			px->rchild = NULL;
			free(px);
		}
	}
	else	//px->lchild != NULL && px->rchild != NULL	//有两个度的节点
	{
		BiTNode *p = px;
		BiTNode *pre = NULL;
		p = p->rchild;
		while(p->lchild)
		{
			pre = p;
			p = p->lchild;
		}
		px->data = p->data;
		pre->lchild = NULL;
		free(p);
	}
	return r;
}

        查找

/*在一棵二叉排序树中查找节点值
	参数:
		@BiTNode *r:传入的二叉排序数
		@int n:要查找的数
	返回值:
		char *:返回这个值在树中的顺序(如“01101”,左0右1)
*/
char *Find_node(BiTNode *r, int n)
{
    BiTNode *p = r;			//遍历指针 用来查找结点的位置
    char *str = NULL;		//用来记录查找时的顺序
	str = (char *)malloc(sizeof(char)*128);
    if(r == NULL)			//这棵树是一颗空树,直接返回
    {
        return str;
    }
    for(int i = 0; ;i++)
    {
        if(n < p->data)		//n小于当前节点值,往左走,str中记0
        {
			sscanf("0",(str+i));
            if(p->lchild == NULL)//如果p左孩子为空 直接挂上去
            {
                printf("二叉排序树中没有这个树\n");
				str = NULL;
                break;
            }
            p = p->lchild;
        }
        else if(n > p->data)	//n小于当前节点值,往右走,str中记1
        {
			sscanf("1",(str+i));
            if(p->rchild == NULL)//如果p右孩子为空 直接挂上去
            {
                printf("二叉排序树中没有这个树\n");
				str = NULL;
                break;
            }
            p = p->rchild;
        }
        else
        {
            break;
        }
    }
    return str;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/827.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python搭建web服务器

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

十大经典排序算法(下)

&#x1f353;个人主页&#xff1a;bit.. &#x1f352;系列专栏&#xff1a;Linux(Ubuntu)入门必看 C语言刷题 数据结构与算法 HTML和CSS3 目录 1.6 快速排序 1. 算法步骤 2. 动图演示 3.代码实现 1.7 堆排序 1. 算法步骤 2. 动图演示 3. 代码实现 1.8 计数排…

网格搜索多个监督学习模型上的超参数,包括神经网络、随机森林和树集合模型(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 我们在选择超参数有两个途径&#xff1a;1)凭经验&#xff1b;2)选择不同大小的参数&#xff0c;带入到模型中&#xff0c;挑选…

记录使用chatgpt的复杂经历

背景 由于最近要写论文&#xff0c;c站的gpt也变样了&#xff0c;无奈之下和同学借了一个gpt账号&#xff0c;才想起没有npv&#xff0c;不好意思去要&#xff0c;也不想买&#xff0c;于是我找了很多临时免费的直到我看到有一家&#xff0c;邀请10人即可&#xff0c;而且只用…

ArrayList源码分析

ArrayList源码分析目标:一、 ArrayList的简介二、ArrayList原理分析2.1 ArrayList的数据结构源码分析2.2 ArrayList默认容量&最大容量2.3 为什么ArrayList查询快&#xff0c;增删慢&#xff1f;2.4 ArrayList初始化容量1、创建ArrayList对象分析&#xff1a;无参数2、创建A…

ChatGPT-4 终于来了(文末附免费体验地址)

大家好&#xff0c;我是小钱学长。 ChatGPT4.0 重磅来袭&#xff0c;今天一打开plus页面出现的就是这个GPT-4的体验界面&#xff01;现在就带大家一起看看GPT4.0​。 进入之后是这样的 看到最下面有一行话&#xff0c;目前应该是4个小时限制100条消息。 GPT-4有什么优势&…

JavaEE--Thread 类的基本用法(不看你会后悔的嘿嘿)

Thread类是JVM用来管理线程的一个类,换句话说,每个线程都唯一对应着一个Thread对象. 因此,认识和掌握Thread类弥足重要. 本文将从 线程创建线程中断线程等待线程休眠获取线程实例 等方面来进行具体说明. 1)线程创建 方法1:通过创建Thread类的子类并重写run () 方法 class M…

new bing的chatGPT如何解析英文论文pdf

昨天我的new bing申请下来了&#xff0c;有了聊天的界面&#xff1a; 但是解析pdf的英文文献&#xff0c;还是不行&#xff0c;没有对话窗口。就问了一下chatGPT&#xff0c;方案如下&#xff1a; 要使用New Bing解析PDF文献&#xff0c;你需要以下几个步骤&#xff1a; 1&a…

【Linux学习】进程间通信——system V(共享内存 | 消息队列 | 信号量)

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 进程间通信——共享内存 | 消息队列 | 信号量&#x1f3c0;共享内存⚽系统调用shmgetkey值⚽系统…

【Linux】 Linux用户权限、文件权限、权限操作相关介绍

文章目录Linux 权限的概念Linux 用户Linux 权限Linux 文件访问者Linux 权限管理Linux 文件类型、访问权限file 文件类型显示Linux 文件访问权限的相关设置访问权限的修改访问用户的修改相关问题 *umask 权限掩码粘滞位Linux 权限的概念 Linux 用户 Linux下有两种用户&#xff…

力扣-超过经理收入的员工

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;181. 超过经理收入的员工二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其…

Android之屏幕适配方案

在说明适配方案之前&#xff0c;我们需要对如下几个概念有所了解&#xff1a;屏幕尺寸&#xff0c;屏幕分辨率&#xff0c;屏幕像素密度。 屏幕尺寸 屏幕尺寸指屏幕的对角线的物理长度&#xff0c;单位是英寸&#xff0c;1英寸2.54厘米。 比如常见的屏幕尺寸&#xff1a;5.0、5…

产品经理面经|当面试官问你还有什么问题?

相信很多产品经理在跳槽面试的时候&#xff0c;在面试尾声都会遇到这样的环节&#xff0c;面试官会问你有什么问题要问的&#xff0c;一般来说大家都能随时随地甩出几个问题来化解&#xff0c;但其实在这个环节对于应聘者来说也是一个很好的机会来展现自己的能力&#xff0c;甚…

机器看世界

博主简介 博主是一名大二学生&#xff0c;主攻人工智能研究。感谢让我们在CSDN相遇&#xff0c;博主致力于在这里分享关于人工智能&#xff0c;c&#xff0c;Python&#xff0c;爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主&#xff0c;博主会继续更新的&#xff0c…

到底什么是线程?线程与进程有哪些区别?

上一篇文章我们讲述了什么是进程&#xff0c;进程的基本调度 http://t.csdn.cn/ybiwThttp://t.csdn.cn/ybiwT 那么本篇文章我们将了解一下什么是线程&#xff1f;线程与进程有哪些区别&#xff1f;线程应该怎么去编程&#xff1f; 目录 http://t.csdn.cn/ybiwThttp://t.csdn…

分布式ID生成方案总结

什么是分布式 ID 分布式 ID 是指&#xff0c;在分布式环境下可用于对数据进行标识且易存储的全局唯一的 ID 标识。 为什么需要分布式 ID 对于单体系统来说&#xff0c;主键ID可能会常用主键自动的方式进行设置&#xff0c;这种ID生成方法在单体项目是可行的。 对于分布式系统…

8年Java架构师面试官教你正确的面试姿势,10W字面试题带你成功上岸大厂

从最开始的面试者变成现在的面试官&#xff0c;工作多年以及在面试中&#xff0c;我经常能体会到&#xff0c;有些面试者确实是认真努力工作&#xff0c;但坦白说表现出的能力水平却不足以通过面试&#xff0c;通常是两方面原因&#xff1a; 1、“知其然不知其所以然”。做了多…

「操作系统」进程间的通信方式全面解析

「操作系统」进程间的通信方式全面解析 参考&鸣谢 进程间有哪些通信方式&#xff1f; XiaoLinCodingg 进程间通信方式详解 进程间通信方式 文章目录「操作系统」进程间的通信方式全面解析一、引言二、管道三、消息队列四、共享内存五、信号量六、信号七、总结一、引言 在操…

JVM调优,调的是什么?目的是什么?

文章目录前言一、jvm是如何运行代码的&#xff1f;二、jvm的内存模型1 整体内存模型结构图2 堆中的年代区域划分2 对象在内存模型中是如何流转的?3 什么是FULL GC,STW? 为什么会发生FULL GC?4 要调优,首先要知道有哪些垃圾收集器及哪些算法5 调优不是盲目的,要有依据,几款内…

SpringSecurity学习(七)授权

授权 什么是权限管理 权限管理核心概念 SpringSecurity权限管理策略 基于URL地址的权限管理 基于方法的权限管理 一、权限管理 二、授权核心概念 在认证的过程成功之后会将当前用户登录信息保存到Authentication对象中&#xff0c;Authentication对象中有一个getAuthorities…
最新文章