数据结构与算法:链表的基本设计思路

本文探讨了链表元素调整时如何防止形成无限循环和内存地址丢失,通过实例讲解了直接插入排序和链表逆置的实现,重点介绍了辅助指针的巧妙运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

调整链表元素,不可避免且最常见的操作就是调整某个确定链表中元素的位序,需要注意以下几点:

1. 防止在调整过程中形成闭环导致无限循环

2. 防止在调整过程中导致被调整元素后的元素内存地址丢失

针对这两个问题,我们通常会设立辅助指针变量,对于问题一,我们设立一个pre指针,该指针始终指向被调整元素节点的前驱节点,用于切断前驱节点与被调整节点之间的链,从而防止闭环的出现,对于问题二,我们设立一个pro指针,该指针始终指向被调整元素的后继节点,防止该节点与后继节点断链后,丢失地址,因此这类问题我们一般都是设立三个指针:

一个用于防止闭环出现(通常仅在循环外部使用一次,断链防闭环),一个用于循环遍历整个链表进行操作(即while循环中的条件),另一个用于防止丢失地址

针对这个方法,看一个例题,基于直接插入排序对单链表进行排序的算法

void sortLinklist(Linklist &L) {
	Linklist p, pro, ppro;
	p = L->next; //p指向已有序序列的最后一个元素节点
	pro = p->next;//pro指向待排序序列的第一个节点
	ppro = pro->next;//ppro指向pro的下一个节点,防止断链后位置丢失
	Linklist pre = L; // pre用于在有序序列中循环遍历确认插入的位置
	p->next = NULL; //第一个数据节点指针置空
	while (pro) {
		ppro = pro->next;
		pro->next = NULL;
		ElemType temp = pro->data;
		while (pre->next != NULL && pre->next->data < temp) {
			pre = pre->next;
		}
		pro->next = pre->next;
		pre->next = pro;
		pro = ppro;
		//if(ppro){ ppro = ppro->next; }
		}
	printListWithNoLeaderNode(L);
}

再一个例题:对链表就地逆置(就地:即空间复杂度为O(1)的算法)

void reverseLinklist(Linklist &L) {
	Linklist p, q, proq;
	p = L->next;
	q = p->next;
	proq = q->next;
	p->next = NULL;
	while (q) {
		q->next = NULL;
		q->next = L->next;
		L->next = q;
		q = proq;
		if (proq != NULL) { proq = proq->next; }
	}
	printListWithNoLeaderNode(L);
}

两个题需要特别注意的是:在被处理节点的前驱节点指针不断后移的过程中,要避免出现空指针异常,通常有两种设置方法:

1. 在循环代码段的开始部分就进行后移

2.在循环代码段结束部分通过if语句来限定指针的移动

最后,附上基本接口

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 20
#define ElemType int
typedef struct LNode {
	ElemType data;
	struct LNode* next;
}LNode, * Linklist;

typedef struct {
	ElemType data[MaxSize];
	int top;
}SqStack;
//基本接口
Linklist createSingleLinklistByTileInsert(Linklist& L) {
	Linklist s;
	L = (LNode*)malloc(sizeof(LNode));
	LNode* r = L;
	int x;
	printf("Please enter the text you need!");
	scanf("%d", &x);
	while (x != 9999) {
		s = (Linklist)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;
		printf("Please enter the text you need!");
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}
Linklist creatSinglleLinklistWithNoLeaderByTileInsert(Linklist& L) {
	int f, x;
	L = (LNode*)malloc(sizeof(LNode));
	Linklist s, r = L;
	printf("请确定第一个节点的值:");
	scanf("%d", &f);
	L->data = f;
	printf("Please enter the text you need!");
	scanf("%d", &x);
	while (x != 9999) {
		s = (Linklist)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;
		printf("Please enter the text you need!");
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}
void printListWithNoLeaderNode(Linklist L) {
	Linklist p = L->next;
	while (p) {
		printf("%3d", p->data);
		p = p->next;
	}
}
void InitStack(SqStack& S) {
	S.top = -1;
}
bool push(SqStack &S,ElemType x) {
	if (S.top == MaxSize - 1) {
		return false;
	}
	S.data[++S.top] = x;
	return true;
}
bool pop(SqStack& S, ElemType& x) {
	if (S.top == -1) {
		return false;
	}
	x = S.data[S.top--];
	return true;
}
bool isEmpty(SqStack S) {
	if (S.top == -1) {
		return true;
	}
	else { return false; }
}
//基本接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值