王道第二章【链表】

本文详细介绍了如何进行链表的操作,包括如何遍历链表找到尾结点并进行连接,以及如何修改链表的指向,内容涵盖19个步骤。

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

1.
在这里插入图片描述
在这里插入图片描述

void Delete(LNode *&L,int x)
{
	LNode *p; //p指向待删除结点
	if(L == NULL) //递归出口
		return;
	if(L->data == x) //若L所指结点的值为x
	{
		p = L;
		L = L->next;
		free(p);
		Delete(L,x); //递归调用
	}
	else //若L所指结点的值不为x
	{
		Delete(L->next,x); //递归调用
	}
}

2.
在这里插入图片描述在这里插入图片描述

//要删除一个结点必须知道其前驱结点
void Delete(LNode *&L,int x)
{
	LNode *p = L->next; 
	LNode *pre = L;
	LNode *q;
	while(p != NULL)
	{
		if(p->data == x)
		{
			q = p; //q
			p = p->next;
			pre ->next = p;
			free(q);
		}
		else
		{
			pre = p;
			p = p->next;
		}
	}
}

在这里插入图片描述

void Delete(LNode *&L,int x)
{
	LNode *p = L-next; //p为工作指针,用来扫描整个链表,指向开始结点
	LNode *r = L; //r指向尾结点,其初值为头结点
	LNode *q;
	while(p != NULL)
	{
		if(p->data != x) //p结点不为x时将其链接到L尾部
		{
			r->next = p;
			r = p; //r始终指向尾结点
			p = p-next; //继续扫描
		}
		else
		{
			q = p; //接收要被删除的结点
			p = p->next; //继续扫描
			free(q);
		}
	}
	r-next = NULL;
}

3.
在这里插入图片描述

void RePrint(LNode *L)
{
	if(L-next != NULL)
	{
		RePrint(L->next); //递归
	}
	print(L->data); //输出函数
}

4.
在这里插入图片描述
在这里插入图片描述

void DeleteMin(LNode *&L)
{
	LNode *p = L->next;
	LNode *pre = L;
	LNode *minp = p;
	LNode *preminp = pre;
	while(p != NULL)
	{
		if(p->data < minp->data)
		{
			minp = p;
			preminp = pre;
		}
		pre = p;
		p = p->next;
	}
	preminp->next = minp->next;
	free(minp);
}

5.
在这里插入图片描述
在这里插入图片描述

void Reverse(LNode *L)
{
	LNode *p = L->next; //p为工作指针,用来扫描整个链表
	LNode *r; //r为p的后继,以防断链
	L->next = NULL; //将头结点L的next域置为NULL
	while(p != NULL) //头插法建立链表
	{
		r = p->next; //暂存p结点的后继
		p->next = L->next;
		L-next = p;
		p = r;
	}
}

在这里插入图片描述

void Reverse(LNode *L)
{
	LNode *pre;
	LNode *p = L->next;
	LNode *r = p->next;
	p->next = NULL; //处理第一个结点
	while(r != NULL) //r为空则说明p为最后一个结点
	{
		pre = p; //依次继续遍历
		p = r;
		r = r->next;
		p->next = pre; //指针反转
	}
	L->next = p; //处理最后一个结点
}

6.
在这里插入图片描述
在这里插入图片描述

void Sort(LNode *&L)
{ //本算法实现将单链表L的结点重排,使其递增有序
	LNode *p = L->next;
	LNode *pre;
	LNode *r = p->next; //r保持*p后继结点指针,以保证不断链
	p->next = NULL; //构造只含一个数据结点的有序表
	p = r;
	while(p != NULL)
	{
		r = p->next; //保存*p的后继结点指针
		pre = L;
		while(pre->next != NULL && pre-next->data < p->data) //直到pre->next为NULL||pre->data >= p->data时循环结束
			pre = pre->next;
		p->next = pre->next; //找到比当前pre->next结点小的结点,插在pre结点之后
		pre->next = p;
		p = r;
	}
}

7.
在这里插入图片描述

void DeleteNode(LNode *&L,int min,int max)
{
	LNode *p; //工作指针,扫描一遍链表
	LNode *pre;
	p = L-next;
	pre = L;
	while(p != NULL)
	{
		if(p->data > min || p->data < max)
		{
			pre ->next = p->next;
			free(p);
			p = pre->next;
		}
		else
		{
			pre = p;
			p = p->next;
		}
	}
}

8.
在这里插入图片描述
在这里插入图片描述

LNode *SearchCommon(LNode *L1,LNode *L2)
{//本算法实现在线性的时间内找到两个单链表的第一个公共结点
	int length1 = Length(L1);
	int length2 = Length(L2); //计算两个链表的长度
	LNode *longList,*shortList;
	if(length1 < length2)
	{
		longList = L1->next;
		shortList = L2->next;
		dist = length1 - length2; //表长之差
	}
	else
	{
		longList = L2->next;
		shortList = L1->next;
		dist = length2 - length1;
	}
	while(dist--) //表长的链表先遍历到第dist个结点
	{
		longList = longList->next;
	}
	while(longList != NULL)
	{
		if(longList == shortList)
			return longList;
		else
		{
			longList = longList->next;
			shortList = shortList->next;
		}
	}
	return NULL;
}

9.
在这里插入图片描述
描述

void DeleteMin(LNode *head)
{//head是带头结点的单链表的头指针,本算法按递增顺序输出单链表中的数据元素
	LNode *pre,*p,*u;
	while(head->next != NULL)
	{
		pre = head;
		p = pre->next; //p为工作指针
		while(p->next != NULL)
		{
			if(p->next->data < pre->next->data)
			{
				pre = p;
				p = p->next;
			}
		}
		print(pre->next->data);
		u = pre->next;
		pre->next = u->next;
		free(u);
	}
	free(head); //释放头结点
}

10.
在这里插入图片描述

void Split(LNode *A,LNode *&B)
{ 
	LNode *p,*q,*r;
	B = (LNode*)malloc(sizeof(LNode));
	B->next = NULL;
	r = B;
	p = A;
	while(p->next != NULL) //p始终指向当前被判断结点的前驱结点
	{
		if(p->next->data%2 == 0) //判断结点是否为偶数,是偶数则从链表中取下来
		{
			q = p->next;
			p->next = q->next;
			q->next = NULL;
			r->next = q;
			r = q;
		}
		else
		{
			p = p->next; //p后移一个位置,即开始检查下一个结点
		}
	}
}

11.
在这里插入图片描述
在这里插入图片描述

void CreateLink(LNode *&A)
{
	LNode *B =(LNode*)malloc(sizeof(LNode));
	B->next = NULL;
	LNode *p = A->next;
	LNode *q;
	LNode *ra = A; //ra始终指向A的尾结点
	while(p != NULL)
	{
		ra->next = p;
		ra = p; //将*p链到A的表尾
		p = p->next;
		q = p->next; //头插后,*p将断链,因此用q记忆*p的后继
		p->next = B->next; //将*p插入到B的前端
		B->next = p;
		p = q;
	}
	ra->next = NULL;
}

12.
在这里插入图片描述
在这里插入图片描述

void Delete(LNode *&L)
{
	LNode *p = L->next; //p为扫描工作指针
	LNode *q;
	if(p == NULL)
		return;
	while(p->next != NULL)
	{
		q = p->next;
		if(p->data == q->data)
		{
			p->next = q->next;
			free(q);
		}
		else
			p = p->next;
	}
}

在这里插入图片描述

void Delete(LNode *&L)
{
	LNode *p = L->next;
	LNode *q = L->next-next;
	LNode *r;
	while(q != NULL)
	{
		while(q != NULL && q->data == p->data)
			q = q->next;
		if(q != NULL)
		{
			p = p->next;
			p->data = q->data;
		}
	}
	q = p->next;
	p->next = NULL;
	while(q != NULL) //释放p之后的所有结点
	{
		r = q;
		q = q->next;
		free(r);
	}
}

13.
在这里插入图片描述

void merge(LNode *A,LNode *B,LNode *&C)
{ //合并两个递增有序链表(带头结点),并使合并后的链表递减排列
	LNode *p = A->next;
	LNode *q = B->next;
	LNode *s;
	C = A;
	C->next = NULL;
	free(B);
	while(p != NULL && q != NULL)
	{
		if(p->data <= q->data)
		{
			s = p; //s保存p结点指针用来头插法操作使用
			p = p->next;
			s->next = C->next;
			C->next = s;
		}
		else
		{
			s = q;
			q = q->next;
			s->next = C->next;
			C->next = s;
		}
	}
	while(p != NULL)
	{
		s = p;
		p = p->next;
		s->next = C->next;
		C->next = s;
	}
	while(q != NULL)
	{
		s = q;
		q = q->next;
		s->next = C->next;
		C->next = s;
	}
}

14.
在这里插入图片描述
在这里插入图片描述

void GetCommon(LNode *A,LNode *B)
{
	LNode *p = A->next;
	LNode *q = B->next;
	LNode *r,*s;
	LNode *C = (LNode *)malloc(sizeof(LNode)); //建立表C
	r = C;
	while(p != NULL && q != NULL)
	{
		if(p->data < q->data) //若A的当前元素较小,后移指针
			p = p->next;
		else if(p->data > q->data) //若B的当前元素较小,后移指针
			q = q->next;
		else
		{
			s = (LNode*)malloc(sizeof(LNode));
			s->data = p->data;
			r->next = s; //尾插法
			r = s;
			p = p->next;
			q = q->next;
		}
	}
	r->next = NULL; //置C尾结点指针为空
}

15.
在这里插入图片描述
在这里插入图片描述

void Merge(LNode *&A,LNode *&B)
{
	LNode *pa = A->next;
	LNode *pb = B->next;
	LNode *pc = A;
	LNode *u;
	while(pa != NULL && pb != NULL)
	{
		if(pa->data == pb->data) //交集并入结果表中
		{
			pc->next = pa;
			pc = pa;
			pa = pa->next;
			u = pb;
			pb = pb->next;
			free(u);
		}
		else if(pa->data < pb->data) //若A中当前结点值小于B中当前结点值
		{
			u = pa;
			pa = pa->next;
			free(u);
		}
		else
		{
			u = pb;
			pb = pb->next;
			free(u);
		}
	}
	while(pa != NULL) //B已遍历完,A未完
	{
		u = pa;
		pa = pa->next;
		free(u);
	}
	while(pb != NULL) //A已遍历完,B未完
	{
		u = pb;
		pb = pb->next;
		free(u);
	}
	pc->next = NULL; //置结果链表尾指针为NULL;
	free(B); //释放B表头结点
}

16.
在这里插入图片描述
在这里插入图片描述

bool isSubLink(LNode *A,LNode *B)
{
	LNode *p = A->next;
	LNode *q = B->next;
	LNode *pre = p; //pre记住每趟比较中A链表的开始结点
	while(p != NULL && q != NULL)
	{
		if(p->data != q->data) //结点值不同
		{
			pre = pre->next;
			p = pre; //A链表新的开始比较结点
			q = B->next; //q从B链表第一个结点开始
		}
		if(p->data == q->data) //结点值相同
		{
			p = p->next;
			q = q->next;
		}
	}
	if(q == NULL)
		return true;
	else
	 	return false;
}

17.
在这里插入图片描述
在这里插入图片描述

int Symmetry(DLNode *L)
{ //本算法是从两头扫描循环双链表,以判断链表是否对称
	DLNode *p = L->next;
	DLNode *q = L->prior;
	while(p != q && p->next != q)
	{
		if(p->data == q->data)
		{
			p = p->next;
			q = q->prior;
		}
		else
			return 0;
	}
	return 1;
}

18.
在这里插入图片描述
设置指针p遍历h1直到找到尾结点,也就是next为h1,将其链接到h2,
p继续遍历直到找到h2尾指针,也就是next为h2,修改指向h1

void GetNewLink(LNode *&h1,LNode *&h2)
{
	LNode *p = h1;
	while(p->next != h1)
	{
	 	p = p->next; //此时p为h1尾结点
	}
	p->next = h2;
	p = p->next;
	while(p->next != h2)
	{
		p = p->next; //此时p为h2尾结点
	}
	p->next = h1;
}

19.
在这里插入图片描述
在这里插入图片描述

void Delete(LNode *&L)
{ //本算法实现每次删除循环单链表中的最小元素,直到链表空为止
	LNode *p,*pre,*minp,*minpre;
	while(L->next != L) //判断表是否为空
	{
		p = L->next;
		pre = L;
		minp = p;
		minpre = pre;
		while(p != L) //循环一趟,查找最小值结点
		{
			if(p->data < minp->data)
			{
				minp =p;
				minpre = pre;
			}
			pre = p;
			p = p->next;
		}
		printf("%d",minp->data); //输出最小值结点元素
		minpre->next = minp->next; //最小值结点从表中"断开"
		free(minp);
	}
	free(L); //释放头结点
}

20.
在这里插入图片描述
在这里插入图片描述

DLNode *Locate(DLNode *&L,int x)
{//本算法先查找数据x,查找成功时结点的访问频度域+1
 //最后将该结点按频度递减插入链表中适当的位置(同频度最近访问的在前面)
 	DLNode *p = L->next,*q; //p为工作指针,q为p的前驱,用于查找插入位置
 	while(p != NULL && p->data != x)
 		p = p->next;
 	if(p == NULL)
 		printf("不存在值为x的结点\n");
 		return NULL;
 	else
 	{
 		p->freq++; //令元素值为x的结点的freq域+1
 		p->next->pred = p->pred;
 		p->pred->next = p->next; //将p结点从链表上摘下
 		q = p->pred;
 		while(q != L && q->freq <= p->freq)
 			q = q->pred;
 		p->next = q->next;
 		p->pred = q;
 		q->next->pred = p;
 		q->next = p;
 	}
 	return p;	
}

21.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

typedef int ElemType; //链表数据的类型定义
typedef struct LNode
{
	ElemType data;
	struct LNode *link;
}LNode;
int Search(LNode *list,int k)
{
	LNode *p = list->link;
	LNode *q = list->link; //指针p,q指示第一个结点
	int count = 0;
	while(p != NULL) //遍历链表直到最后一个结点
	{
		if(count < k) //计数,若count<k只移动p
			count++;
		else
			q = q->list; //之后让p,q同步移动
		p = p->link;
	}
	if(count < k)
		return 0;
	else
	{
		printf("%d",q->data);
		return 1;
	}
}

22.
在这里插入图片描述
在这里插入图片描述

typedef struct Node
{
	char data;
	struct Node *next;
}Node;
//求链表长度的函数
int listLength(Node *head)
{
	int len = 0;
	while(head->next != NULL)
	{
		len++;
		head = head->next;
	}
	return len;
}
//找到共同后缀的起始地址
Node *findCommon(Node *str1,Node *str2)
{
	int m,n;
	Node *p,*q;
	m = listLength(str1); //求str1的长度
	n = listLength(str2); //求str2的长度
	for(p=str1;m>n;m--) //若m>n,使p指向链表中的第m-n+1个结点
		p = p->next;
	for(q=str2;m<n;n--) //若m<n,使q指向链表中的第n-m+1个结点
		q = q->next;
	while(p->next != NULL && q->next != NULL && p->next != q->next)
	{ //将指针p和q同步向后移动
		p = p->next;
		q = q->next;
	}
	return p->next;
}

23.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

typedef struct LNode
{
	int data;
	struct LNode *link;
}LNode;
void findAndDelete(LNode *head,int n)
{
	LNode *p =head;
	LNode *r;
	int *q;
	int m;
	q = (int *)malloc(sizeof(int)*(n+1)); //申请n+1个位置的辅助空间
	for(int i=0;i<n+1;i++)
	{
		*(q+i) = 0; //为辅助数组赋值为0
	}
	while(p->link != NULL)
	{
		m = p->link->data>0? p->link->data:-(p->link->data);
		if(*(q+m) == 0) //判断该结点的data是否已经出现
		{
			*(q+m) == 1; //首次出现
			p = p->link; //保留
		}
		else //重复出现
		{
			r = p->link;
			p->link = r->link; //删除
			free(r);
		}
	}
	free(q);
} //时间复杂度为O(m),空间复杂度为O(n);
### 关于王道操作系统第五章的内容总结 #### 文件系统概述 文件系统是操作系统的组成部分之一,负责管理磁盘或其他存储设备上的数据。它提供了创建、删除、读取和写入文件的功能,并支持目录结构以便更好地组织这些文件[^1]。 #### 文件的逻辑结构 - **流式文件**:由字符序列组成的一维数据集合。 - **记录式文件**:由固定长度或可变长度的记录组成的二维数据表。 这两种类型的文件各有优缺点,在实际应用中可以根据需求选择合适的类型来表示信息[^2]。 #### 文件的物理结构 为了适应外存分配方式以及提高检索速度,通常采用以下几种形式组织文件: - 连续分配 - 链接分配 - 索引分配 每种方法都有其特定场景下的优势与局限性,了解它们有助于设计更高效的存储方案[^3]。 #### 目录管理 为解决重名问题并简化用户操作体验,现代文件系统普遍采用了多层次树形目录结构。通过引入路径概念区分不同层次间的关系,使得定位某个具体位置变得简单明了[^4]。 #### 存储空间管理 针对磁盘等辅助存储器而言,主要涉及空闲块管理和分配策略两大部分内容。前者常用位图法、链表法等方式标记哪些区域处于可用状态;后者则依据请求大小决定如何划分资源给待处理的任务使用[^5]。 #### 文件共享与保护机制 允许多个进程或者用户之间相互访问某些指定范围内的资料称为文件共享。与此同时还需要建立相应的权限控制体系防止非法入侵行为发生,保障信息安全可靠[^6]。 ```c++ // 示例代码展示简单的文件打开关闭功能 #include <iostream> #include <fstream> int main() { std::ofstream outFile; outFile.open("example.txt"); if(outFile.is_open()){ outFile << "This is an example of file handling.\n"; outFile.close(); } else{ std::cout<<"Unable to open file\n"; } return 0; } ``` #### 常见习题解答示例 假设有一道题目如下:“如果一个文件被分成若干簇(cluster),而每个簇又进一步划分为多个扇区(sector)。那么当我们要寻找某条记录所在的精确地址时应该怎么做?” 答案要点在于理解寻址过程中的计算原理——即先确定目标位于哪一个簇之中再细化至具体的扇区内偏移量位置即可完成整个查询动作[^7]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值