链表的实现

主体:

// 1、无头+单向+非循环链表增删查改实现
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

申请空间:

// 动态申请一个结点
SListNode* BuySListNode(SLTDateType x) {
	SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
	if (!tmp) {
		perror("fail buy");
		exit(-1);
	}
	tmp->data = x;
	tmp->next = NULL;
	return tmp;
}

思路:

申请一片空间,然后判断是否申请成功,没有成功就退出,退出码为-1;

申请成功,我们就填入数据,然后将我们节点的指向为NULL,这样方便后面操作;

遇见的问题:

我在实现顺序表的时候也遇见了,就是它警告NULL取消tmp->data的引用;

我当时没有反应过来,且没有报错就没改,我后面才想起来perror是一个打印错误信息的函数,本身不会结束进程;所以代码还是会向下执行,所以我们要用一个在子进程可以杀死进程的函数exit;

打印:

// 单链表打印
void SListPrint(SListNode* plist) {
	assert(plist);
	SListNode* tmp = plist;
	while (tmp) {
		printf("%d", tmp->data);
		tmp=tmp->next;
	}
	printf("\n");
}

思路:

先判断给指针的是否为空;因为我们要访问它的成员;

其实这个tmp是没有必要的;我们这里的plist也是一个函数内部的临时变量;

实际上就是从前往后读取,边界条件为最后一个节点也要打印;于是要将指针移动到指向NULL;

优化后的代码:

// 单链表打印
void SListPrint(SListNode* plist) {
	assert(plist);
	while (plist) {
		printf("%d", plist->data);
		plist = plist->next;
	}
	printf("\n");
}

尾插:


// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x) {
	SListNode* tmp = BuySListNode(x);
	SListNode* ptmp = *pplist;
	if (ptmp == NULL) ptmp = tmp;
	else {
		while (ptmp->next) {
			ptmp = ptmp->next;
		}
		ptmp->next = tmp;
	}
}

思路:

第一,链表为空(就是一个节点都没有);我们直接指向申请的节点;

第二,不为空,链表找尾,边界条件为尾节点保留,就是移动指针到节点next为空的时候;

细节:我们不断言指针为空的情况,因为空链表也是可以的;

改bug:

代码第5行,这里会存在问题;因为我们要改的是外面的指针,而不是这个临时变量;

这里就算赋值了,也不会改变外面;要改变一个变量值就是直接给这个变量赋值;

或者这个变量的指针赋值;

这里的临时变量只是外面指针的拷贝;所以只是指向空间相同;但是他们还是属于同等级的指针;但是我们后面的代码是对的原因也是因为我们要操作的数据和指针的等级相匹配;

我们要改结构体,只需要结构体指针就可以了;对他进行解引用改值就行;


// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x) {
	SListNode* tmp = BuySListNode(x);
	if (*pplist == NULL) *pplist= tmp;
	else {
		SListNode* ptmp = *pplist;
		while (ptmp->next) {
			ptmp = ptmp->next;
		}
		ptmp->next = tmp;
	}
}

头插:

// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x) {
	SListNode* tmp = BuySListNode(x);
	//这里用一个局部的一级指针;这里会有问题;
		tmp->next=*pplist;
		*pplist = tmp;
}

思路

将新节点的下一个指向现在的头节点;然后将我们指针指向新节点;

这里和尾插一样不能用临时指针变量;

尾删:

// 单链表的尾删
void SListPopBack(SListNode** pplist) {
	assert(*pplist);
	SListNode* ptmp = *pplist;
	if (ptmp->next == NULL)//一个节点;
	{
		free(ptmp);
		ptmp = NULL;
	}
	else {
		SListNode* tmp = ptmp;
		while (ptmp->next) {
			tmp = ptmp;
			ptmp = ptmp->next;
		}
		free(ptmp);
		tmp->next = NULL;
	}
}

思路:

尾删,

空的时候就报错;不能访问;

只有一个节点的时候直接free()所指向的空间;然后指针置空;

多个节点就要求找尾,然后同一的操作;

优化:

我刚才发现了,我们可以将这里那个合并为一个;

// 单链表的尾删
void SListPopBack(SListNode** pplist) {
	assert(*pplist);
	SListNode* ptmp = *pplist;
		SListNode* tmp = ptmp;
		while (ptmp->next) {
			tmp = ptmp;
			ptmp = ptmp->next;
		}
		free(ptmp);
		tmp->next = NULL;
}

代码执行效果一样;

头删:

// 单链表头删
void SListPopFront(SListNode** pplist) {
	assert(*pplist);
	SListNode* ptmp = *pplist;
	(*pplist) = (*pplist)->next;
	free(ptmp);
}

这里也一样不能用临时指针变量;

就是将我们指针指向他的下一个位置;

所以我们要保证他有一个节点,不然我们都没办法删;

我们要避免内存泄漏,就要求有一个指针指向跳过的节点;然后释放空间;且这里是

栈区的指针变量它会自己释放;所以可以不指向空;

查找:

// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x) {
	assert(plist);
	while (plist) {
		if (plist->data == x) return plist;
	}
	return NULL;
}

这个没什么要说的,就是一个循环找就行了;

任意位置插入与删除

/ 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x) {
	SListNode* tmp = BuySListNode(x);
	tmp->next = pos->next;
	pos->next = tmp;
}
// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos) {
	assert(pos && pos->next);
	SListNode* tmp = pos->next;
	pos->next = pos->next->next;
	free(tmp);
}

思路与注意点前面完全一样;

pos->next = pos->next->next;

因为这里我们要访问pos->next的成员,所以我们要断言判断这个pos->next是否存在;

如果为空我们访问它的成员就是非法的;

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中,可以使用类来实现链表。一个常见的链表实现是单链表。单链表由节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。在Python中,可以使用类来定义单链表。例如,可以定义一个SingleLinkedList类,其中包含一个头节点和链表的大小属性。可以使用__init__方法来初始化链表为空表,并使用其他方法来实现链表的各种操作,如插入、删除和遍历等。\[1\] 在Python中,变量赋值是指针的赋值运算。当使用a,b=b,a这样的赋值语句时,实际上是将a和b的指针进行了交换,而不是交换它们所指向的对象的值。这是因为在Python中,一切皆为对象,变量存储的是对象的地址。因此,通过交换指针,可以实现变量值的交换。这种机制使得在Python中进行链表操作更加方便,可以直接通过改变节点的指针来实现节点之间的连接。\[2\]\[3\] 所以,在Python中实现链表时,可以使用类来定义节点,每个节点包含一个数据元素和一个指向下一个节点的指针。通过改变节点的指针,可以实现节点之间的连接,从而构建链表。可以使用类的方法来实现链表的各种操作,如插入、删除和遍历等。 #### 引用[.reference_title] - *1* [Python数据结构——链表实现](https://blog.csdn.net/weixin_33772645/article/details/86193584)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Python实现链表](https://blog.csdn.net/qq_38851184/article/details/105750984)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值