带头结点的单链表的基本操作实现

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

typedef struct node
{
	int data;
	struct node *next;
}LNode,*Linklist;

bool initlist(Linklist *l)	//初始化一个带头结点的单链表
{
	(*l) = (LNode*)malloc(sizeof(LNode));	//分配一个头结点
	if((*l)==NULL)			//内存不足分配失败
		return false;
	(*l)->next=NULL;		//头结点之后暂时还没有节点
	return true;
}

bool empty(Linklist l)	//判断带头结点的单链表是否为空
{
	if(l->next==NULL)
		return true;
	else
		return false;
}

bool listinsert(Linklist l, int i, int e)//按位序插入,在第i个位置插入元素e
{
	if(i<1)
		return false;
	LNode *p;		// 指针p指向当前扫描到的结点
	int j=0;		//当前p指向的是第几个结点
	p = l;			//l指向头结点,头结点是第0个结点(不存数据)

	while (p != NULL && j < i - 1) {	//循环找到第i-1个结点
		p=p->next;	//如果i不是合法的结点,那么p循环往后的时候就会指向NULL
		j++;		//然后退出循环,此时p的值为NULL
	}

	if(p==NULL)		//i值不合法				
		return false;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	s->data=e;

	s->next = p->next;
	p->next = s;

	return true;
}

bool insertnextnode(LNode* p, int e)//指定结点的后插操作
{
	if(p==NULL)
		return false;
	LNode *s=(LNode*)malloc(sizeof(LNode));
	if(s==NULL)			//内存分配失败
		return false;
	s->data=e;

	s->next =p->next;
	p->next = s;		//将结点s连接到p之后

	return true;
}

bool insertpriornode(LNode* p, int e)	//前插操作:在p结点之前插入元素e     (实际上是在p之后做了后插结点操作再交换两个结点的值)
{										//(时间复杂度O(1))
	if(p==NULL)
		return false;
	LNode *s = (LNode*)malloc(sizeof(LNode));
	if(s==NULL)
		return false;

	s->next=p->next;
	p->next =s;			//将新结点s连接到p之后

	s->data=p->data;	//将p元素的值复制到s中
	p->data=e;			//p中元素覆盖为e		

	return true;
}

bool listdelete(Linklist l, int i, int* e)//按位序删除,删除表中第i个元素,其实就是找到第i-1个结点,将其指针指向第i+1个结点,并释放第i个结点
{
	if(i<1)
		return false;
	LNode*p;		//指针p指向当前扫描到的结点
	int j=0;		//当前p指向的是第几个结点
	p=l;			//先让p指向头结点
	while (p != NULL && j < i - 1) {	//循环找到第i-1个结点
		p=p->next;
		j++;
	}
	if(p==NULL)
		return false;
	if(p->next==NULL)		//第i-1个结点之后已经没有其他结点
		return false;

	LNode* q  =p->next;		//令q指向被删除结点
	*e = q->data;			//用e返回元素的值

	p->next = q->next;		//将*q结点从链中"断开"

	free(q);				//释放结点的存储空间

	return true;			//删除成功
}

bool deletenode(LNode* p)	//指定结点的删除操作:需要修改其前驱结点的next指针,方法1:传入头指针,循环找到p的前驱结点。方法2:偷天换日(类似于结点前插操作)
{
	if(p==NULL)
		return false;
	if(p->next==NULL)		//如果*p为最后一个结点我们只能通过从表头开始依次寻找p的前驱,时间复杂度O(n)
		return false;
	LNode *q= p->next;	//让q指向p的后继结点
	p->data=q->data;		//和后继结点交换数据域,p不存在后继结点我们访问后继节点的数据是错误的
	p->next=q->next;
	free(q);
	return true;
}

LNode* getelem(Linklist l, int i)	//带头结点的按位查找
{
	if(i<0)
		return NULL;
	LNode *p;		//指针p指向当前扫描到的结点
	int j=0;		//当前p指向的是第几个结点
	p=l;			//先让p指向头结点,头结点是第0个结点(不存数据)
	while (p != NULL && j < i) {	//循环找到第i个结点
		p=p->next;
		j++;
	}
	return p;		
}

//按值查找,找到数据域==e的结点
LNode* locateelem(Linklist l, int e)	//带头结点的按值查找
{	
	LNode *p = l->next;				//p指向第1个结点
	while (p != NULL && p->data != e) {
		p=p->next;
	}
	return p;		//找到后返回该结点指针,否则返回NULL
}

int length(Linklist l)	//求单链表的长度
{
	int len =0; 
	LNode *p = l;
	while (p->next != NULL) {
		p=p->next;
		len++;
	}
	return len;
}

Linklist creat_withhead_by_tailinsert(Linklist* l)	//尾插法建立带头结点的单链表
{
	int x;
	scanf("%d",&x);
	(*l)=(LNode*)malloc(sizeof(LNode));		//建立头结点,不存数据
	LNode *s,*r =(*l);				//尾指针指向新结点,s和r一开始都指向头结点

	while (x != 9999) {
		s=(LNode*)malloc(sizeof(LNode));
		s->data=x;
		r->next=s;
		r=s;				//尾指针指向新结点
		scanf("%d",&x);
	}
	r->next=NULL;		//循环建立链表结束不要忘了使最后一个结点的指针指向NULL
	return (*l);
}

Linklist creat_withhead_by_headinsert(Linklist* l)		//头插法建立带头结点的单链表
{
	int x;
	scanf("%d",&x);
	(*l)=(LNode*)malloc(sizeof(LNode));		//建立头结点,不存数据
	(*l)->next=NULL;						//初始化为空链表  如果不把指针指向NULL可能指向一片神秘不可知的地方

	LNode *s;
	while (x != 9999) {
		s=(LNode*)malloc(sizeof(LNode));
		s->data=x;
		s->next=(*l)->next;
		(*l)->next=s;		//将新结点插入表中,*l为头指针
		scanf("%d",&x);
	}
	return (*l);
}

bool print(Linklist l)
{
	LNode *p;
	p=l;
	if(p->next==NULL)
		return false;
	while (p->next != NULL) {
		printf("%d\n",p->next->data);
		p=p->next;
	}
	return true;
}

int main()
{
	Linklist list=NULL;		//定义一个指向单链表的指针
	//creat_withhead_by_tailinsert(&list);

	creat_withhead_by_tailinsert(&list);

	printf("%d##\n",length(list));
	print(list);

	listinsert(list,1,99);
	print(list);
	printf("%d##\n",length(list));
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值