数据结构之单链表的基本操作及常考题型

版权声明:转载请联系 :[email protected] https://blog.csdn.net/weixin_40928253/article/details/80725442

// 倒叙打印链表

void ReversePrint(SListNode *pFirst); 

// 逆置链表

SListNode * ReverseList(SListNode *pFirst); 

// 删除非尾无头链表

void RemoveNodeNotTail(SListNode *pos); 

// 无头链表前插入

void InsertNoHead(SListNode *pos, int data); 

约瑟夫环

SListNode * JocephCircle(SListNode *pFirst, int k);

// 冒泡排序

void BubbleSort(SListNode *pFirst);

// 合并两个有序链表

SListNode * MergeOrderedList(SListNode *p1First, SListNode *p2First); 

// 遍历一次,找到中间结点

SListNode * FindMid(SListNode *pFirst); 

// 遍历一次,找到倒数第 k 个结点(k从1开始)

SListNode * FindK(SListNode *pFirst, int k);

验证后结果为:

具体实现看代码,代码如下:

Interview.h

#pragma once
#include "SList.h"

//从头到尾打印单链表
void Print(SListNode *pFirst){
	SListNode *pNode = pFirst;
	SListNode *end = NULL;
	while (end != pFirst)
	{
		while (pNode->pNext != end)
		{
			pNode = pNode->pNext;
		}
		end = pNode;
		printf("%d", pNode->data);
		pNode = pFirst;
	}
}

void Show(SListNode *p){
	if (p->pNext){
		Show(p->pNext);
	}
	printf("<- %d", p->data);
}

void TestPrintR(){
	SListNode *pFirst = NULL;
	printf("从头到尾打印单链表的结果是:5");
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	Show(pFirst);
	printf("\n");
	printf("\n");
}

//逆置单链表
SListNode *ReverseSList(SListNode *pFirst)
{
	SListNode *pNewFirst = NULL;
	DataType data;
	while (pFirst != NULL)
	{
		data = pFirst->data;
		PopFront(&pFirst);            //头插
		PushFront(&pNewFirst, data);  //头删
	}
	return pNewFirst;
}
void TestReverse()
{
	SListNode *pFirst = NULL;
	printf("逆置单链表的结果是:");
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 5);
	SListNode *pNewFirst = ReverseSList(pFirst);
	Print(pNewFirst);
	printf("\n");
	printf("\n");
}

//删除无头链表的非尾节点 (不能遍历链表) 转换为删除pos指向的结点的下一个结点
//无头结点的链表:第一个节点既有数据域,又有指针域,是通过一个指向该链表的第一个节点的指针来标记该链表的,即可以成环。
void EraseNoFirstNotTail(SListNode *pPos)
{
	assert(pPos != NULL);
	SListNode *pNext = pPos->pNext;
	pPos->pNext = pNext->pNext;
	pPos->data = pNext->data;
	free(pNext);
}

//在无头单链表的一个节点前插入一个节点(不能遍历链表)
void InsertNoFirst(SListNode *pPos, DataType data)
{
	SListNode *pNewNode = (SListNode *)malloc(sizeof(SListNode));
	assert(pNewNode != NULL);

	pNewNode->data = pPos->data;
	pNewNode->pNext = pPos->pNext;
	pPos->data = data;
	pPos->pNext = pNewNode;
}

void TestReplaceMethod()
{
	SListNode *pFirst = NULL;
	printf("插入节点后的结果是:");
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 5);
	SListNode *pFound = Find(pFirst, 4);
	InsertNoFirst(pFound, 7);
	Print(pFirst);
	printf("\n");
	printf("\n");
	printf("删除无头链表非尾节点7后的结果是:");
	EraseNoFirstNotTail(pFound);
	Print(pFirst);
	printf("\n");
	printf("\n");
}

//合并两个有序链表,合并后依旧有序
SListNode *MergeOrderedList(SListNode *p1First, SListNode *p2First)
{
	SListNode *p1 = p1First;
	SListNode *p2 = p2First;
	SListNode *pNewFirst = NULL;
	while (p1 != NULL&&p2 != NULL)
	{
		if (p1->data < p2->data)
		{
			PushBack(&pNewFirst, p1->data);
			p1 = p1->pNext;
		}
		else
		{
			PushBack(&pNewFirst, p2->data);
			p2 = p2->pNext;
		}
	}
	SListNode *pNotEmpty = p1;
	if (p1 == NULL)
	{
		pNotEmpty = p2;
	}
	while (pNotEmpty)
	{
		PushBack(&pNewFirst, pNotEmpty->data);
		pNotEmpty = pNotEmpty->pNext;
	}
	return pNewFirst;
}

void TestMergeOrderedList()
{
	SListNode *p1First = NULL;
	PushBack(&p1First, 1);
	PushBack(&p1First, 2);
	PushBack(&p1First, 3);
	PushBack(&p1First, 4);
	printf("有序链表1的结果是:");
	Print(p1First);
	printf("\n");
	SListNode *p2First = NULL;
	PushBack(&p2First, 5);
	PushBack(&p2First, 6);
	PushBack(&p2First, 7);
	PushBack(&p2First, 9);
	printf("有序链表2的结果是:");
	Print(p2First);
	printf("\n");
	SListNode *pMerged = MergeOrderedList(p1First, p2First);
	printf("两个有序链表合并的结果是:");
	Print(pMerged);
	printf("\n");
	printf("\n");
}

//约瑟夫环:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。
//从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,
//数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
//通常解决这类问题时我们把编号从0~n-1,最后 [1]  结果+1即为原问题的解。
SListNode *JocephCircle(SListNode *pFirst, int k)
{
	SListNode *pNode = pFirst;
	SListNode *pPrev = NULL;
	int i;
	while (pNode->pNext)
	{
		pNode = pNode->pNext;
	}
	pNode->pNext = pFirst;
	pNode = pFirst;
	while (pNode->pNext != pNode)
	{
		for (i = 0; i < k - 1; i++){
			pPrev = pNode;
			pNode = pNode->pNext;
		}
		pPrev->pNext = pNode->pNext;
		free(pNode);
		pNode = pPrev->pNext;
	}
	return pNode;
}
void TestJoceph()
{

	SListNode *pFirst = NULL;
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 5);
	PushBack(&pFirst, 6);
	PushBack(&pFirst, 7);
	printf("约瑟夫环为:");
	Print(pFirst);
	printf("\n");
	printf("按3删除后的结果是:");
	SListNode *pSuv = JocephCircle(pFirst, 3);
	printf("%d\n", pSuv->data);
	printf("\n");
}

//查找单链表的中间节点,要求只能遍历一次链表
//快慢指针
SListNode * FindMiddle(SListNode *pFirst)
{
	assert(pFirst != NULL);
	SListNode *pFast = pFirst;
	SListNode *pSlow = pFirst;
	while (1) {
		pFast = pFast->pNext;
		if (pFast == NULL) {
			break;
		}
		pFast = pFast->pNext;
		if (pFast == NULL) {
			break;
		}
		pSlow = pSlow->pNext;
	}
	return pSlow;
}

void TestFindMiddle()
{
	SListNode *pFirst = NULL;
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 5);
	PushBack(&pFirst, 6);
	PushBack(&pFirst, 7);
	PushBack(&pFirst, 5);
	PushBack(&pFirst, 6);
	PushBack(&pFirst, 7);
	printf("单链表是:");
	Print(pFirst);
	printf("\n");
	SListNode *pFound = FindMiddle(pFirst);
	printf("找到的中间结点是:");
	printf("%d\n", pFound->data);
	printf("\n");
}


void Swap(int* a, int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
	return;
}
//单链表实现冒泡排序
void BubbleSort(SListNode *pFirst)
{
	SListNode *pCur = pFirst;
	SListNode *pLast = pFirst;
	if (pFirst == NULL){
		return ;
	}
	for (pCur; pCur->pNext != NULL; pCur = pCur->pNext)
	{
		for (pLast;pLast ->pNext!=NULL ; pLast = pLast->pNext)
		{
			if (pLast->data  < pLast->pNext->data)
			{
				int temp = pLast->data;
				pLast->data = pLast->pNext->data;
				pLast->pNext->data = temp;
			}
		}
	}
	return;
}

void TestBubbleSort()
{
	SListNode *pFirst = NULL;
	PushBack(&pFirst, 1);	
	PushBack(&pFirst, 9);
	PushBack(&pFirst, 5);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 8);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	printf("单链表是:");
	Print(pFirst);
	printf("\n");
	BubbleSort(pFirst);
	BubbleSort(pFirst);
	BubbleSort(pFirst);
	BubbleSort(pFirst);
	BubbleSort(pFirst);
	BubbleSort(pFirst);
	printf("冒泡排序后的结果是:");
	Print(pFirst);
	printf("\n");
	printf("\n");
}

// 遍历一次,找到倒数第 k 个结点
SListNode * FindK(SListNode *pFirst, int k){
	if (k < 1 || pFirst ==NULL)
	{
		return NULL;
	}
	SListNode *pFast = pFirst;
	SListNode *pSlow = pFirst;
	for (int i = 0; i < k; i++)
	{
		if (pFast != NULL){
			pFast = pFast->pNext;
		}
		else
		{
			return NULL;
		}
	}
	while (pFast->pNext != NULL)
	{
		pFirst = pFirst->pNext;
		pFast = pFast->pNext;
	}
	return pFirst;
}

void TestFindK()
{
	SListNode *pFirst = NULL;
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 1);
	PushBack(&pFirst, 2);
	PushBack(&pFirst, 3);
	PushBack(&pFirst, 4);
	PushBack(&pFirst, 5);
	PushBack(&pFirst, 6);
	PushBack(&pFirst, 7);
	PushBack(&pFirst, 5);
	PushBack(&pFirst, 6);
	PushBack(&pFirst, 7);
	printf("尾插形成的单链表是:");
	Print(pFirst);
	printf("\n");
	SListNode *pFound = FindK(pFirst,1);
	printf("找到的下标为k的结点是:");
	printf("%d\n", pFound->data);
	printf("\n");
}

SList.h

#pragma once

#include <stdlib.h>
#include <assert.h>
#include <stdio.h>

//定义链表数据类型
typedef int DataType;

//定义链表数据结构
typedef struct SListNode{
	DataType data;             //当前节点中保存的元素
	struct SListNode *pNext;   //指向链表的下一个结点
}SListNode;

//链表初始化
void SListInit(SListNode **ppFirst)
{
	assert(ppFirst != NULL);  //assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行
	*ppFirst = NULL;
}

//链表销毁
void SListDestroy(SListNode **ppFirst){

	assert(ppFirst != NULL);
	SListNode *pNode, *pNext;
	pNode = *ppFirst;
	while (pNode != NULL){
		pNext = pNode->pNext;
		free(pNode);            //void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针。
								//如果分配失败,则返回一个空指针(NULL)。关于分配失败的原因,应该有多种,比如说空间不足就是一种。
								//void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,
								//也就是释放了这块内存,让它重新得到自由.free()释放的是指针指向的内存!
		pNode = pNext;
	}
	*ppFirst = NULL;
}

//创建新结点
SListNode *CreateNewNode(int data)
{
	SListNode *pNewNode = (SListNode*)malloc(sizeof(SListNode));  //malloc()是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。
	assert(pNewNode);
	pNewNode->data = data;
	pNewNode->pNext = NULL;
	return pNewNode;
}

//尾插
void PushBack(SListNode **ppFirst, DataType data)
{
	assert(ppFirst != NULL);
	SListNode *pNewNode = CreateNewNode(data);
	if (*ppFirst == NULL)
	{
		*ppFirst = pNewNode;
		return;
	}
	SListNode *pNode;
	pNode = *ppFirst;
	while (pNode->pNext != NULL)
	{
		pNode = pNode->pNext;
	}
	pNode->pNext = pNewNode;
}

//头插
void PushFront(SListNode **ppFirst, DataType data)
{
	assert(ppFirst != NULL);
	SListNode *pNewNode = CreateNewNode(data);
	pNewNode->pNext = *ppFirst;
	*ppFirst = pNewNode;
}

//头删
void PopFront(SListNode **ppFirst)
{
	assert(ppFirst != NULL);
	assert(*ppFirst != NULL);
	SListNode *pOldFirst = *ppFirst;
	*ppFirst = (*ppFirst)->pNext;
	free(pOldFirst);

}

SListNode * Find(SListNode *pFirst, DataType data)
{
	SListNode *pNode;
	for (pNode = pFirst; pNode; pNode = pNode->pNext) {
		if (pNode->data == data) {
			return pNode;
		}
	}
	return NULL;
}

Main.cpp

#include "Interview.h"

int main(void)
{
	TestPrintR();
	TestReverse();
	TestReplaceMethod();
	TestMergeOrderedList();
	TestJoceph();
	TestFindMiddle();
	TestBubbleSort();
	TestFindK();
	system("pause");
}

猜你喜欢

转载自blog.csdn.net/weixin_40928253/article/details/80725442
今日推荐