学习笔记:2.单链表的实现和代码

单链表

前言

自己学习数据结构的笔记,看的是王道的视频,写了源代码在最下面,有详细的注释,可以直接跑。(要保存成c++文件)希望对大家学习数据结构有所帮助。

一、单链表的定义

1.定义单链表

typedef struct LNode{
	int data;  				//数据域
	struct  LNode *next;	//指针域 
}LNode,*LinkList;
//LNode      强调节点
//*LinkList  强调链表 

2.初始化单链表

bool InitList(LinkList &L){
    L = NULL;
    return true;
}

二、单链表的插入

1.指定节点的后插操作 [平均时间复杂度O(1)]

//后插操作,在节点p之后插入元素e 
bool InsertNextNode(LNode *p,int e){
	
	//1.判断节点p是否存在 
	if(p == NULL) 
		return false;
	
	//2.分配内存空间 
	LNode *s = (LNode*)malloc(sizeof(LNode));
	
	//3.进行后插操作 
	s->data = e;		//将元素e的值赋值给节点s 
	s->next = p->next;	//令s的指针指向p的下一个节点 
	p->next = s;		//令p的指针指向s 
	return true;   
}

2.指定节点的前插操作 [平均时间复杂度O(1)]

//前插操作,在节点p前插入元素e
bool InsertPriorNode(LNode *p,int e){
	
	//1.判断节点p是否存在 
	if(p == NULL)
		return false;
	
	//2.分配内存空间
	LNode *s = (LNode*)malloc(sizeof(LNode));
		
	//3.进行前插操作 
	s->next = p->next;	//让s的指针指向p的下一个节点 
	p->next = s;		//让p的指针指向s 
	s->data = p->data;	//将p的数据赋值给s 
	p->data = e;  		//将e赋值给p
	return true; 
} 

3.按位序插入(不带头结点) [平均时间复杂度O(n)]

//按位序插入,在第i个位置插入元素e 
bool ListInsert(LinkList &L,int i,int e){
	
	//1.判断i的值是否合法 
	if(i < 1){
		return false;
	}
	
	//2.当i是第一个节点时,进行特殊处理	
	if(i == 1){
		//分配内存空间 
		LNode *s = (LNode*)malloc(sizeof(LNode));
		
		s->data = e;	//将元素e的值赋值给节点s
		s->next = L;	//令s的指针指向原来的第一个节点(头指针指向的节点)
		L = s;			//头指针指向新节点s 
		return true;
	}
	
	LNode *p;			//指针p指向当前扫描到的节点 
	int j = 1;			//当前p指向的是第几个节点
	p = L;				//没有头结点,L指向第一个节点
	
	//3.循环找到第i-1个节点 
	while(p && j < i-1){	 
		p = p->next;
		j++;
	}
	
	//4.i值不合法 
	if(p == NULL) 
		return false;
	
	//5.调用后插操作 
	return InsertNextNode(p,e);	
} 

4.按位序插入(带头结点) [平均时间复杂度O(n)]

//按位序插入,在第i个位置插入元素e 
bool ListInsert(LinkList &L,int i,int e){
	
	//1.判断i的值是否合法 
	if(i < 1){
		return false;
	}
    
	//2.循环找到第i-1个节点
	LNode *p;		//指针p指向当前扫描到的节点 
	int j = 0;		//当前p指向的是第几个节点
	p = L;			//L指向头结点,头结点是第0个节点(不存储数据)
    while(p && j < i-1){	 
		p = p->next;
		j++;
	}
	
	//3.i值不合法 
	if(p == NULL) 
		return false;
	
	//4.调用后插操作 
	return InsertNextNode(p,e);	
} 

三、单链表的删除

1.删除指定节点

//删除指定节点p 
//当p为最后一个节点时,不能使用此操作 
bool DeleteNode(LNode *p){
	
	//1.判断第i-1个节点后是否存在节点
	if(p->next == NULL)
		return false; 
	
    //2.进行删除操作
	LNode *q = p->next;	//创建指针q指向被删除节点 
	p->data = q->data; 	//用e返回被删除元素的值 
	p->next = q->next;	//p的指针指向被删除节点的下一个节点 
	free(q);	 
} 

2.按位序删除(不带头结点) [平均时间复杂度O(n)]

//按位序删除,删除位序为i的节点,并用e返回被删除的值 
bool ListDelete(LinkList &L,int i,int &e){

	//1.判断i的值是否合法 
	if(i < 1)
		return false; 
	
	//2.当删除第一个节点时,进行特殊操作,让头指针指向第二个元素 
	if(i == 1){
		L = L->next;
		return true;
	}
	
    //3.循环找到第i-1个节点 
	LNode *p;		//指针p指向当前扫描到的节点 
	int j = 1;		//当前p指向的是第几个节点,因为没有头结点,p指向第一个节点
	p = L;		
	
	while(p && j < i-1){	 
		p = p->next;
		j++;
	}
	
	//4.判断i的值是否合法 
	if(p == NULL)
		return false;
	
	//5.判断第i-1个节点后是否存在节点 
	if(p->next == NULL)
		return false;
		
	//6.进行删除操作 
	LNode *q = p->next;	//创建指针q指向被删除节点 
	e = q->data; 		//用e返回被删除元素的值 
	p->next = q->next;	//p的指针指向被删除节点的下一个节点 
	free(q);			//释放节点q的内存空间 
	return true;	
} 	

3.按位序删除(带头结点) [平均时间复杂度O(n)]

//按位序删除,删除位序为i的节点,并用e返回被删除的值 
bool ListDelete(LinkList &L,int i,int &e){

	//1.判断i的值是否合法 
	if(i < 1)
		return false; 
	
    //2.循环找到第i-1个节点
	LNode *p;		//指针p指向当前扫描到的节点 
	int j = 0;		//当前p指向的是第几个节点
	p = L;		
	 
	while(p && j < i-1){	 
		p = p->next;
		j++;
	}
	
	//3.判断i的值是否合法 
	if(p == NULL)
		return false;
	
	//4.判断第i-1个节点后是否存在节点 
	if(p->next == NULL)
		return false;
		
	//6.进行删除操作 
	LNode *q = p->next;	//创建指针q指向被删除节点 
	e = q->data; 		//用e返回被删除元素的值 
	p->next = q->next;	//p的指针指向被删除节点的下一个节点 
	free(q);			//释放节点q的内存空间 
	return true;	
}

四、单链表的查找

1.按位查找 [平均时间复杂度O(n)]

//按位查找,返回第i个元素
LNode* GetElem(LinkList L,int i){
	
	//1.判断i值是否合法 
	if(i < 0)		//当不带头结点时,判断条件为(i < 1)
		return NULL;
	
	//2.循环找到第i个节点
	LNode *p;		//指针p指向当前扫描到的节点 
	int j = 0;		//当前p指向的是第几个节点,当不带头结点时,j初始值为(j = 1)
	p = L;			//因为没有头结点,p指向第一个节点
	while(p != NULL && j < i){
		p = p->next;
		j++ ; 
	}
	return p; 
} 

2.按值查找 [平均时间复杂度O(n)]

//按值查找,找到数据域等于e的第一个节点
LNode* LocateElem(LinkList L,int e){
	
	//1.创建指针p令其指向第一个节点 
	LNode *p = L->next;		//当不带头结点时*p = L
	
	//2.循环查找数据域为e的节点 
	while(p != NULL && p->data != e){
		p = p->next;	 
	}
	return p; 
} 

3.统计单链表的长度 [平均时间复杂度O(n)]

//求单链表表长
int length(LinkList L){
	int len = 0;
	LNode *p = L;
	while(p->next != NULL){	//当不带头结点时,判断条件为 p != NULL
		len++;
		p = p->next; 
	}
	return len; 
} 

五、单链表的建立

1.尾插法建立单链表 [平均时间复杂度O(n)]

//尾插法创建单链表
LinkList TailInsert(LinkList &L){
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL; 
	LNode *s;
	LNode *r = L; 			//表尾指针 
	//bool is_head = true;	//判断插入节点的是否为第一个元素 
	int x;
	scanf("%d",&x);			//输入插入单链表的元素
	while(x != 9999){		//当输入9999时,结束单链表创建 
		s = (LNode*)malloc(sizeof(LNode));
		
		/*当不带头结点时,对第一个节点进行特殊操作 
		if(is_head != false){
			s->data = x ;
			L = s;			//令头指针指向该节点 
			r = s;			//令表尾指针指向该节点 
			is_head = false; 
		} */
		
		s->data = x;		 
		r->next = s;		//令s的指针指向L的下一个节点 
		r = s;				//令表尾指针指向s
		scanf("%d",&x);
	}
	r->next = NULL;
	return L; 
} 

2.头插法建立单链表 [平均时间复杂度O(n)]

//头插法创建单链表
LinkList HeadInsert(LinkList &L){
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	LNode *s;

	int x;
	scanf("%d",&x);			//输入插入单链表的元素
	while(x != 9999){		//当输入9999时,结束单链表创建 
		LNode *s = (LNode*)malloc(sizeof(LNode));

		s->data = x;		
		s->next = L->next;	//当不带头结点时,操作为 s->next = L; 
		L->next = s;		//当不带头结点时,操作为 L = s; 
		scanf("%d",&x);
	}
	return L; 
}

六、单链表的特点

1.不能随机存取。

2.存储密度低,节点处除了存放数据外还需要额外的内存空间存储指针。

3.优点是方便扩展容量,插入删除操作简单。

4.引入头结点的好处:对单链表第一个节点进行操作无需特殊处理。

七、源代码

带头结点的实现方式

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>


//单链表的定义 
typedef struct  LNode{
	int data;  //表示数据域
	struct  LNode *next;//指向下一个节点的指针
}LNode,*LinkList;
//LNode     强调节点
//*LinkList  强调链表 


//函数声明
bool InitList(LinkList &L);					//初始化单链表 
bool InsertNextNode(LNode *p,int e); 		//后插操作 
bool InsertPriorNode(LNode *p,int e); 		//前插操作 
bool ListInsert(LinkList &L,int i,int e); 	//按位序插入 
bool ListDelete(LinkList &L,int i,int &e); 	//按位序删除 
bool DeleteNode(LNode *p,int e); 			//删除指定节点 
void LinkListPrint(LinkList L); 			//遍历单链表 
int  LinkListlength(LinkList L); 			//求表长
LNode* GetElem(LinkList L,int i); 			//按位查找
LNode* LocateElem(LinkList L,int e); 		//按值查找 
LinkList HeadInsert(LinkList &L); 			//头插法建立单链表 
LinkList TailInsert(LinkList &L); 			//尾插法建立单链表 


//主函数
int main(void){
	LinkList L;
	TailInsert(L);
	LinkListPrint(L);
	ListInsert(L,1,100);
	LinkListPrint(L);
	int e = 0; 
	ListDelete(L,4,e);
	LinkListPrint(L);
	printf("单链表第2个元素为:%d\n",GetElem(L,2)->data);
	printf("按值查找得到的指针地址为:%d\n",LocateElem(L,5));		
	return 0; 
} 
 
 
//初始化单链表
bool InitList(LinkList &L){
	L = NULL;
	return true; 
} 


//后插操作,在节点p之后插入元素e 
bool InsertNextNode(LNode *p,int e){
	
	//1.判断节点p是否存在 
	if(p == NULL) 
		return false;
	
	//2.分配内存空间 
	LNode *s = (LNode*)malloc(sizeof(LNode));
	
	//3.进行后插操作 
	s->data = e;		//将元素e的值赋值给节点s 
	s->next = p->next;	//令s的指针指向p的下一个节点 
	p->next = s;		//令p的指针指向s
	
	printf("元素%d插入成功!\n",e);  
	return true;   
}


//前插操作,在p节点前插入元素e
bool InsertPriorNode(LNode *p,int e){
	
	//1.判断节点p是否存在 
	if(p == NULL)
		return false;
	
	//2.分配内存空间
	LNode *s = (LNode*)malloc(sizeof(LNode));
	
	//3.进行前插操作 
	s->next = p->next;	//让s的指针指向p的下一个节点 
	p->next = s;		//让p的指针指向s 
	s->data = p->data;	//将p的数据赋值给s 
	p->data = e;  		//将e赋值给p
	
	printf("元素%d插入成功\n",e); 
	return true; 
} 

 
//按位序插入,在第i个位置插入元素e 
bool ListInsert(LinkList &L,int i,int e){
	
	//1.判断i的值是否合法 
	if(i < 1){
		return false;
	}
	
	LNode *p;	//指针p指向当前扫描到的节点 
	int j = 0;	//当前p指向的是第几个节点
	p = L;		//L指向头结点,头结点是第0个节点(不存储数据) 
	
	//2.循环找到第i-1个节点 
	while(p && j < i-1){	 
		p = p->next;
		j++;
	}
	
	//3.调用后插操作 
	return InsertNextNode(p,e);
} 
 

//按位序删除,删除位序为i的节点,并用e返回被删除的值 
bool ListDelete(LinkList &L,int i,int &e){

	//1.判断i的值是否合法 
	if(i < 1)
		return false; 
	
	LNode *p;	//指针p指向当前扫描到的节点 
	int j = 0;	//当前p指向的是第几个节点
	p = L;		//因为没有头结点,p指向第一个节点
	
	//2.循环找到第i-1个节点 
	while(p && j < i-1){	 
		p = p->next;
		j++;
	}
	
	//3.判断i的值是否合法 
	if(p == NULL)
		return false;
	
	//4.判断第i-1个节点后是否存在节点 
	if(p->next == NULL)
		return false;
		
	//5.进行删除操作 
	LNode *q = p->next;	//创建指针q指向被删除节点 
	e = q->data; 		//用e返回被删除元素的值 
	p->next = q->next;	//p的指针指向被删除节点的下一个节点 
	free(q);			//释放节点q的内存空间
	
	printf("元素%d删除成功!\n",e); 
	return true;	
} 	


//删除指定节点p 
//当p为最后一个节点时,不能使用此操作 
bool DeleteNode(LNode *p,int e){
	
	//1.判断第i-1个节点后是否存在节点
	if(p->next == NULL)
		return false; 
	
	//2.进行删除操作  
	LNode *q = p->next;	//创建指针q指向被删除节点 
	p->data = q->data; 	//用e返回被删除元素的值 
	p->next = q->next;	//p的指针指向被删除节点的下一个节点 
	free(q);
	
	printf("元素%d删除成功!\n",p->data);	 
} 
  

//按位查找,返回第i个元素
LNode* GetElem(LinkList L,int i){
	
	//1.判断i值是否合法 
	if(i < 0)
		return NULL;
	
	//2.循环找到第i个节点
	LNode *p;		//指针p指向当前扫描到的节点 
	int j = 0;		//当前p指向的是第几个节点
	p = L;			//因为没有头结点,p指向第一个节点
	while(p != NULL && j < i){
		p = p->next;
		j++ ; 
	}
	
	//3.返回第i个节点的元素值 
	return p; 
} 


//按值查找,找到数据域等于e的第一个节点
LNode* LocateElem(LinkList L,int e){
	
	//1.创建指针p令其指向第一个节点 
	LNode *p = L->next;		//不带头结点时 *p = L
	
	//2.查找数据域为e的节点 
	while(p != NULL && p->data != e){
		p = p->next;	 
	}
	
	//3.找到后返回该节点的指针,否则返回NULL 
	return p; 
} 


//头插法创建单链表
LinkList HeadInsert(LinkList &L){
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	LNode *s;

	int x;
	printf("开始头插法单链表,请输入参数值:\n"); 
	scanf("%d",&x);			//输入插入单链表的元素
	while(x != 9999){		//当输入9999时,结束单链表创建 
		LNode *s = (LNode*)malloc(sizeof(LNode));

		s->data = x;		
		s->next = L->next;	//当不带头结点时,操作为 s->next = L; 
		L->next = s;		//当不带头结点时,操作为 L = s; 
		scanf("%d",&x);
	}
	return L; 
}


//尾插法创建单链表
LinkList TailInsert(LinkList &L){
	L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL; 
	LNode *s;
	LNode *r = L; 			//表尾指针 
	//bool is_head = true;判断插入的是否为第一个元素
	printf("开始尾插法单链表,请输入参数值(输入9999结束创建)\n");  
	int x;
	scanf("%d",&x);			//输入插入单链表的元素
	while(x != 9999){		//当输入9999时,结束单链表创建 
		s = (LNode*)malloc(sizeof(LNode));
		
		/*当不带头结点时,对第一个节点进行特殊操作 
		if(is_head != false){
			s->data = x ;
			L = s;			//令头指针指向该节点 
			r = s;			//令表尾指针指向该节点 
			is_head = false; 
		} */
		
		s->data = x;		 
		r->next = s;		//令s的指针指向L的下一个节点 
		r = s;				//令表尾指针指向s
		scanf("%d",&x);
	}
	r->next = NULL;
	return L; 
}  


//求单链表表长
int LinkListlength(LinkList L){
	int len = 0;
	LNode *p = L;
	while(p->next != NULL){	//当不带头结点时,判断条件为 p != NULL
		len++;
		p = p->next; 
	}
	printf("单链表表长为:%d\n",len); 
	return len; 
} 


//单链表的遍历
void LinkListPrint(LinkList L){
	LNode *s = L;
	printf("==================\n"); 
	printf("单链表的遍历结果为:"); 
	while(s->next != NULL){
		s = s->next;
		printf("%d ",s->data);
	}
	printf("\n");
	LinkListlength(L);
	printf("==================\n");  
} 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值