DS--链表的概念及单链表接口的实现及其应用

链表

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

链表的结构类型可分为:
1,单链表,双向链表
2,不带头单链表,带头链表
3,单链表,循环单链表

链表的实现

一,单链表接口的实现
声明文件SList.h

SList.h
#ifndef _SLIST_H_
#define _SLIST_H_

#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<assert.h>
#include<math.h>
#pragma warning(disable:4996)


typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SListNode;


void SListInit(SListNode** pphead);

void SListDestory(SListNode** pphead);

SListNode* BuySListNode(SLTDataType x);

void SListPushFront(SListNode** pphead, SLTDataType x);

void SListPopFront(SListNode** pphead);
SListNode* SListFind(SListNode* phead, SLTDataType x);

void SListInsertAfter(SListNode* pos, SLTDataType x);

void SListEraseAfter(SListNode* pos);
void SListRemove(SListNode** pphead, SLTDataType x);

void SListPrint(SListNode* phead);


#endif

实现文件SList.c

SList.c
#include"SList.h"

void SListInit(SListNode** pphead)//将头指针进行初始化,所以需要二级指针来接收头指针的地址,对二级指针解引用(头指针)将其的data和next都置为NULL
{
	*pphead = NULL;
	/**pphead = (SListNode*)malloc(sizeof(SListNode));
	(*pphead)->data = 0;
	(*pphead)->next = NULL;*/
}

SListNode* BuySListNode(SLTDataType x)//重新申请一个新的节点,通过tmp来指向这个节点,将其数据部分赋值为x,next置为空
{
	SListNode *tmp = (SListNode*)malloc(sizeof(SListNode));
	assert(tmp);
	tmp->data = x;
	tmp->next = NULL;
	return tmp;
}

SListNode* SListFind(SListNode* phead, SLTDataType x)//找到与x相同的数字的地址并返回,需要一个tmp变量来进行遍历知道找到和x相同的数据的地址返回
{
	SListNode *tmp = phead;
	for (tmp = phead; tmp; tmp = tmp->next)
	{
		if (tmp->data == x)
		{
			return tmp;
		}
	}
}

void SListPopFront(SListNode** pphead)//头删,由于需要进行头删操作所以我们就需要定义一个二级指针来指向头phead,定义一个tmp来保存头所指向的目标,再把tmp的地址传给二级指针pphead
{
	if (*pphead == NULL)
	{
		return;
	}
	SListNode *tmp = (*pphead)->next;
	free(*pphead);
	*pphead = tmp;
}

void SListPushFront(SListNode** pphead, SLTDataType x)//头插,首先要申请一个新的节点,然后让这个新节点的next指向phead,然后再将pphead指向tmp
{
	SListNode *tmp = BuySListNode(x);
	tmp->next = *pphead;
	*pphead = tmp;
}

void SListInsertAfter(SListNode* pos, SLTDataType x)//后插
{
	SListNode *tmp = BuySListNode(x);
	tmp->next = pos->next;
	pos->next = tmp;
}

void SListEraseAfter(SListNode* pos)//后删
{
	SListNode *tmp = pos->next;
	if (tmp == NULL)
	{
		return;
	}
	pos->next = tmp->next;
	free(tmp);
}

void SListRemove(SListNode** pphead, SLTDataType x)
{
	SListNode *tmp = NULL;
	if ((*pphead)->data == x)
	{
		SListPopFront(pphead);
		return;
	}
	for (tmp = *pphead; tmp->next; tmp = tmp->next)
	{
		if (tmp->next->data == x)
		{
			SListEraseAfter(tmp);
			return;
		}
	}
}
void SListRemoveAll(SListNode** pphead, SLTDataType x)
{
	SListNode *tmp = NULL;
	if (*pphead&&(*pphead)->data == x)
	{
		SListPopFront(pphead);
	}
	for (tmp = *pphead; tmp&&tmp->next;)
	{
		if (tmp->next->data == x)
		{
			SListEraseAfter(tmp);
		}
		else
		{
			tmp = tmp->next;
		}
	}
}

void SListPrint(SListNode* phead)
{
	SListNode *tmp = phead;
	for (tmp = phead; tmp; tmp = tmp->next)
	{
		printf("->%d ", tmp->data);
	}
	tmp = NULL;
}

void SListDestory(SListNode** pphead)//从头结点开始,删除其后的每一个节点,直到只剩下头结点,最后free头结点
{
	if (*pphead == NULL)
	{
		return;
	}
	while ((*pphead)->next)
	{
		SListEraseAfter(*pphead);
	}
	free(*pphead);
	*pphead = NULL;
}

测试文件main.c

main.c
#include"SList.h"

int main()
{

	SListNode *head;
	SListInit(&head);
	SListPushFront(&head, 5);
	SListPushFront(&head, 5);
	SListPushFront(&head, 3);
	SListPushFront(&head, 5);
	SListPushFront(&head, 5);
	//SListPopFront(&head);
	SListInsertAfter(SListFind(head,4), 10);
	//SListRemove(&head, 4);
	_SListReverse(&head);


	SListPrint(head);
	system("pause");
	return 0;
}

二,单链表的应用(函数需要在头文件声明,main函数实现)
1,反转一个单链表(题目详情见https://leetcode-cn.com/problems/reverse-linked-list/description/)

//反转一个单链表
//方法一
void SListReverse(SListNode** pphead)
{
	SListNode *oldh = *pphead;//定义一个oldh指针指向头,始终指向原有的头结点
	SListNode *head = *pphead;//定义一个head指针指向头,指向不断更新的头结点
	SListNode *tmp = head->next;//tmp始终指向oldh的下一个    
	while (tmp)
	{
		oldh->next = tmp->next;//断开tmp,旧头指向tmp的下一个
		tmp->next = head;//tmp每次指向新的头
		head = tmp;//将head挪到新的头
		tmp = oldh->next;//将tmp挪到旧头oldh的下一个
	}
	*pphead = head;//逆转结束后,将新的头赋给phead
}
//方法二
void _SListReverse(SListNode** pphead)
{
	SListNode *pre = *pphead;
	SListNode *cur = pre->next;
	SListNode *next = cur;
	pre->next = NULL;//让头变成尾
	while (next)
	{
		next = next->next;//next右移一位
		cur->next = pre;//将原本指向下一位的反转指向上一位
		pre = cur;//将cur给pre
		cur = next;//将next给cur(cur指向next)
	}
	*pphead = pre;
}

2,输入两个链表,找它们的第一个公共结点(题目详情见https://leetcode-cn.com/problems/intersection-of-two-linked-lists/description/)

//两个链表找他们的第一个公共节点(右对齐)
SListNode *getIntersectionNode(SListNode *headA, SListNode *headB)
{
	SListNode *longerlist=headA;
	SListNode *shorterlist=headB;
	SListNode *cur;
	int lenA=0;
	int lenB=0;
	int gap = 0;
	int i = 0;
	for (cur = headA; cur; cur = cur->next)
	{
		lenA++;
	}
	for (cur = headB; cur; cur = cur->next)
	{
		lenB++;
	}
	gap = abs(lenA - lenB);//找到两个链表的长度之差
	if (lenA < lenB)
	{
		longerlist = headB;
		shorterlist = headA;
	}
	for (i = 0; i < gap; i++)//让长的链表走到和短的链表一样的起点
	{
		longerlist = longerlist->next;
	}
	for (; longerlist&&shorterlist; longerlist = longerlist->next, shorterlist = shorterlist->next)//让两链表一起走直到找到两链表相同的地址结束循环
	{
		if (longerlist == shorterlist)
		{
			return longerlist;//返回找到的地址(即这两个链表的第一个公共节点)
		}
	}
	return NULL;
}

3,给定一个链表,返回链表开始入环的第一个节点,如果链表无环,则返回NULL(题目详情见https://leetcode-cn.com/problems/linked-list-cycle-ii/description/)

//找一个链表入环的第一个节点,如果无环返回NULL
SListNode *detectCycle(SListNode *head)//设置两个指针fast和slow,fast的速度是slow的两倍,当fast与slow相等的时候就是他们的相遇点
{
	SListNode *fast = head;
	SListNode *slow = head;
	while (fast&&slow&&fast->next)
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast == slow)
		{
			break;
		}
	}
	for (; fast&&fast->next; fast = fast->next, head = head->next)//从相遇点和从头节点到入环的第一个相遇点的距离是一样的,当找到他们距离相等的点就是入环的第一个节点
	{
		if (fast == head)
		{
			return fast;
		}
	}
}

约瑟夫环问题

int __main()
{
	SListNode *phead;
	SListNode *plast;
	SListNode *cur;
	int m = 6, n = 5;
	int i;
	SListInit(&phead);
	SListPushFront(&phead, m);
	plast = phead;
	for (i = m - 1; i >= 1; i--)
	{
		SListPushFront(&phead, i);
	}
	plast->next = phead;

	cur = plast;
	for (; m > 1; m--)
	{
		for (i = 1; i < n; i++)
		{
			cur = cur->next;
		}
		SListEraseAfter(cur);
	}

	printf("%d", cur->data);

	free(cur);
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44930562/article/details/97101105
今日推荐