408-数据结构-单链表

通过链式存储方式的线性表,每一个结点包含了数据元素以及指向后继结点的指针
算法中考虑方面:

  1. 如何判断是否为空
  2. 如何判断表头还是表尾
  3. 表头、表中、表尾的插入与删除

单链表主要有两种(都必须掌握):

  1. 带头结点,在链头之前加入一个空结点,好处是在链头这个位置不需要进行特殊判断
  2. 不带头结点

单链表特点:

  1. 不要求大量连续区域
  2. 可以实现动态增加动态减少
  3. 不可以随机存取
  4. 并且需要额外开销存放指针

时间复杂度:

  1. 进行按位序插入,时间复杂度为O(n)
  2. 按位序删除,时间复杂度O(n)
  3. 进行给定结点的前插后插操作,时间复杂度为O(1)
  4. 进行给定结点的删除操作,时间复杂度为O(1)

带头节点

带头结点所有相关操作

//声明节点结构体
typedef struct LNode{
	ElemType data;
	LNode *next;
}LNode, *LinkList;
//typedef说明跳转至专栏中函数说明博客

//按位序插入
bool InsertList(LinkList &L, int i, Elem e){
	//寻找第i-1个结点的前驱结点
	if (i < 1)						//插入越界判断
		return false;
	int j = 0;
	LNode *p = L;
	while (p != NULL && j < i - 1){
		p = p->next;
		j ++;
	}
	if (p == NULL)					//说明输入i的值超越范围
		return false;
	//完成后插操作
	LNode *new_node = (LNode *) malloc (sizeof(LNode));		//产生新结点插入后方
	new_node->data = e;
	new_node->next = p->next;
	p->next = new_node;
	return true;
}

//完成指定结点后插操作
bool InsertList(LNode * node, ElemType e){
	if (node == NULL)				//判断输入是否有误
		return false;
	LNode * p = (LNode *)malloc(sizeof(LNode));		//完成后插操作
	if (p == NULL)
		return false;
	p->data = e;
	p->next = node->next;
	node->next = p;
	return true;
}

//完成指定结点的前插操作,偷天换日
bool InsertPrior(LNode *node, ElemType e){
	if (node == NULL)
		return false;
	//无法知道当前结点的前一个结点,但是知道当前结点的后一个
	//可以将当前结点变为要插入的结点,生成一个备份后一个结点
	LNode * p = (LNode *)malloc(sizeof(LNode));
	p->next = node;
	p->data = node->data;
	node->data = e;
	return true;
}

//删除后继结点
//存在小问题,如果删除的是最后一个结点,将无法删除,因为无法获得前驱结点
bool LNodeDelete(LNode * node, ElemType &e){
	if (node == NULL)
		return false;
	if (node->next == NULL)
		return false;
	LNode * p = node->next;
	e = p->data;
	node->next = p->next;
	free(p);
	return true;
}

//按位序删除
bool DeleteByPos(LinkList &L, int i, ElemType &e){
	if (i < 1)
		return false;
	int j = 0;
	LNode *p = L;
	while (p != NULL && j < i - 1){
		p = p->next;
		j ++;
	}
	if (p == NULL)			//如果p为null说明输入i超过了length+1
		return false;
	if (p->next == NULL)	//如果p不为null而p的next为null说明输入i恰巧为length+1
		return false;
	LNode *tem = p->next;
	p->next = tem->next;
	e = tem->data;
	free(tem);
	return true;
}

//按值删除
bool deleteByValue(LinkList &L, ElemType e, ElemType &e){
	LNode * p = L;
	while (p->next != NULL && p->next->data != e)
		p = p->next;
	if (p->next == NULL){
		return false;
	}
	LNode * tem = p->next;
	e = tem->data;
	p->next = tem->next;
	free(tem);
	return true;
}

//按位序查找
LNode * searchList(LinkList L, int i){
	if (i < 1 ){
		return NULL;
	}
	int j = 0;
	LNode * p = L;
	while (p != NULL && j < i){
		p = p->next;
		j ++;
	}
	return p;
}

//判断链表是否为空
bool isEmpty(LinkList L){
	return L->next == NULL;
}

//链表置空
void ClearLinkList(LinkList & L){
	LNode * p = L->next;
	L->next = NULL;
	while (p != NULL){
		LNode tem = p;
		p = p->next;
		free(tem);
	}
}

//求表长
int Length(LinkList L){
	LNode * p = L;
	int i = 0;
	while (p->next != NULL){
		i++;
		p = p->next;
	}
	return i;
}

链表的初始化插入有两种方式

  1. 头插法,即来一个数据元素,直接插入到头指针的下一个,链表存储数据与输入顺序相反
  2. 尾插法,来一个元素,插入到链尾的下一个,链表存储数据与输入顺序相同

//头插法插入
void InitLinkList(LinkList & L){
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
	LNode * p = L;
	LNode * q;
	ElemType value;
	while (scanf(%d”, &value) != EOF){
		q = (LNode *)malloc(sizeof(LNode));
		q->next = p->next;
		q->data = value;
		p->next = q;
	}
}

//尾插法插入数据
void InitLinkList(LinkList &L){
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
	LNode * p = L;
	LNode * q;
	ElemType value;
	while (scanf(%d”, &value) != EOF){
		q = (LNode *)malloc(sizeof(LNode));
		q->next = p->next;
		q->data = value;
		p->next = q;
		q = q->next;
	}
}

//尾插法有一个具体应用是反转链表,当然这是数据的反转,通过双指针实现
void LinkListReverse(LinkList &L){
	LNode * p = L;
	LNode * q = L->next;
	p->next = NULL;
	while (q != NULL){
		LNode * tem = q->next;
		q->next = p->next;
		p->next = q;
		q = tem;
	}
}

不带头节点

最大的特点是头结点需要特殊判断,因为一般来说,修改节点会指向他的直接前驱,那么非头结点就是修改前驱结点的next值,而头结点需要修改指针。

其余操作类似,将头指针单独拿出来进行判断。需要注意计数器也要进行修改。

//按位序插入,i为位序
bool insertLinkList (LinkList &L, int i, ElemType e){
	if (i < 1)
		return false;
	if (i == 1){
		LNode * p = (LNode *)malloc(sizeof(LNode));
		p->next = L;
		p->data = e;
		L = p;
		return true;
	}
	int j = 1;
	LNode * p = L;
	for (p != NULL && j < i){
		p = p->next;
		j ++;
	}
	if (p == NULL)
		return false;
	LNode * q = (LNode *)malloc(sizeof(LNode));
	q->next = p->next;
	q->data = e;
	p->next = q;
	return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值