概念理解:
线性表:逻辑结构
单链表:使用链式存储方式实现的线性表
数据类型重命名: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;
}