目录
1.头文件
#include <string.h>
#include <cstdio>
#include <cstdlib>
2.定义
//单链表的定义
typedef struct LNode{ //定义单链表结点类型
int data; //每个节点存放一个整型元素
struct LNode *next; //指针指向下一个节点
}LNode,*LinkList;
//重命名等价于
// typedef struct LNode LNode; # typedf <原名字> <别名>
// typedef struct LNode *LinkList;
// LNode *L==LinkList L ->声明一个指向单链表第一个结点的指针(头指针)
// 强调这是一个单链表 LinkList 强调这是一个结点 LNode *
3.初始化
(1)不带头结点
// 不带头节点的单链表初始化
bool InitList_nohead(LinkList &L){
L=NULL;
return true;
}
(2)带头结点
//带头结点初始化
bool InitList(LinkList &L){
L = (LNode *) malloc(sizeof(LNode));//申请一片空间,让头指针指向它
if(L==NULL){ //内存不足,则分配失败
return false;}
L->next=NULL;//头指针指向的结点的指针域指向NULL,因为此时还没有下一个结点
return true;
}
4.判空
(1)不带头结点
//判断不带头节点空链表是否为空
bool Empty_nohead(LinkList L) {
if (L == NULL) {
printf("该表为空!\n");
return true;
} else {
printf("该表非空!\n");
return false;}
}
(2)带头结点
//判断带头节点的单链表是否为空
bool Empty(LinkList L){
if(L->next == NULL){
printf("该单链表为空!\n");
return true;
} else{
printf("该单链表非空!\n");
return false;}
}
5.按位插入
(1)不带头结点
//按位插入 (不带头结点)
bool ListInsert_nohead(LinkList &L,int i,int e){
LNode *p;//定义一个指针p指向当前扫到的结点
p=L;
if(i<1){
printf("i<1\n");
return false;
} else if(i==1){
LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
if(s==NULL){//内存分配失败
return false;}
s->data=e;//把要插入的元素值放到结点中
s->next=L;//把新节点的next指针指向头指针
L=s;//把头指针指向新节点
printf("插入成功!\n");
return true;
}else {
int j=1;//定义一个变量j反应当前指向第几个结点
//p=L;
while (p!=NULL&&j<i-1){//循环找到第i-1个结点,即要插入的位置的前一位
//p不指向NULL(即空值)或0结点时
p=p->next;//p移向p的next结点
j++;}
LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
s->data=e;//把要插入的元素值放到结点中
s->next=p->next;//把新节点的next指针指向头指针
p->next=s;//把头指针指向新节点
printf("插入成功了!\n");
return true;}
}
(2)带头结点
//按位插入 带头节点
//时间复杂度:最好O(1),最差O(n),平均O(n)
//119-125行可以用LNode *p = GetElem(L,i-1);封装
bool ListInsert(LinkList &L,int i,int e){
if(i<1){//判断位置i是否合理
return false;}
LNode *p;//定义一个指针p指向当前扫到的结点
int j=0;//定义一个变量j反应当前指向第几个结点
p=L;//初始值 p指向头节点L,即第0个结点
while (p!=NULL&&j<i-1){//循环找到第i-1个结点,即要插入的位置的前一位
//p不指向NULL(即空值)或0结点时
p=p->next;//p移向p的next结点
j++;}
if(p==NULL)//i值太大了
return false;
LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
if(s==NULL){//内存分配失败
return false;}
s->data=e;//把要插入的元素值放到结点中
s->next=p->next;//把新节点的next指针指向i-1位的next指针
p->next=s;//把i-1位的next指针指向新节点
return true;
// 以上等价于:
//return InsertNextNode(p,e);
}
6.后插法
//给定一个结点,实现后插操作:在p节点后插入指针e
bool InsertNextNode(LNode *p,int e){
if(p==NULL){
return false;
}
LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
if(s==NULL){//内存分配失败
return false;
}
s->data=e;//把要插入的元素值放到结点中
s->next=p->next;//把新节点的next指针指向i-1位的next指针
p->next=s;//把i-1位的next指针指向新节点
return true;
}
7.前插法
(1)不带头结点
//前插法之无头指针
//时间复杂度O(1)
bool InsertPriorNode_nohead(LNode *p,int e){
//本质是后插,但移动data
if(p==NULL){
return false;}
LNode *s=(LNode *) malloc(sizeof(LNode));//申请一个新结点
if(s==NULL){//内存分配失败
return false;}
s->data=p->data;
s->next=p->next;
p->data=e;
p->next=s;
return true;
}
(2)带头结点
//给定一个结点,实现前插操作:在p节点前插入指针e
//时间复杂度:O(n)
bool InsertPriorNode(LinkList L,LNode *p,int e){//单链表不可逆所以要传入头指针
if(p==NULL){
return false;
}
LNode *q;//定义一个指针q指向当前扫到的结点
int j=0;//定义一个变量j反应当前指向第几个结点
q=L;//初始值 p指向头节点L,即第0个结点
while (q!=NULL&&q!=p){//循环找到p前一个结点,即要插入的位置的前一位
//p不指向NULL(即空值)或p结点时
p=p->next;//p移向p的next结点
j++;}
printf("成功");
return InsertNextNode(q,e);
//因为q是p的前一个结点,所以对q后插==对p前插
}
8.删除
(1)删除指定结点
//删除指定结点p 且这个p不能是最后一个结点(此时必须找到p的前驱结点)
//时间复杂度:O(1),如果p是最后一个结点则为O(n)
bool DeleteNode(LNode *p){
//本质是将p+1的data复制到p,然后删p+1
if(p==NULL||p->next==NULL){
return false;
}
LNode *q=p->next;//令q指向p+1
p->data=q->data;//将p+1的值覆盖原p值
p->next=q->next;//将p的next的指针指向p+2
free(q);//释放p+1
return true;
}
(2)按位删除
//按位删除-带头结点
bool ListDelete(LinkList &L,int i) {
//174-175 179-184行可以用LNode *p = GetElem(L,i-1);封装
LNode *p;//定义一个指针p指向当前扫到的结点
p = L;//初始值 p指向头节点L,即第0个结点
if (i < 1||p==NULL) {//判断位置i是否合理
return false;
}
int j = 0;//定义一个变量j反应当前指向第几个结点
while (p != NULL && j < i - 1) {//循环找到第i-1个结点,即要插入的位置的前一位
//p不指向NULL(即空值)或0结点时
p = p->next;//p移向p的next结点
j++;
}
if(p->next==NULL){//第i-1结点后已无新结点
return false;}
LNode *q=p->next;//令q结点指向第i个结点
p->next=q->next;//令p的next指针指向q的next,即i+1个结点
int e=q->data;//用变量e接受被删除的值
free(q);//释放q结点的空间
printf("被删除的的元素是:%d\n",e);
return true;
}
9.查找
(1)按位查找
//按位查找 带头结点 返回第i个元素值
//时间复杂度:O(n)
LNode *GetElem(LinkList L,int i){
LNode *p;//指向当前扫描到的结点
p=L;//p默认值 指向0结点(头结点)
if(i<0||p->next==NULL){
//i不合法(应该在0-实际长度中间)或链表为空 即头结点(不存放数据)next指向空
printf("该位置没有元素!\n");
return NULL;
} else{
int j=0;//表述当前p指向第几个结点
while (p!=NULL&&j<1){//当表内有元素时,循环找到第i个结点
p=p->next;
j++;
printf("第%d位元素为:%d\n",i,p->data);
return p;
}
}
}
(2)按值查找
//按值查找 找到数据域等于e的结点
LNode *LocateElem(LinkList L,int e){
LNode *p=L->next;//将头指针的下一个结点赋值给p,即第一个结点
while (p->data!=e&&p->next!=NULL){
p=p->next;//p后移
}
return p;
}
10.求表长
//求表长
int Length(LinkList L){
LNode *p=L;
int length=0;
while(p->next!=NULL){
p=p->next;
length++;
}
printf("该顺序表长度为:%d",length);
return length;
}
11.建立单链表
(1)头插法
//用头插法建立单链表
LinkList List_HeadInert(LinkList &L,int x){
LNode *s;
//int x;//定义一个整型来接收需要插入的函数
//L=(LinkList) malloc(sizeof(LNode));//建立头结点
//L->next=NULL;//初始化空表
//printf("请输入一个数(输入9999退出):");
//scanf("%d",&x);
//while (x!=9999){
s=(LNode *) malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
//scanf("%d",&x);
//}
return L;
}
(2)尾插法
//用尾插法建立单链表
LinkList List_TailInsert(LinkList &L){//正向声明一个单链表
int x;//定义一个整型来接收需要插入的函数
L=(LinkList) malloc(sizeof(LNode));//建立头结点
LNode *s,*r=L;//r指向尾结点,一开始表为空,所以指向头指针
printf("请输入一个数(输入9999退出):");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof (LNode));//申请一个新结点并由s指向
s->data=x;//在s的data中存入数据
r->next=s;//原尾指针于新申请的结点相连
r=s;//r指向新的尾指针
scanf("%d",&x);
}
r->next=NULL;//尾指针的next为空
return L;
}
12.顺序表的逆置
//顺序表的逆置
LinkList List_nizhi(LinkList &L){
LNode *s=L->next;//指向原顺序表的第一个结点
LinkList p;
InitList(p);//初始化
int x=0;//来接收原顺序表中的值
while(s!=NULL){
x=s->data;//将该值赋给x
List_HeadInert(p,x);
s=s->next;//s后移
}
L=p;
//return p;
}
13.单链表的打印
//单链表的打印
int List_Printf(LinkList L){
LNode *p=L->next;
int x=0;
while (p!=NULL){
x=p->data;
p=p->next;
printf("%d ",x);
}
printf("\n");
}
14.主函数
int main() {
system("chcp 65001");//输出为中文
LinkList L_nohead;//声明一个指向单链表的指针
Empty_nohead(L_nohead);//判空
InitList_nohead(L_nohead);//初始化
Empty_nohead(L_nohead);//判空
ListInsert_nohead(L_nohead,1,12);//插入
ListInsert_nohead(L_nohead,2,13);//插入
ListInsert_nohead(L_nohead,3,12);//插入
ListInsert_nohead(L_nohead,4,45);//插入
//printf("--------测试--------\n");
//Del_x(L_nohead,12);
printf("----------------带头结点-----------------\n");
LinkList L;//声明
Empty(L);//判空
InitList(L);//初始化
Empty(L);//判空
ListInsert(L,1,12);//插入
GetElem(L,1);//按位查找
ListDelete(L,1);//删除
Empty(L);//判空
GetElem(L,1);//按位查找
printf("--------头插法测试--------\n");
List_HeadInert(L,3);//头插法
List_HeadInert(L,6);//头插法
List_Printf(L);//打印
//printf("--------尾插法测试--------\n");
//List_TailInsert(L);//尾插法
//List_Printf(L);//打印
printf("--------逆置法测试--------\n");
//L=List_nizhi(L);
List_nizhi(L);
List_Printf(L);//打印
return 0;
}
运行结果:
Active code page: 65001
该表非空!
该表为空!
插入成功!
插入成功了!
插入成功了!
插入成功了!
----------------带头结点-----------------
该单链表为空!
该单链表为空!
第1位元素为:12
被删除的的元素是:12
该单链表为空!
该位置没有元素!
--------头插法测试--------
6 3
--------逆置法测试--------
3 6进程已结束,退出代码为 0