单链表是什么:
单链表是一种基础的数据结构,它由一系列节点(Node)组成。每个节点包含两个部分:一个是存储数据元素的数据域(data field),另一个是指向列表中下一个节点的指针(next pointer)。链表的第一个节点被称为头节点(head),最后一个节点的指针指向NULL
,表示链表的结束。
单链表的特点包括:
- 动态大小:链表的大小在运行时可以改变,可以动态地添加或删除节点。
- 顺序访问:链表中的元素必须从头开始,按顺序访问,不能随机访问。
- 空间效率:与数组相比,链表在空间上更高效,因为它不需要预先分配固定大小的空间。
展示的代码部分有以下操作:
1、初始化单链表: InitList
函数用于初始化一个带头节点的空单链表。它通过动态内存分配创建头节点,并将头节点的next
指针设置为NULL
,表示链表为空。
2、后插操作: InsertNextNode
函数在给定节点p
之后插入一个新节点,该新节点的数据域为e
。
3、尾插法建立单链表: List_Taillnsert
函数通过尾插法建立单链表,即在链表的末尾插入新节点。
4、按位查找和插入: ListInsert
函数在链表的第i
个位置后插入一个新节点,其数据域为e
。
5、前插操作: InsertPriorNode
函数在给定节点p
之前插入一个新节点,该新节点的数据域为e
。
6、按位删除: ListDelete
函数删除链表中的第i
个位置的节点,并通过引用参数e
返回被删除节点的数据域。
7、按值查找: LocateElem
函数查找链表中数据域等于e
的节点,并返回指向该节点的指针。
8、求链表长度: Length
函数计算链表的长度。
9、打印链表: PrintList
函数打印链表中的所有元素。
10、主函数: main
函数是程序的入口点,负责调用上述函数以执行链表的相关操作。
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data; //定义单链表节点类型
struct LNode *next; //每个节点存放一个数据元素
} LNode,*LinkList; // 指针指向下个节点 强调这是一个单链表 使用LinkList 强调这是一个节点使用LNode *
/*判断单链表是否为空
bool Empty(LiinkList L){
if(L->next==null){
return true;
}else{
return false;
}
}
// 初始化一个空的单链表
bool InitList(LinkList &L){
L=Null; //空表,暂时还没有任何节点
return true;
} */
//初始化一个空表
bool InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode)); //空表,暂时还没有任何节点
if(L==NULL){
return false;
}
L->next=NULL;
return true;
}
//后插操作:在p节点之后插入元素e
bool InsertNextNode(LNode *p,double e){
if(p==NULL){
return false;
}
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL){ //内存分配失败
return false;
}
s->data=e; //用节点s保存数据元素e
s->next=p->next;
p->next=s; //将节点s连到p之后
return true;
}
//尾插法建立输入性单链表
LinkList List_Taillnsert(LinkList &L){ //正向建立单链表
int x; //设输入类型为整形
L=(LinkList)malloc(sizeof(LNode)); //建立头节点
LNode *s,*r=L; //r为表尾节点
printf("请输入值(9999结束):");
scanf("%d",&x); //输入节点到的值
while(x!=9999){ //输入9999表示结束
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s; //r指向新的表尾节点
scanf("%d",&x);
}
r->next=NULL; //为节点指针置空
return L;
}
//按位查找:在指定节点在第i个位置后插入元素e(带头结点)
bool ListInsert(LinkList &L,int i,double 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;
j++;
}
if(p==NULL){ //i值不合法
return false;
}
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s; //将节点s连到p之后
return true; //插入成功
}
//前插操作:在p节点之前插入元素e
bool InsertPriorNode(LNode *p,double e){
if(p==NULL)
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL) //内存分配失败
return false;
s->next=p->next; //新节点s连到p之后
p->next=s; //将p中元素复制到s中
s->data=p->data; //p中元素覆盖为e
p->data=e;
return true;
}
// 按位序删除(带头结点)
bool ListDelete(LinkList &L,int i,double &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;
j++;
}
if(p==NULL) //i值不合法
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; //删除成功
}
//按位查找:找到数据域==e的节点
LNode *LocateElem(LinkList &L,double e){
LNode *p=L->next;
//从第1个节点开始查找数据域为e的节点
while(p!=NULL&&p->data!=e){
p=p->next;
}
return p;
}
//求表的长度
int Length(LinkList L){
int len=0; //统计表长
LNode *p=L;
while(p->next!=NULL){
p=p->next;
len++;
}
return len;
}
// 打印链表的值
void PrintList(LinkList L) {
LNode *p = L->next; // 跳过头节点
while (p != NULL) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main() {
LinkList L; // 声明一个单链表
int position;
double value, deletedValue;
// 初始化单链表
if (!InitList(L)) {
printf("初始化链表失败!\n");
return -1;
}
// 使用尾插法建立单链表
L = List_Taillnsert(L);
// 输出单链表的值
printf("链表的值为:");
PrintList(L);
// 打印链表长度
printf("链表长度为:%d\n", Length(L));
// 按位序插入元素
printf("请输入要插入的位置和值(例如:3 5.0):");
scanf("%d %lf", &position, &value);
if (ListInsert(L, position, value)) {
printf("插入成功!\n");
} else {
printf("插入失败!\n");
}
// 输出单链表的值
printf("插入后的链表值为:");
PrintList(L);
// 打印链表长度
printf("插入后的链表长度为:%d\n", Length(L));
// 按位序删除元素
printf("请输入要删除的元素位置:");
scanf("%d", &position);
if (ListDelete(L, position, deletedValue)) {
printf("删除成功,删除的元素值为:%lf\n", deletedValue);
} else {
printf("删除失败!\n");
}
// 输出单链表的值
printf("删除后的链表值为:");
PrintList(L);
// 打印链表长度
printf("删除后的链表长度为:%d\n", Length(L));
// 释放链表内存(在实际使用中,应该遍历链表并释放每个节点的内存)
free(L);
return 0;
}