C语言线性表实现:单链表

C语言指针详解

概念理解:

线性表:逻辑结构
单链表:使用链式存储方式实现的线性表

数据类型重命名:typedef <数据类型> <别名>
LNode:struct LNode的重命名写法
LinkList:指向LNode类型结构体的指针的重命名写法。(LinkList=struct LNode* =LNode*)

LNode*和LinkList区别:没有区别!不要被误导,都是普通的指针而已:
1.指针类型:struct LNode *
2.指针指向元素的类型:struct LNode,即结点类型。
3.指针返回值:返回所指向结点的内存地址。
4.唯一的小区别:LNode *更强调该指针指向的是一个结点,LinkList更强调该指针是一个头指针。

点(.)是用于结构体变量访问成员,箭头(->)是用于指向结构体的指针访问成员。
链表这一块一般都是先获取指向某个结点的指针,再通过指针访问该结点的data和next成员变量。

记住链表最后一个结点的后继指针(next)要置空,删除结点后记得使用free()函数释放该结点内存空间。(这条的作用主要是提高代码规范的)

单链表结构体:

typedef struct LNode{
	int data;
	struct LNode* next;
} LNode,*LinkList;

初始化单链表,创建头结点:

bool InitList(LinkList &L){//初始化单链表,传入头指针
	L = (LNode*)malloc(sizeof(LNode));//初始化头结点,头指针指向该结点
	L->next = NULL;//头结点后继结点为空
	return true;	
}

头插:

LinkList List_HeadInsert(LinkList &L){//头插法
	LNode* s;//指针s指向要插入到链表中的结点
	int x;//x接收控制台输入的数据
	scanf("%d",&x);
	while(x != 9999){//如果控制台不输入9999就会一直循环
		s = (LNode*)malloc(sizeof(LNode));//动态开辟一块LNode型的内存空间,将结点s指向该内存空间
		s->data = x;//设置结点的数据域
		s->next = L->next;
		L->next = s;
		scanf("%d",&x);//再次控制台输入
	}
	return L;//返回插入后的链表
}

尾插:

LinkList List_TailInsert(LinkList &L){//尾插法
	LNode* s;//指针s指向要插入到链表中的结点
	LNode* p = L;//p始终指向表尾结点
	int x;//x接收控制台输入的数据
	scanf("%d",&x);
	while(x != 9999){
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		p->next = s;
		p = s;
		scanf("%d",&x);//再次控制台输入
	}
	p->next = NULL;//养成习惯,链表最后一个结点后继指针置空
	return L;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
}

按位查找:

LNode* GetElem(LinkList L,int i){//按位查找
	LNode* p = L->next;//指针p指向第一个非空结点
	int j = 1;//当前指针p位于第几个结点
	while(p != NULL && j < i){//循环到指针p指向第i个结点
		p = p->next;
		j++;
	}
	if(p != NULL){
		return p;//指针p当前指向的结点即为要查找的结点
	}
	return NULL;
}

按值查找:

LNode* LocateElem(LinkList L,int e){//按值查找
	LNode* p = L->next;//指针p指向第一个非空结点
	while(p != NULL){	
		if(p->data == e){
			return p;//返回指向第一个符合条件的结点的指针
		}else{
			p = p->next;
		}
	}
	return NULL;
}

插入结点:

bool ListInsert(LinkList &L,int i,int e){//插入结点
	LNode* s = (LNode*)malloc(sizeof(LNode));//开辟一块新结点,让指针s指向该结点
	s->data = e;
	//复习malloc:开辟一块内存空间,返回一个指向该内存空间的指针
	LNode* p = GetElem(L,i-1);//获取指向链表中i-1位置结点的指针
	s->next = p->next;
	p->next = s;
	return true;
}

删除结点:

bool ListDelete(LinkList &L,int i){//删除结点
	LNode* p = GetElem(L,i-1);//获取指向链表中i-1位置结点的指针
	LNode* q = p->next;//q指针指向链表中第i个结点
	p->next = p->next->next;
	free(q);//注意要释放存储空间
	return true;
}

获取单链表长度:

int getLength(LinkList &L){//获取链表长度(不含头结点)
	LNode* p = L->next;//指针p指向头结点
	int sum = 0;
	while(p!=NULL){
		sum++;//当前指针指向的结点不为空就+1
		p = p->next;//然后指针后移一位,指向下一结点
	}
	return sum;
}

打印单链表信息:

void printList(LinkList &L){//打印单链表
	LNode* p = L->next;//指针p指向头结点
	while(p!=NULL){
		printf("%d->",p->data);
		p = p->next;//然后指针后移一位,指向下一结点
	}
	printf("\n");
}

测试:

#include <stdio.h>
#include <stdlib.h>//使用malloc和free关键字需要引入这个库

typedef struct LNode{
	int data;
	struct LNode* next;
} LNode,*LinkList;

bool InitList(LinkList &L){//初始化单链表,传入头指针
	L = (LNode*)malloc(sizeof(LNode));//初始化头结点,头指针指向该结点
	L->next = NULL;//头结点后继结点为空
	return true;	
}

LinkList List_HeadInsert(LinkList &L){//头插法
	LNode* s;//指针s指向要插入到链表中的结点
	int x;//x接收控制台输入的数据
	scanf("%d",&x);
	while(x != 9999){//如果控制台不输入9999就会一直循环
		s = (LNode*)malloc(sizeof(LNode));//动态开辟一块LNode型的内存空间,将结点s指向该内存空间
		s->data = x;//设置结点的数据域
		s->next = L->next;
		L->next = s;
		scanf("%d",&x);//再次控制台输入
	}
	return L;//返回插入后的链表
}

LinkList List_TailInsert(LinkList &L){//尾插法
	LNode* s;//指针s指向要插入到链表中的结点
	LNode* p = L;//p始终指向表尾结点
	int x;//x接收控制台输入的数据
	scanf("%d",&x);
	while(x != 9999){
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		p->next = s;
		p = s;
		scanf("%d",&x);//再次控制台输入
	}
	p->next = NULL;//养成习惯,链表最后一个结点后继指针置空
	return L;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
}

LNode* GetElem(LinkList L,int i){//按位查找
	LNode* p = L->next;//指针p指向第一个非空结点
	int j = 1;//当前指针p位于第几个结点
	while(p != NULL && j < i){//循环到指针p指向第i个结点
		p = p->next;
		j++;
	}
	if(p != NULL){
		return p;//指针p当前指向的结点即为要查找的结点
	}
	return NULL;
}

LNode* LocateElem(LinkList L,int e){//按值查找
	LNode* p = L->next;//指针p指向第一个非空结点
	while(p != NULL){	
		if(p->data == e){
			return p;//返回指向第一个符合条件的结点的指针
		}else{
			p = p->next;
		}
	}
	return NULL;
}

bool ListInsert(LinkList &L,int i,int e){//插入结点
	LNode* s = (LNode*)malloc(sizeof(LNode));//开辟一块新结点,让指针s指向该结点
	s->data = e;
	//复习malloc:开辟一块内存空间,返回一个指向该内存空间的指针
	LNode* p = GetElem(L,i-1);//获取指向链表中i-1位置结点的指针
	s->next = p->next;
	p->next = s;
	return true;
}

bool ListDelete(LinkList &L,int i){//删除结点
	LNode* p = GetElem(L,i-1);//获取指向链表中i-1位置结点的指针
	LNode* q = p->next;//q指针指向链表中第i个结点
	p->next = p->next->next;
	free(q);//注意要释放存储空间
	return true;
}

int getLength(LinkList &L){//获取链表长度(不含头结点)
	LNode* p = L->next;//指针p指向头结点
	int sum = 0;
	while(p!=NULL){
		sum++;//当前指针指向的结点不为空就+1
		p = p->next;//然后指针后移一位,指向下一结点
	}
	return sum;
}

void printList(LinkList &L){//打印单链表
	LNode* p = L->next;//指针p指向头结点
	while(p!=NULL){
		printf("%d->",p->data);
		p = p->next;//然后指针后移一位,指向下一结点
	}
	printf("\n");
}

int main(){
	LinkList L1;//创建一个头指针
	InitList(L1);//初始化单链表(创建头结点)
	List_TailInsert(L1);//尾插法
	printList(L1);
	printf("单链表6号位置的数据域:%d\n",GetElem(L1,6)->data);
	printf("数据域为2的结点在单链表中的位置:%d\n",LocateElem(L1,2)->data);	
	ListInsert(L1,3,5);//插入5作为第三个结点
	printList(L1);
	ListDelete(L1,4);//删除第四个结点
	printList(L1);
	printf("当前链表长度:%d\n",getLength(L1));
	return 0;
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姓蔡小朋友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值