数据结构 线性表的基础操作 C/C++代码实现 #2

线性表的链式存储结构C语言实现

首先是结构体:

typedef struct Lnode
{
	int info;
	Lnode* next;
}node,*pnode;

我们选择建立一个带头结点的链表,有了头结点方便插入。头结点的信息部分还可以存放链表的长度,但是信息部分不一定有int类型的存储结构,这些还是看具体情况吧。

当然我们还可以用这样的结构体,记录一些关于链表的信息,不过之后的代码都会使用之前提到的“Lnode”结构体。

typedef struct node
{
    int info;
    node *next;
}node,*pnode;
typedef struct Line
{
    pnode firstnode;//指向头节点
    int length;//记录表长
    pnode lastnode;//指向尾结点
}Line,*pLine;

1.创建线性表

int initlist(pnode &list)
{
	if (list != NULL)
	{
		printf_s("指针不为空,很有可能丢失原有的链表\n");
		return 1;
	}
	else
	{
		list = (pnode)malloc(sizeof(node));
		if (list != NULL)
		{
			list->next = NULL;
			//list->info = 0;
			//头节点中可以存放相关数据,比如这里我可以放单链表的长度。
			//但这只是一种投机取巧的办法,并不能适用于所有情况,所以之后的代码中没有关于这一点的利用。
		}
			return 0;
	}
}

2.销毁线性表

int destroylist(pnode& list)
{
	if (list == NULL)
	{
		printf_s("指针为空,链表已经不存在。");
		//我看过很多人的代码,他们似乎不在乎指针原本是否为空,只要销毁链表就达到目的
		//但是我觉得传入一个空的指针给销毁函数本身就是一种异常。
		return 1;
	}
	while (list)
	{
		pnode keep = list;
		list = list->next;
		free(keep);
	}
	return 0;
}

3.清空线性表

int clearlist(pnode& list)
{
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	pnode p;
	p = list->next;
	list->next = NULL;
	if(p==NULL)
		return 0;
	else
	{
		while (p)
		{
			pnode keep = p;
			p = p->next;
			free(keep);
		}
	}
	return 0;
}

4.检查线性表是否为空

int listempty(pnode list)
{
	if(list==NULL)
	{
		printf_s("线性表不存在,返回-1\n");
		return -1;
	}
	if (list->next == NULL)
		return 1;
	else
		return 0;
}

5.返回线性表数据元素的个数

int listlength(pnode list)
{
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return -1;
	}
	int lenth = 0;
	pnode p=list;
	if (p->next == NULL)
		return 0;
	else
	{
	    p = p->next;
		while (p!=NULL)
		{
			p = p->next;
			lenth++;
		}
	}
	return lenth;
}

6.返回线性表中指定位置的元素的值

int getinfolist(pnode list,int i,int &e)
{
	int listlength(pnode);
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	int lenth = listlength(list);
	if (lenth == 0)
	{
		printf_s("链表为空,无法找到数据\n");
		return 3;
	}
	if (i > lenth)
	{
		printf_s("该位置没有存储数据\n");
		return 2;
	}
	pnode p = list;
	for (int j = 1; j <= i; j++)
	{
		p = p->next;
	}
	return p->info;
}

7.找到符合条件的元素,返回其位置

bool compare(int a, int b)
{
	return a < b;
}
bool (*comparing)(int a, int b) = compare;
int locateelemlist(pnode list, int e, bool (*compare)(int a, int b))
{
	int listlength(pnode);
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	int lenth = listlength(list);
	if (lenth == 0)
	{
		printf_s("链表为空,无法找到数据\n");
		return 3;
	}
	pnode p = list->next;
	for (int i = 1; i <= lenth; i++)
	{
		if (compare(e, p->info))
		{
			return i;//compare 表示如果a>b则为true;结果返回的就是线性表中第一个比e小的数字的位置
		}
		p = p->next;
	}
	return -1;//没有比e小的数字则返回-1;
}

8.返回线性表中指定元素的前一个元素的位置

int get_prior(pnode list, int numth, pnode& prior)
{
	prior = NULL;
	int listlength(pnode);
	if (list == NULL)
	{
		//printf_s("线性表不存在\n");
		return 1;
	}
	int lenth = listlength(list);
	if (numth > lenth + 1)
	{
		//printf_s("超出链表范围\n");
		return 2;
	}
	pnode p = list;
	for (int i = 1; i <= numth; i++)
	{
		if (i == numth)
		{
			prior = p;
			break;
		}
		else
			p = p->next;
	}
	return 0;
}

9.返回线性表中指定元素的后一个元素的位置

int get_next(pnode list, int numth, pnode& next)
{
	next = NULL;
	//提前置为空,之后的三种特殊情况都会返回NULL
	int listlength(pnode);
	if (list == NULL)
	{
		//printf_s("线性表不存在\n");
		return 1;
	}
	int lenth = listlength(list);
	if (lenth == 0)
	{
		//printf_s("链表为空\n");
		return 2;
	}
	if (numth > lenth - 1)
	{
		//printf_s("位置超出存在后继范围,不存在后继\n");
		return 3;
	}
	pnode p = list->next;
	for (int i = 0; i <= numth; i++)
	{
		if (i == numth)
		{
			next = p;
			break;
		}
		else
			p = p->next;
	}
	return 0;
}

10.在线性表指定位置插入一个元素

链表中插入元素需要找到该元素的前驱和该元素的位置。当然,找到了该元素的前驱就自然而然的找到了该元素的位置,毕竟两者是相邻的。需要注意的是,我的代码中,链表的下标是从1开始的,而上一篇的顺序表下标是从0开始的。

int listinsert(pnode list, int numth, int e)
{
	int get_prior(pnode, int, pnode&);
	int listlength(pnode);
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	int lenth = listlength(list);
	if (numth > lenth+1)
	{
		printf_s("位置无效,无法插入\n");
		return 3;
	}
	pnode newnode = (pnode)malloc(sizeof(node));
	if (newnode != NULL)
	{
		newnode->info = e;
		newnode->next = NULL;
		pnode pre=NULL;
		get_prior(list, numth, pre);
		pnode mid = pre->next;
		newnode->next = mid;
		pre->next = newnode;
		return 0;
	}
	else return 4;
}

11.删除线性表中指定位置的元素

int ListDelete(pnode& list, int numth, int& e)
{
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	int listlength(pnode);
	int lenth = listlength(list);
	if (lenth == 0)
	{
		printf_s("链表为空\n");
		return 2;
	}
	if (numth > lenth)
	{
		printf_s("位置无效,无法删除\n");
		return 3;
	}
	int get_prior(pnode, int, pnode&);
	int get_next(pnode, int, pnode&);
	pnode mid, pre, next;
	get_prior(list, numth, pre);
	get_next(list, numth, next);
	mid = pre->next;
	e = mid->info;
	pre->next = next;
	free(mid);
	return 0;
}

12.遍历线性表

void visit(int e)
{
	printf_s("%d ", e);
	return;
}

void (*q)(int a) = visit;

int List1Traverse(pnode list, void (*visit1)(int a))
{
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	int listlength(pnode);
	int lenth = listlength(list);
	if (lenth == 0)
	{
		printf_s("链表为空\n");
		return 2;
	}
	pnode p = list->next;
	for (; p != NULL; p = p->next)
	{
		visit1(p->info);
	}
	printf_s("\n");
	return 0;
}

为了方便的建立链表,我这次设计了两个函数,分别代表头插法和尾插法。
1.头插法

int List1push_pre(pnode& list, int e)
{
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	int listinsert(pnode, int, int);
	listinsert(list, 1, e);
	return 0;
}

2.尾插法

int List1push_back(pnode& list, int e)
{
	if (list == NULL)
	{
		printf_s("线性表不存在\n");
		return 1;
	}
	int listinsert(pnode, int, int);
	int listlength(pnode);
	listinsert(list, listlength(list)+1, e);
	return 0;
}

其实只是限制了函数‘listinsert’的插入位置,并没有太大的区别。

我就不写总体的实现了,写过一遍之后就知道那并没有什么意思,=_=

顺序表的C++的实现,只是申请动态空间的方式不一样而已。其实并没有太大的区别。

所以下一篇我会介绍一下 <vector>的使用方法,了解了这个,你甚至会开始怀疑我们学习C语言的线性表到底是为了什么。@_@

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值