线性表2:链表的基本操作


此系列文主要用于自查、复习。所以行文、逻辑、思路是按照个人的思考方式来的,但也希冀能帮到一二三位初学者。

线性表的特点:
1.表头无前驱,表尾无后继
2.其他元素有且仅有一个直接前驱和一个直接后继

线性表有顺序存储结构和链式存储结构,下面介绍链式存储结构的单向链表。

链表的特点

优点: 删除和增加不会造成大量数据的移动
缺点: 查找、修改比较麻烦

链表的描述

描述: 数据域+指针域

typedef int datatype;

typedef struct node {
	datatype data;//数据域
	struct node * next;//保存下一个数据的地址
}linknode, * linklist;

基本操作

创建空链表

用malloc动态申请空间

linklist createLinkList()
{
	//1.申请头结点的空间
	linklist H = (linklist)malloc(sizeof(linknode));
	if(NULL == H)
	{
		printf("创建头结点失败\n");
		return NULL;
	}
	
	//2.给头结点赋值
	H->data = 0;
	H->next = NULL;
	
	//3.返回头节点
	return H;
}

第一种插入方式:头插

头插,新结点永远插入第一项(头结点不是第一项,头结点后面才是第一项)
头插

int headInsertLinkList(linklist H, datatype x)
{
	//1.申请新结点空间
	linklist pnew = (linklist)malloc(sizeof(linknode));
	if(NULL == pnew)
	{
		printf("申请新结点失败\n");
		return -1;
	}

	//2.给新结点赋值
	pnew->data = x;
	
	//3.新结点先保存头结点下一个数据的地址
	pnew->next = H->next;
	//4.将新结点接入头结点后面
	H->next = pnew;

	return 0;
}

输出链表

void showLinkList(linklist H)
{
	linklist p = H->next;

	while(p)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

求表长

int linkLength(linklist H)
{
	linklist p = H;
	int length = 0;
	
	while(p->next != NULL)
	{
		p = p->next;
		length++;
	}
	
	return length;
}

单链表中,取第i个元素必须从头结点出发寻找。
按位置查找,查找第pos项元素,返回其地址

linklist searchPos(linklist H, int pos)
{
	int count = -1;//计数:记录遍历的次数
	linklist p = H;
	int length = linkLength(H);
	
	if(pos<0 || pos>length)//1.判断位置是否合法
	{
		printf("位置不在表长范围内\n");
		return NULL;
	}
	
	//2.依次遍历直到pos
	while(count < pos)
	{
		p = p->next;
		count++;
	}
	
	return p;
}

第二种插入方式:任意位置插入新结点

利用上面的查找函数searchPos()找到要插入的前一个位置

int insertLinklist(linklist H, int pos, datatype x)
{
	//1.找到插入位置的前一项
	linklist p;
	if(0 == pos)
		p = H;
	else
		p = search(H, pos-1);

	if(NULL == p)
		return -1;

	//2.申请新结点
	linklist pnew = (linklist)malloc(sizeof(linknode));
	if(NULL == pnew)
	{
		printf("insert: 申请新结点失败\n");
		return -1;
	}

	//3.给新结点赋值
	pnew->data = x;
	//“先连后断”
	pnew->next = p->next;
	p->next = pnew;

	return 0;
}

删除结点
删

int deleteLinkList(linklist H, int pos)
{
	//判空
	if(NULL == H->next)
	{
		printf("链表为空\n");
		return -1;
	}
	
	//p保存删除的前一个位置, q保存要删除的位置
	linklist p = NULL, q = NULL;

	if(pos>=0 && pos<=linkLength(H))//保证位置有效
	{
		if(pos == 0)
			p = H;
		else		
			p = searchPos(H, pos-1);

		//保存删除结点
		q = p->next;
		//删除该结点
		p->next = q->next;
		//释放该结点
		free(q);
		q = NULL;
	}
	else
	{
		printf("deleteLinkList:the pos is error\n");
		return -1;
	}
		
	return 0;
}

逆序输出

利用头插法
在这里插入图片描述

void reverseLinkList(linklist H)
{
	//p保存无头链表的一个结点,q保存要接入头节点后面的结点
	linklist p = NULL, q = NULL;

	//1.一分为二,分为头结点和无头链表两部分
	p = H->next;
	H->next = NULL;

	//2.依次从无头链表中取第一个结点出来头插
	while(p != NULL)
	{
		//取无头链表的第一个结点
		q = p;
		p = p->next;

		q->next = H->next;
		H->next = q;
	}
}

排序

在这里插入图片描述

void orderLinkList(linklist H)
{
	linklist p = NULL;//保存无头链表的第一个结点
	linklist q = NULL;//保存插入结点
	linklist r = NULL;//保存要插入位置的前一个结点

	//1.一分为二,分为头结点和无头链表两部分
	p = H->next;
	H->next = NULL;

	//2.从无头链表中取第一个结点,有序插入到有头链表中
	while(p != NULL)
	{
		//取无头链表的第一个结点
		q = p;
		p = p->next;

		//从头开始找插入位置的前一个结点
		r = H;
		while(r->next && (r->next->data < q->data))
			r = r->next;

		//找到了,就插入该结点
		q->next = r->next;
		r->next = q;
	}
}

清空

清空是将链表置空,头结点保留,表仍然可以用。
销毁不仅要将有效结点全部删除,头结点也要删除,表不再可用。

void clear(linklist H)
{
	linklist p, q;
	p = H->next;
	while(p != NULL)
	{
		q = p;
		p = p->next;
		
		free(q);		
	}
}

销毁

void destroy(linklist H)
{
	clear(H)free(H);
	H = NULL;
}

测试

#include"linklist.h"

int main()
{
	//1.调用函数创建一个空链表
	linklist H = createLinkList();
	if(NULL == H)
	{
		printf("创建空链表失败\n");
		return -1;
	}
	//2.调用头插函数,向链表里新增数据
	printf("head insert:\n");
	headInsertLinkList(H, 111);
	headInsertLinkList(H, 555);
	headInsertLinkList(H, 333);
	headInsertLinkList(H, 777);
	headInsertLinkList(H, 666);
	//3.调用打印函数,查看链表
	showLinkList(H);
	
	printf("search:\n");
	linklist p = searchPos(H, 2);
	printf("pos %d = %d\n", 2, p->data);

	//4.任意位置插入数据
	insertLinklist(H, 2, 777);
	showLinkList(H);

	//5.求表长
	printf("length = %d\n", linkLength(H));

	//6.删除结点
	deleteLinkList(H, 0);
	printf("delete: ");
	showLinkList(H);
	
	//7.逆序输出
	reverseLinkList(H);
	printf("reverse: ");
	showLinkList(H);
	
	//8.排序
	printf("order: ");
	orderLinkList(H);
	showLinkList(H);
	
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值