[双向链表排序]—-对双向链表中结(节)点的成员排序(冒泡排序)「建议收藏」

[双向链表排序]—-对双向链表中结(节)点的成员排序(冒泡排序)「建议收藏」双向链表

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

1. 双向链表的定义


【百度百科】

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

  • 链表中的每个节点的成员由两部分组成:
    1. 数据域:专门用来保存各个成员的信息数据。
    2. 指针域:专门用来与其他节点链接。

2. 结构体中的两个重要指针


直接后继 & 直接前驱
  • 直接后继:我个人习惯称之为后向指针,也习惯定义为pnext,该指针指向下一个节点,如果该节点为尾节点,那么pnext指向NULL

  • 直接前驱:同样我习惯称之为后向指针,也习惯定义为prev,该指针指向前一个节点,如果该节点为头节点,那么prev指向NULL


3. 双向链表中节点的成员排序(冒泡排序)


在排序之前我们需要明确一点:<明确我们操作的链表的头节点的数据域是否写有数据>

因为有时候程序员写代码时为了链表方便操作会专门创建一个表头(头结点),即不存放数据的表头。


3.1头节点数据域为空

接下来我们来看几段代码:

typedef struct student
{
	int num;
	char name[20];
	float score;
	struct student *prev;
	struct student *pnext;
}STU,*PSTU;
//1.首先我们定义一个结构体,有数据域(前三个)和指针域(后两个)两部分
//2.将结构体和结构体指针分别重命名为STU,PSTU

冒泡排序代码如下:

#incldue <stdio.h>

PSTU score_sort(PSTU head)				  //函数返回值为头指针,形参也为头指针
{
	int i=0,j=0;
	int n=num_of_stu(head);              //调用统计节点个数的函数
	PSTU p=head;                         //定义两个临时指针来进行数据处理
	PSTU pn=head;                        //p和pn总是两个相邻的节点,且pn在p之后
   //****冒泡排序****//
	for(i=0;i<n;i++)
	{
		p=head->pnext;
		pn=p->pnext;
		for(j=0;j<n-1-i;j++)
		{
			if(p->score < pn->score)          //判断,条件成立之后交换位置
			{
				if(pn->pnext==NULL)           //判断是否为尾节点
				{
					//**交换位置代码**//
					p->pnext=pn->pnext;
					pn->prev=p->prev;
					pn->pnext=p;
					p->prev->pnext=pn;
					p->prev=pn;
					//**位置交换结束**//
				}
				else
				{
					//**交换位置代码**//
					p->pnext=pn->pnext;
					pn->prev=p->prev;
					pn->pnext->prev=p;
					p->prev->pnext=pn;
					//下一行请注意//	
					pn->pnext=p;
					p->prev=pn;
					//**位置交换结束**//
					pn=p->pnext;      //位置交换结束之后进行指针偏移,pn指向p的下一个节点
				}
			else                                       //条件不成立
			{
				p=p->pnext;
				pn=p->pnext;
					//如果未发生位置交换,则两个指针都要发生偏移
			}
		}
	}
	return head;		
}

重点:
在上一段代码中一定要注意我在代码前面注释的那一行,并且要与不是尾结点的情况对比来看,你会发现少了一行代码, pn->pnext->prev=p,我先解释一下这一行代码是什么意思,从上面的代码可以看出两个临时指针的位置关系为p总是在Pn的前面,那也就是说满足交换位置条件之后进行位置交换,交换之后两个临时指针位置就随之交换,在交换的过程中,假如有尾结点,那么pn的后向指针指向NULL,随之 pn->pnext->prev 就会出现段错误


3.2头节点数据域不为空(一般不建议)

这种方式在数据处理上面会比较麻烦,一旦头结点的数据发生位置交换(比如排序,插入结点,删除结点等),那么在函数的封装是就要考虑将新的头结点返回。

接下来我们来看几段代码:

typedef struct student
{
	int num;
	char name[20];
	float score;
	struct student *prev;
	struct student *pnext;
}STU,*PSTU;
//1.首先我们定义一个结构体,有数据域(前三个)和指针域(后两个)两部分
//2.将结构体和结构体指针分别重命名为STU,PSTU

冒泡排序部分核心代码如下:

#incldue <stdio.h>

PSTU score_sort(PSTU head)				  //函数返回值为头指针,形参也为头指针
{
	int i=0,j=0;
	int n=num_of_stu(head);              //调用统计节点个数的函数
	PSTU p=head;                         //定义两个临时指针来进行数据处理
	PSTU p1=head;                        //p和pn总是两个相邻的节点,且pn在p之后
   //****冒泡排序****//
	for(i=0;i<n;i++)
	{
		p=head->pnext;
		pn=p->pnext;
		for(j=0;j<n-1-i;j++)
		{
			if(p->score < pn->score)          //判断,条件成立之后交换位置
			{
				if(j==0)//***重点参考                //判断头结点是否会参与位置交换
				{
					head=p1;
					p->pnext=p1->pnext;
					p1->prev=p->prev;
					p1->pnext=p;
					p1->pnext->prev=p;
					p->prev=p1;
					
					p1=p->pnext;
				}
				 ......//中间省略部分代码//......
				else
				{
					//**交换位置代码**//
					p->pnext=pn->pnext;
					pn->prev=p->prev;
					pn->pnext->prev=p;
					p->prev->pnext=pn;
					//下一行请注意//	
					pn->pnext=p;
					p->prev=pn;
					//**位置交换结束**//
					pn=p->pnext;         //位置交换结束之后进行指针偏移,pn指向p的下一个节点
				}
			else                                       //条件不成立
			{
				p=p->pnext;
				pn=p->pnext;
					//如果未发生位置交换,则两个指针都要发生偏移
			}
		}
	}
	return head;		
}

重点:
在看上面的代码时我们需要与3.1节的内容对比来看,因为3.2节的中要单独考虑的情况有四种:

  • 头结点发生改变:
    重点要考虑头指针的的前向指针为NULL;
  • 尾结点发生改变:
    重点要考虑尾结点的的后向向指针为NULL;
  • 有且仅有两个结点(即头结点和尾结点):
    重点要考虑头指针的的前向指针为NULL且尾结点的的后向向指针为NULL;
  • 发生位置交换的结点不包含头结点和尾结点:
    这种情况下交换位置的6行代码都不能少;
以上就是就是本次的所有内容,朋友如若发现问题,随时欢迎交流,希望能帮到你!!!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183253.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • sql server 2008 r2 序列号密钥实测可用20210906

    sqlserver2008密钥Developer:PTTFM-X467G-P7RH2-3Q6CG-4DMYBEnterprise:JD8Y6-HQG69-P9H84-XDTPG-34MBBMicrosoftSQLServer2008R2序列号密钥开发版32位:MC46H-JQR3C-2JRHY-XYRKY-QWPVM开发版64位:FTMGC-B2J97-PJ4QG-V84YB-MTXX8工组版:XQ4CB-VK9P3-4WYYH-4HQX3-K2R6QWEB版:FP4P7-YK

    2022年4月7日
    316
  • 445port入侵具体解释

    445port入侵具体解释

    2021年12月1日
    34
  • 安装 Prophet

    安装 Prophet本安装文档主要翻译整理自ProphetInstallation官方安装文档。在R上安装Prophet一、Windows系统安装Prophet前的准备工作如果是Windows系统,需要按照rstan提供的教程给R安装一个编译器。其中,最为关键的一步就是先安装Rtools。1.安装R和RStudio2.安装Rtools,确保其安装…

    2022年6月25日
    79
  • java静态全局变量和全局变量的区别_java静态全局变量

    java静态全局变量和全局变量的区别_java静态全局变量Java的面向对象的代码结构会使在多个位置引用变量更加困难。有时也很难确定给定变量应属于哪个类,尤其是当它是一个广泛使用的值(例如数据库连接器或数学常数)时。Java全局变量怎么定义?在许多语言中,当遇到这样的问题时,我们可以声明一个全局变量。但是,不幸的是,Java从技术上不允许在全局范围内创建变量。在本文中,我们将介绍如何在Java中模拟和使用全局变量。什么是全局变量?全局变量是可以从任何范围访问的变量。许多编程语言都具有用于声明全局变量的特殊语法,例如,Python使我们可以使

    2022年8月21日
    4
  • RC有源滤波器之带通滤波器(四)

    RC有源滤波器之带通滤波器(四)记录一下,方便以后翻阅~过去的滤波器都是由R、L、C等无源元件组成,称为无源滤波器。现在的滤波器大都是由R、C元件与有源器件(如运算放大器)组成,称为RC有源滤波器。常见滤波器类型有低通滤波器、高通滤波器、带通滤波器、带阻滤波器、全通滤波器等。RC有源带通滤波器带通滤波器允许某一频率范围内的信号通过,衰减或抑制此频率范围以外的频率信号。理想带通滤波器的模频特性如下图所示,Wc2和Wc1分别为上下截止频率。RC有源带通滤波器器电路如下图所示:电压传输函数为:其模:…

    2022年6月7日
    43
  • pycharm如何使用pyinstaller_python的pyinstaller用法

    pycharm如何使用pyinstaller_python的pyinstaller用法在pycharm里面安装pyinstaller直入正题之前,我们得先在pycharm上安装好这个插件。按照下图所示方法打开terminal(这个我感觉相当于你电脑运行cmd),随后你还是得找到你的python安装路径,C盘的话好像直接使用指令:pipinstallpyinstaller,D盘的话就要找到目录进行安装。python3的版本可以试着吧指令换为:pip3installpyinstaller问题引出之前我在电脑上用python搞了一个小程序(很简单的,就不细讲),但是等到我

    2022年8月28日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号