数据结构——单链表(八卦掌)上部(附源码)

    文章目录


前言

        今天学习一门新的招式,八卦掌又称为游身八卦掌、八卦连环掌,是一种以内功和外功相结合,以掌法变换和行步走转为主要特点的中国传统拳术。

        本次主要学习掌法变换

        我们学的是无头单向非循环链表

        如八卦掌招数有问题,或可以优化,望各位大侠进行斧正。(ง •̀_•́)ง(ง •̀_•́)ง(ง •̀_•́)ง


提示:以下是本篇文章正文内容,下面案例可供参考

一、链表是什么?

        概念:链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。

        我们可以把链表想象成一列火车,这列火车有一个火车头和n个车厢,乘客的数量决定了车厢的数量。车厢有挂钩将车厢之间连接起来。我们把车厢想象成物理空间,指针指向的地址表示挂钩,链表的结构体表示车厢的形状。

        

二、实现单链表

1.结构体的定义

        根据上面的图,我们应该知道。单链表是一个结构体,这个结构体有两个空间。一个是链表的数据,它放在结构体里面,一个是指向下一个结构体的类型,它也放在结构体之中。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int stl_type; // 对变量名进行重命名

typedef struct s_list_node    (车厢)
{
	stl_type data; // 存放数据的类型    (乘客)
	struct s_list_node* next; 指针的类型是这个结构体的类型    (车钩)
 }s_l_node;

2.八大掌

2.1 起手(扩容)

        在学习八大掌之前我们要打基础,又称起手式

       当我们要放进n个数据,怎么定义,这就和动态顺序表一样,对结构体进行扩容,需要放进去几个就扩容几个。扩容的大小为一个结构体的大小。同时对其进行判断,是否扩容成功。

        这里的扩容是指,我们向内存要一块空间(车厢)并且放入数据(乘客)。所以,我们传进来的是数据,同时地址指向空,这是防止地址出现野指针

s_l_node* add_capacity(stl_type x)
{
	s_l_node* new_node = (s_l_node*)malloc(sizeof(s_l_node)); //扩容一个整形的地址
	if (new_node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	new_node->data = x;
	new_node->next = NULL;
	return new_node;
}

2.2 八大掌

        在八卦掌中 八大掌分别对应 天、地、雷、风、水、火、山、泽。下面就让我们开始练功。

        链表无非增删查改所以我们要实现 尾插,头插,尾删,头删,out之前插入,out之后插入,out位置删除,out后面删除

 2.2.1:尾插

        尾插,将数据放在最后的位置上,比如依此尾插 1,2,3,4,5 它们的顺序应该是1->2->3->4->5->NULL。那么它该如何写呢?我们定义一个函数,对于函数的类型为什么要选择void (void是因为我们是链表不需要进行返回类型。并且由于是链表,我们需要修改指针pp所以我们要用**pp二级指针进行接收。这是由于形参是实参的一份临时拷贝。如果传入的是*pp对函数外的指针不会做任何改变)

void s_l_push_back(s_l_node** pp, stl_type x) // 尾插
{
	s_l_node* new_node = add_capacity(x); 
	if (*pp == NULL) // 假如传进来的是一个空指针,代表这个链表是空的,是没有数据的
	{
		*pp = new_node;
	}
	else      // 代表链表里面至少有一个数据,那么就要实现在最后一个数据后面添加新数据
	{
		s_l_node* tem = *pp;	// 定义一临时结构体来接收链表地址。
		while (tem->next != NULL)	
		{
			tem = tem->next;
		}
		tem->next = new_node;  // 连接放入数据的车厢
	}
}

        在写完一个函数之后要干嘛?肯定是要进行验证。如果我们把整个链表都写完再去验证那么,如果出现错误在排查的过程中将会非常麻烦,如果是大型项目那么会令人非常恶心。

        为了能更直观的感受,在进行打印数据的时候,数据后面加入 “->”代表这个数据所指向的下一个数据。

void slt_printf(s_l_node* p)
{
	s_l_node* cur = p;
	while (cur != NULL)    // 满足条件继续循环
	{
		printf("%d->", cur->data); //打印数据类型,
		cur = cur->next; //当结构体指向结构体里面的结构体地址的时候就到了下一个位置
	}
	printf("NULL\n");
}


void slt_test()
{
	s_l_node* pl = NULL; // 对链表初始化
	s_l_push_back(&pl, 1);
	s_l_push_back(&pl, 2);
	s_l_push_back(&pl, 3);
	s_l_push_back(&pl, 4);
	slt_printf(pl); //打印链表
	
}

int main()
{
	slt_test();
	return 0;
}
2.2.2:头插 

         我们下面进行头插,将新数据放在第一个位置上,也就是说,首先拿过来一个存放乘客的新车厢,和尾插不同的是,当数据为空的时候我们不像尾插那样需要判断。只需要考虑,如果将新车厢,和现有的车厢相连接。将新车厢的挂钩挂在(指针指向)现有车厢即可。

void s_l_push_fornt(s_l_node** pp, stl_type x)	// 头插
{
	s_l_node* new_node = add_capacity(x);
	s_l_node* tem = *pp;
	new_node->next = tem;
	*pp = new_node;
}

2.2.3:指定位置前插入 

        下面就是在out之前插入。这是什么意思呢。如果我们的链表存放的是,1,3,4,5。我们想让链表存放1,2,3,4,5那么就需要在3这个位置前插入一个链表。

        我们看一张简易的结构体的表,数字代表地址,我们在out车厢前进行插入,可以很明显的看到插入的过程是什么样子的。找到out车厢前的车厢,将这个车厢的挂钩指向插入的新车厢,将新车厢的挂钩指向out车厢的位置即可。同时我们还需要考虑第二章种情况,在a车厢的位置进行插入,我们无法在N前插入,因为那是空指针,所以在out前插入只有两种情况。而第二种情况不就是头插吗!所以当为第二种情况的时候,我们调用头插的函数即可。

void s_l_insert(s_l_node** pp, s_l_node* out, stl_type x) //out之前插入
{
	assert(out);
	if (out == *pp) // 第一种情况
	{
		s_l_push_fornt(pp, x);
	}								//			d
	else							//	a->b->c->e->f->NULL
	{
		s_l_node* new_node = add_capacity(x);
		s_l_node* text = *pp;
		while (text->next != out && text->next != NULL)
		{
			text = text->next;
		}
		if (text->next == out)
		{
			text->next = new_node;
			new_node->next = out;
		}
		else
		{
			printf("没有查找到out");
			free(new_node);
		}
	}
}
2.2.4:指定位置后插入 

        有out位置前插入就有out位置后插入。 可以看下面的图片,其插入方法就是,将新车厢指向d在将out车厢指向新车厢即可。

        我们还需要考虑其他情况吗?比如在e后面插入?自己思考就知道,不需要了。在后面插入,第三方存放的地址是NULL,新车厢指向第三方所存的地址,是可以的。

void s_l_insert_after(s_l_node* out, stl_type x) //out之后插入
{
	assert(out);
	s_l_node* new_node = add_capacity(x);
	new_node->next = out->next;
	out->next = new_node;
}

         到现在我们学会了四大掌增添数据,后面就来学习后四大掌删除数据。

2.2.5:尾删

         尾删顾名思义,删除最后一个。学会了上面四个删除还是比较简单的。我们找到链表最后一个删除即可

void s_l_out_back(s_l_node** pp)//尾删
{
	assert(*pp);
	s_l_node* del = *pp;
	if (del->next->next == NULL)
	{
		free(del->next);
		del->next = NULL;
	}
	else
	{
		while (del->next->next != NULL)
		{
			del = del->next;
		}
		free(del->next);
		del->next = NULL;
	}
	
}
2.2.6:头删 

         头删稍微复杂一点,但也是很简单的。删除最前面的数据。

void s_l_out_fornt(s_l_node** pp)//头删
{
	assert(*pp);
	s_l_node* del = *pp; //给它起始地址
	*pp = del->next; //跳过首地址
	free(del); 
	del->next = NULL;
}
2.2.7:在指定位置删除   

         有了上面的功底,看下面的图片,便很容易便可以写出来。我们需要考虑两种情况,那就是当只有a这一个数据的时候怎么删除。 我要删除F但链表里面没有F。   


void s_l_erase(s_l_node** pp, s_l_node* out) // out位置删除
{
	assert(*pp);
	assert(out);
	if (*pp == out) // 当只有一个数据的时候
	{
		s_l_out_fornt(pp);
	}
	s_l_node* del = *pp;
	while (del->next != out && del->next != NULL) // 如何链表里面没有out
	{
		del = del->next;
	}
	if (del->next == out)
	{
		del->next = out->next;
		free(out);
		del->next = NULL;
	}
	else
	{
		printf("链表内没有这个数,无法删除它");
	}
}

 2.2.8:在指定位置后面删除

         这个更加简单,只需要考虑链表不为空的情况即可。断言一下不就行了。

void s_l_del_after(s_l_node* out) //out后面删除
{
	assert(out);
	s_l_node* del = out->next;
	out->next = del->next;
	free(del);
	del = NULL;
}

总结

        至此八卦掌上部正式学完。要掌握为什么有的函数要用二级指针。

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
八卦结构是一种思维模型,可以用于分析任何复杂的系统,包括股票市场。在使用八卦结构进行股票数据分析时,可以按照以下步骤进行: 1. 制定目标:首先需要明确分析的目标是什么。例如,你可能想要找出股票市场的趋势、评估某个公司的财务状况、预测未来的股票价格等等。 2. 收集数据:收集与目标相关的数据,包括历史股价、财务报表、行业报告等等。 3. 分析八卦结构:将收集到的数据按照八卦结构进行分析,即将数据分为乾、坤、震、巽、离、坎、艮、兑八个部分。乾代表股票市场的整体趋势,坤代表公司的基本面情况,震代表行业的发展趋势,巽代表公司的营销策略,离代表公司的盈利能力,坎代表市场风险,艮代表公司管理层的质量,兑代表公司与投资者的互动。 4. 分析关系:分析各个部分之间的关系,例如乾和坤之间的关系代表着市场趋势和公司的基本面之间的关系。通过分析这些关系,可以深入了解股票市场的运作机制。 5. 制定策略:根据分析的结果,制定相应的投资策略。例如,如果分析结果表明市场风险较高,可以选择保守的投资策略;如果分析结果表明某个公司财务状况不佳,可以考虑卖空该股票等等。 总之,用八卦结构对股票进行数据分析可以帮助投资者更好地理解市场运作机制,制定更科学的投资策略,从而更好地把握投资机会。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值