PS:这个程序我在写的时候出了问题,我本来用的是菜单功能,结果我把初始化这个功能也放进去了,也就是说,程序第一次运行的时候,是没有强制初始化一个表的。这就有个问题,若我初始化并存值后,再调用其他功能,程序是没有反应,这是因为此时我原先创建的表没有被调用,那个表创建了就不见了,或许有别的方法调用出来,但是我没找到,而且这样也不符合我的程序初衷,时间复杂度和空间复杂度被硬生生的提高,得不偿失。
言归正传。上一个程序讲过了什么是堆、栈空间法的和他们的区别。这个代码用的就是栈空间法,通过调用指针来进行一系列的操作。
分块讲解
1)、链表的创建
#include <iostream>
typedef struct LinkNode{
int data;
struct LinkNode *next;
}linkNode;
//-----------------------------------------------------------------实现功能-----------------------------------------------------------------//
//初始化链表
linkNode *CreateLink(){
linkNode *head, *p, *s;
int x;//取值给表
int z=1,
n=0;//记录表长
head = NULL;
p=head;//替换、备用的头指针
printf("这是一个正值表,请不要输入负数!!\n");
printf("\n 说明: 请一个一个输入数据(空格隔开,输入-1 结束)!! \n");
while(z){
printf("输入:");
scanf("%d",&x);
if(x != -1 && x < 0){ //输入的值为负数
printf("建立失败!!\n");
exit(0);
} else if(x != -1){//创建成功
s = new linkNode;//节点
s->data = x;
s->next = NULL;
if(!head){
head = s;
} else {
p->next = s;
}
p=s;
n++;//计数表长
} else z = 0;
}
return head->next;
}
//菜单
void menu(){
printf("********1.插入 2.删除*********\n");
printf("********3.表长 4.输出*********\n");
}
int main(){
linkNode *head;
head=CreateLinkNode();
int choose;
while(1){
menu();//菜单
printf("请输入对应功能的序号!!\n");
scanf("%d",&choose);
switch (choose)
{
case 1:InsertLink(head);break;//插入
case 2:DeleteLink(head);break;//删除
case 3:LengthLink(head);break;//表长
case 4:showLinkNode(head);break;//输出展示
default:printf("输入非法!!!\n");
}
}
}
讲解:
首先要了解一下链表的结构。你初始化得到的是一个大的空间,然后什么都没有,这个时候你要去创建节点,和顺序表不一样。顺序表是用new创建一个连续的空间来放值,程序内部就给了你一个链接的顺序,你不可调看甚至更改。但是链表不一样,他给你的是空间的分配额,当你存进一个值,要用new或者malloc关键字去调用,告诉他,我现在需要一个空间额度,然后他会根据你的关键字那一条的语句来从你的额度中取一份空间给你。
但是注意了,这个空间会根据你的结构体被分成两块。一块用来放值,另一块用来存储指针地址。链表,顾名思义,像链子一样的。
我八输入模块和初始化模块合并在一起了,所以我的代码是没有输入模块的。如果你在链表创建好后,通过输入模块输入数值,那你的输入模块只能用一次,在后面的接上另外的新数据,可以直接用插入功能,在链表的后面直接插入。
但是注意了,这个空间会根据你的结构体被分成两块。一块用来放值,另一块用来存储指针地址。链表,顾名思义,像链子一样的。
2)、输出
//输出
void showLink(linkNode *s){
linkNode *head,*p;
head->next = s->next;
if(!head){
printf("请先创建链表!!");
}
printf("链表的值:\n");
while(head){
p=head;
printf("%d ",p->data);
head = head->next;
delete p;
}
printf("\n");
}
讲解:链表的输出,也就是将里面的值取出来,那样的话,表里的东西按理说是没了的,所以你需要释放空间,我用的是new分配空间,所以要用delete释放。
3、求表长
//表长
void LengthLink(linkNode *s){
if(!s){
printf("请先创建链表!!\n");
}
linkNode *p = s;
int n = 0;//计算表长
while(p->next){
p = p->next;
n++;
}
printf("表长为:%d \n",n);
}
讲解:遍历一遍链表即可。
4、插入
//实现插入
bool ListInsert(linkNode *head, int place, int num){
linkNode *p,*s;
p=head;
int z=2;
while(p != NULL && z<place){
z++;
p = p->next;
}
if(p!=NULL){
s=new linkNode;
s->data=num;
s->next=p->next;
p->next=s;
return true;
} else {
return false;
}
}
//插入
void InsertLink(linkNode *head)
{
if(!head){
printf("链表为空!!\n");
}
int place, num;
bool flag;
printf("请输入插入位置,从1开始!\n");
scanf("%d",&place);
printf("请输入插入的数据!\n");
scanf("%d",&num);
flag=ListInsert(head,place,num);
if(flag){
printf("插入成功!\n");
showLinkNode(head);
} else {
printf("插入失败!\n");
}
}
讲解:
插入功能,只要理解了逻辑就很容易的了。
插入功能的逻辑步骤:
先获取插入位置a1的前一个位置a0,然后给你要插入的新值建个结点b1,将你拿到的a0的指针域的值给b1的指针域,然后用a0获取b1的地址,也就是说,a0的指针域的值更新为b1的地址,插入完成。相较于顺序表的插入,链表的插入明显麻烦些,需要遍历到对应的位置才能插入,这就比较麻烦。
5、删除
//实现删除
bool LinkDelete(linkNode *head, int num){
linkNode *p, *s;
p=head;
while(p){
if(p->data == num){
break;
}
s = p;
p = p->next;
}
if(s!=NULL && p!=NULL){
s->next = p->next;
return true;
}else
return false;
}
//删除
void DeleteLink(linkNode *head)
{
if(!head){
printf("请先创建链表!!\n");
}
int place, num;
bool flag;
printf("请输入要删除的数据:\n");
scanf("%d",&num);
flag = LinkDelete(head, num);
if(flag){
printf("删除成功!!\n");
showLink(head);
} else
printf("错误,越界!! \n");
}
讲解:
删除功能的逻辑步骤:
分为对值删除和对位置删除。但是不管哪种,删除后都不需要像顺序表那样前移,直接将链表的地址进行更改,然后用delete释放删除节点的空间即可(如果你用的是malloc建立节点的话,需要用feel释放空间)。这点较顺序表来说简直不要太方便。
完整代码
#include <iostream>
using namespace std;
typedef struct LinkNode{
int data;
struct LinkNode *next;
}linkNode;
//初始化
linkNode *CreateLinkNode(){
linkNode *head,*p,*s;
int input=0;
int W=1;
int n=0;//计算表长
head = NULL;//空的头
p=NULL;//和s绑定后中转衔接
printf("请先创建你的链表!!\n");
printf("输入-1停止!!\n");
//循环输入
while(W){
printf("输入:");
scanf("%d",&input);
if(input == -1){//循环开关
W=0;
} else {
s = new linkNode;//创建新的节点
s->data = input;//放数据
s->next = NULL;//指向下个地址为空
if(!head){
head=s; //获得s的地址
}else{
p->next=s;
}
p=s;
n++;
}
}
return head;
}
//实现插入
bool ListInsert(linkNode *head, int place, int num){
linkNode *p,*s;
p=head;
int z=2;
while(p != NULL && z<place){
z++;
p = p->next;
}
if(p!=NULL){
s=new linkNode;
s->data=num;
s->next=p->next;
p->next=s;
return true;
} else {
return false;
}
}
//实现删除
bool LinkDelete(linkNode *head, int num){
linkNode *p, *s;
p=head;
while(p){
if(p->data == num){
break;
}
s = p;
p = p->next;
}
if(s!=NULL && p!=NULL){
s->next = p->next;
return true;
}else
return false;
}
//-----------------------------------------------------------------操作实现功能-----------------------------------------------------------------//
//展示
void showLinkNode(linkNode *head){
if(!head){
printf("空链!!\n");
exit(0);
}
while(head){
printf("%d ",head->data);
head=head->next;
}
printf("\n");
}
//创建
void create(linkNode *head){
head=CreateLinkNode();
showLinkNode(head);
}
//插入
void InsertLink(linkNode *head)
{
if(!head){
printf("链表为空!!\n");
}
int place, num;
bool flag;
printf("请输入插入位置,从1开始!\n");
scanf("%d",&place);
printf("请输入插入的数据!\n");
scanf("%d",&num);
flag=ListInsert(head,place,num);
if(flag){
printf("插入成功!\n");
showLinkNode(head);
} else {
printf("插入失败!\n");
}
}
//删除
void DeleteLink(linkNode *head)
{
if(!head){
printf("请先创建链表!!\n");
}else{
int place, num;
bool flag;
printf("请输入要删除的数据:\n");
scanf("%d",&num);
flag = LinkDelete(head, num);
if(flag){
printf("删除成功!!\n");
showLinkNode(head);
} else
printf("错误,越界!! \n");
}
}
//表长
void LengthLink(linkNode *head){
if(!head){
printf("空表!!\n");
}else{
int len=0;
while(head){
head=head->next;
len++;
}
printf("表长:%d\n",len);
return ;
}
}
//菜单
void menu(){
printf("********1.插入 2.删除*********\n");
printf("********3.表长 4.输出*********\n");
}
int main(){
linkNode *head;
head=CreateLinkNode();
int choose;
while(1){
menu();//菜单
printf("请输入对应功能的序号!!\n");
scanf("%d",&choose);
switch (choose)
{
case 1:InsertLink(head);break;//插入
case 2:DeleteLink(head);break;//删除
case 3:LengthLink(head);break;//表长
case 4:showLinkNode(head);break;//输出展示
default:printf("输入非法!!!\n");
}
}
}
链表的结构分为两种,一种是头节点,一种是无头结点。头节点指你链表的第一个结点是不放值的,他只用到了存放指针地址的指针域,指向你存放的第一个值的地址;无头结点,顾名思义,第一个节点就是你的第一个存放的第一个数值。然后又因为放值,或者插入的方式不一样,被分为两种。一种是头插法,一种是尾插法。顾名思义,头插法就是在节点的前面插入,尾插法就是在节点的尾部插入。