【数据结构】不带头单向不循环链表的实现

空链表结构:
在这里插入图片描述
有结点的链表结构:
在这里插入图片描述

不带头单向不循环链表的特性

  1. 链表在头删和尾删,或者按值删除时,要考虑链表是否为空。
  2. 尾插的时候也要注意此时链表是否为空。
  3. 单链表和顺序存储结构不同,它是一种动态结构。整个可用存储空间可为多个链表共同享用,每个链表占用的空间不需要预先分配划定,而是可以应需求即时生成。

不带头单向不循环链表的定义及功能实现

///slist.h
#pragma once
#include"commen.h"

#define ElemType int
typedef struct SListNode
{
	ElemType data;
	struct SListNode* next;
}SListNode;

//不带头结点的单链表
typedef SListNode* SList;

void SListInit(SList* phead);
void SListDestroy(SList* phead);
void SListShow(SList phead);
void SListPushBack(SList* phead,ElemType x);
void SListPushFront(SList* phead,ElemType x);
void SListPopBack(SList* phead);
void SListPopFront(SList* phead);
size_t SListLength(SList phead);
SListNode* SListFind(SList phead, ElemType key);
void SListEraseByVal(SList* phead, ElemType key);
void SListSort(SList* phead);
void SListInsertByVal(SList* phead,ElemType x);
ElemType SListFront(SList* phead);
ElemType SListBack(SList* phead);
void SListEraseAll(SList* phead, ElemType x);
void SListClean(SList* phead);
void SListReverse(SList* phead);

///

void SListInit(SList* phead)
{
	assert(phead != NULL);
	*phead = NULL;
}
void SListShow(SList phead)
{
	//assert(phead != NULL);//不检查链表为空的情况,使得空链表也可以打印出来
	SListNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("over\n");
}
void SListPushBack(SList* phead, ElemType x)
{
	assert(phead != NULL);
	SListNode* node = (SListNode*)malloc(sizeof(SListNode));
	assert(node != NULL);
	node->data = x;
	node->next = NULL;

	//链接结点
	SListNode* cur = *phead;
	if (cur == NULL)//插入的结点为第一个结点
		*phead = node;
	else
	{
		while (cur->next != NULL)
			cur = cur->next;
		cur->next = node;
	}
}
void SListPushFront(SList* phead, ElemType x)
{
	assert(phead != NULL);
	//创建新结点
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	assert(newnode);
	newnode->data = x;
	//对新结点进行插入
	newnode->next = *phead;
	*phead = newnode;

}

size_t SListLength(SList phead)
{
	assert(phead != NULL);
	SListNode* cur = phead;
	size_t count = 0;
	while (cur != NULL)
	{
		++count;
		cur = cur->next;
	}
	return count;
}

void SListPopBack(SList* phead)
{
	assert(phead != NULL);
	SListNode* cur = *phead;
	SListNode* pre = NULL;
	if (*phead == NULL)
		printf("该链表为空,无法删除\n");
	else
	{
		while (cur->next != NULL)
		{
			pre = cur;
			cur = cur->next;
		}
		free(cur);
		cur = NULL;
		//如果只有一个结点时,pre == NULL
		if (pre == NULL)
			*phead = NULL;
		else
			pre->next = NULL;
	}	
}
void SListPopFront(SList* phead)
{
	assert(phead != NULL);
	if (*phead == NULL)
		printf("该链表为空,无法删除\n");
	else
	{
		SListNode* cur = *phead;
		*phead = cur->next;
		free(cur);
		cur = NULL;
	}
}
SListNode* SListFind(SList phead, ElemType key)
{
#if 0
	SListNode* cur = phead;
	while (cur != NULL)
	{
		if (cur->data == key)
			return cur;
		cur = cur->next;
	}
	return NULL;
#endif
	SListNode* cur = phead;
	while (cur != NULL && cur->data != key)
		cur = cur->next;
	return cur;
}
void SListEraseByVal(SList* phead, ElemType key)
{
#if 0
	assert(phead != NULL);
	SListNode* node = SListFind(*phead, key);
	if (node == NULL)
		printf("该元素%d不存在,无法删除\n", key);
	else
	{
		if (node->next == NULL)//所要删除的结点是最后一个结点
			SListPopBack(phead);
		else
		{
			//标记要删除结点的下一个结点
			SListNode* p = node->next;
			//将下一个结点的元素覆盖到要删除元素的位置,那么要删除的元素变成了node->next
			node->data = p->data;
			//移除要删除的结点
			node->next = p->next;
			free(p);
			p = NULL;
		}
	}
#endif
	assert(phead != NULL);
	SListNode* p = SListFind(*phead, key);
	if (p == NULL)
		printf("元素%d不存在,无法正常删除\n",key);
	else
	{
		SListNode* prev = *phead;
		while (prev != p && prev->next != p)
		{
			prev = prev->next;
		}
		if (prev == p)//第一个结点就是要找的结点p
			*phead = p->next;
		else
			prev->next = p->next;
		free(p);
		p == NULL;
	}
}

void SListSort(SList* phead)
{
	assert(phead != NULL);
	if (SListLength(*phead) == 1)
		return;
	//将链表分成成两段
	SListNode* p = *phead;
	SListNode* q = p->next;
	p->next = NULL;

	SListNode* prev = NULL;
	SListNode* cur = *phead;

	while (q != NULL)
	{
		p = q;
		q = q->next;
		while (cur != NULL && p->data > cur->data)
		{
			prev = cur;
			cur = cur->next;
		}
		if (prev == NULL)//头插
		{
			p->next = *phead;
			*phead = p;
		}
		else
		{
			p->next = cur;
			prev->next = p;
		}
		prev = NULL;
		cur = *phead;
	}
}
void SListInsertByVal(SList* phead, ElemType x)
{
	assert(phead != NULL);
	SListNode *cur = *phead,*prev = NULL;
	SListNode* node = (SListNode*)malloc(sizeof(SListNode));
	assert(node != NULL);
	node->data = x;
	
	while (cur != NULL && cur->data < x)
	{
		prev = cur;
		cur = cur->next;
	}
	if (prev == NULL)
	{
		node->next = *phead;
		*phead = node;
	}
	else
	{
		node->next = cur;
		prev->next = node;
	}
}
ElemType SListFront(SList* phead)
{
	assert(phead != NULL);
	if (*phead == NULL)
		return -1;
	else
		return (*phead)->data;
}
ElemType SListBack(SList* phead)
{
	assert(phead);
	if (*phead == NULL)
		return -1;
	SListNode* cur = *phead;
	while (cur->next != NULL)
		cur = cur->next;
	return cur->data;
}
void SListEraseAll(SList* phead,ElemType x)
{
	assert(phead != NULL);
	SListNode* node = NULL;
	while (*phead != NULL && (*phead)->data == x)//如果第一个元素就是要删除的元素
	{
		node = *phead;
		*phead = (*phead)->next;
		free(node);
		node = NULL;
	}
	if (*phead == NULL)
		return;
	SListNode* cur = *phead;
	SListNode* prev = NULL, * next = cur->next;
	while (cur != NULL)
	{	
		if (cur->data == x)
		{
			free(cur);
			cur = prev;
			prev->next = next;
		}
		prev = cur;
		cur = next;
		if(cur != NULL)
			next = cur->next;
	}
}

void SListClean(SList* phead)
{
	assert(phead);
	SListNode* cur = NULL;
	while (*phead != NULL)
	{
		cur = *phead;
		*phead = (*phead)->next;
		free(cur);
		cur = NULL;
	}
}
void SListDestroy(SList* phead)
{
	SListClean(phead);//不带头的链表的清除与销毁操作一致
}
void SListReverse(SList* phead)//头插
{
	assert(phead != NULL);
	SListNode* p = *phead;
	SListNode* q = p->next;
	p->next = NULL;

	while (q != NULL)
	{
		p = q;
		q = q->next;
		p->next = *phead;
		*phead = p;
	}
}


不带头单向不循环链表的功能测试模块

//test.c
#define _CRT_SECURE_NO_WARNINGS
#include"commen.h"
#include"slist.h"
int main()
{
	SList list;
	SListInit(&list);

	SListNode* p = NULL;
	ElemType item;
	int select = 1;
	size_t pos;
	while (select)
	{
		printf("**************************************************\n");
		printf("***********************MENU***********************\n");
		printf("*  [1]push_back                   [2]push_front  *\n");
		printf("*  [3]show_list                   [0]quit_system *\n");
		printf("*  [4]pop_back                    [5]pop_front   *\n");
		printf("*  [6]insert_val                  [7]erase_val   *\n");
		printf("*  [8]find                        [9]length      *\n");
		printf("*  [10]earse_all                  [11]sort       *\n");
		printf("*  [12]reverse                    [13]clean      *\n");
		printf("*  [14]front                      [15]back       *\n");
		printf("**************************************************\n");
		printf("**************************************************\n");
		printf("请选择->\n");
		scanf("%d", &select);
		if (select == 0)
			break;
		switch (select)
		{
		case 0:
			select = 0;
			break;
		case 1:
			printf("请输入要插入的元素,若要退出,输入-1->\n");
			while (scanf("%d", &item), item != -1)
			{
				SListPushBack(&list, item);
			}
			break;
		case 2:
			printf("请输入要插入的元素,若要退出,输入-1->\n");
			while (scanf("%d", &item), item != -1)
			{
				SListPushFront(&list, item);
			}
			break;
		case 3:
			SListShow(list);
			break;
		case 4:
			SListPopBack(&list);
			break;
		case 5:
			SListPopFront(&list);
			break;
		case 6:
			printf("请输入要插入的元素->\n");
			scanf("%d", &item);
			SListSort(&list);
			SListInsertByVal(&list, item);
			break;
		case 7:
			printf("请输入要删除的元素->\n");
			scanf("%d", &item);
			SListEraseByVal(&list, item);
			break;
		case 8:
			printf("请输入要查找的元素->\n");
			scanf("%d", &item);
			p = SListFind(list, item);
			if (p == NULL)
				printf("元素%d不存在\n", item);
			else
				printf("元素%d所在的位置为%d", item, p);
			break;
		case 9:
			printf("length = %d\n", SListLength(list));
			break;
		case 10:
			printf("请输入要删除的元素->\n");
			scanf("%d", &item);
			SListEraseAll(&list,item);
			break;
		case 11:
			SListSort(&list);
			break;
		case 12:
			SListReverse(&list);
			break;
		case 13:
			SListClean(&list);
			break;
		case 14:
			if (SListFront(&list) == -1)
				printf("该顺序表为空,无法获取其头部元素\n");
			else
				printf("头元素为%d\n", SListFront(&list));
			break;
		case 15:
			if (SListBack(&list) == -1)
				printf("该顺序表为空,无法获取其尾部元素\n");
			else
				printf("末尾元素为%d\n", SListBack(&list));
			break;
		default:
			printf("输入非法,请重新选选择->\n");
			break;
		}
		system("pause");
		system("cls");
	}
	SListDestroy(&list);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值