单链表的定义以及概念与结构:
单链表是一种常见的数据结构,用于存储一系列元素。它由一系列称为节点(node)的对象组成,每个节点包含两个部分:数据部分和指针部分。数据部分存储该节点表示的元素的值。指针部分则指向下一个节点,在单链表中,每个节点只有一个指针指向下一个节点,最后一个节点的指针指向空(NULL)。通过这种方式,节点之间形成了一个链式的关系,因此称为链表。在单链表中,只能通过从头节点(第一个节点)开始顺序遍历整个链表才能访问到各个节点。
结构:
typedef struct node //typedef是函数的重命名
{
int data; //存储结点,包括 data域和 next域
struct node *next;
}LNode ,*LinkList;
单链表的特点:
链式存储结构;动态性;顺序访问;插入和删除效率高;内存消耗。
单链表的初始化:
当我们开始使用单链表时,首先要对单链表进行初始化,创建一个带头结点的单链表。带头节点的单链表指的是在链表的头部添加一个空节点,该节点不存储实际的数据,仅用作头节点的前一个节点,也称为哨兵节点或者虚拟节点
代码实现:
void InitList(LinkList &L)//建立带头结点的单链表
{
L=new LNode;
L->next=NULL;
}
单链表的建立:
头插法:
单链表的头插法(Head Insertion)是指在链表的头部插入新的节点的一种操作方法。具体步骤如下:
- 创建一个新节点,将要插入的数据存储在该节点中。
- 将新节点的指针指向原来链表的头节点(即新节点的 next 指针指向原来的头节点)。
- 将链表的头节点指向新节点(即头指针指向新节点)。
代码实现:
//头插法建表 输入结果与输出结果相反
void InputList_H(LinkList &L,int n)
{
LNode *p; //用于专门开辟新的节点,用来插入节点
cout<<"请输入这"<<n<<"个数:";
for(int i=1;i<=n;i++)
{
p=new LNode; //申请链表LNode的空间
cin>>p->data;
p->next = L->next; //将新结点插入头节点后面
L->next = p;
}
}
尾插法:
单链表的尾插法(Tail Insertion)是指在链表的尾部插入新的节点的一种操作方法。具体步骤如下:
- 创建一个新节点,将要插入的数据存储在该节点中。
- 若链表为空,则将链表的头节点指向新节点(即头指针指向新节点),并将新节点作为尾节点。
- 若链表不为空,则找到当前链表的尾节点(即遍历到 next 指针为 null 的节点)。
- 将尾节点的 next 指针指向新节点,将新节点作为新的尾节点。
代码实现:
//尾插法建表 输入顺序与输出顺序一致
void InputList_R(LinkList &L,int n)
{
LNode *p; //用于专门开辟新的结点
LNode *r; //用于指向表尾结点
r=L;
while(r->next!=NULL) //先遍历链表在插入
{
r=r->next;
}
cout<<"请输入这"<<n<<"个数:";
for(int i=1;i<=n;i++)
{
p=new LNode; //申请链表LNode的空间
cin>>p->data;
//将新结点插入表尾
r->next=p;
r=p; //将新插入的结点的指针p变为指针r,把插入的结点变为新的尾结点
}
r->next=NULL;
}
单链表的遍历:
代码思路:我们要遍历一个单链表。首先是要创建一个用于遍历节点的指针p,它最开始是指向表头下一个节点,然后输出该节点data域的数值,随后在 p=p->next,让p又指向当前节点的下一个节点,直到没有
代码实现:
//链表遍历
void ShowList(LinkList &L)
{
LNode *p; //用于专门开辟新的结点
p=L->next; //先将遍历指针指向头部,用头部往下进行遍历
cout<<"它的值如下:"<<endl;
while(p!=NULL)
{
cout<<p->data<<"\t";
p=p->next;
}
}
单链表的长度:
代码思路:其实与单链表的遍历的思路是一致的,不过要多一个整数
代码实现:
//计算表长 通过遍历的方法进行计算表的长度
void GetLength(LinkList &L)
{
LNode *p; //用于专门开辟新的结点
p=L->next; //先将遍历指针指向头部,用头部往下进行遍历
int i=0; //头结点不做计算
while(p!=NULL)
{
p=p->next;
i=i+1;
}
cout<<"该表长是:"<<i<<endl;
}
单链表的按位查找:
查找链表中第n个位置的data值
代码思路:首先是要创建一个用于遍历节点的指针p,p指针用于指向第n个位置节点,所以我们要对链表进行依次遍历,直到p指向第n个位置,然后输出该节点下的数值
代码实现:
//按位置进行查找
void ShowOne(LinkList &L,int n)
{
LNode *p; //用于专门开辟新的结点
p=L->next; //要向下进行遍历,所以该指针要先指向第一个(头结点的下一个)
for(int i=1;i<n;i++)
{
p=p->next;
}
cout<<"这个位置的值是:"<<p->data<<endl;
}
单链表的按位删除:
代码思路:首先是要创建一个用于遍历节点的指针p,另外创建一个指向被删除节点的指针q,当我们删除q指向的节点后,我们会发现链表已经断开,此时我们便要通过q节点以及p节点来恢复链表,删除前要想将p的下一个节点变成q的下一个节点也就是p->next=q->next。
代码实现:
//按位置删除
void DelList_W(LinkList &L,int n)
{
LNode *p,*q; //开辟两个新的指针,一个用于先遍历查找到要删除的结点,
p=L;
for(int i=1;i<n;i++)
{
p=p->next;
}
q=p->next; //此时的q正指向要删除的的结点
p->next=q->next; //q指的是被删除的结点的前驱,删除q后,q后续的结点要向前
delete(q); //删除q
while(p->next!=NULL) //将q后续的结点推向前
{
p=p->next;
}
}
单链表的按位插入:
代码思路:首先也是创建两个指针,一个遍历p,另外一个用于创建一个新的节点q,当我们遍历到要插入的位置时,则我们需要先把q的next指向p的next,然后将p的next重新指向q。
代码实现:
void DelList_I(LinkList &L,int n)
{
LNode *p,*q; //开辟两个新的指针,一个用于遍历,查一个用于指向开辟的新节点
p=L;
for(int i=1;i<n;i++)
{
p=p->next;
}
q=new LNode;
cout<<"请输入你要插入数据:";
int m;
cin>>m;
q->data=m;
q->next=p->next; //将q节点指向p的next节点
p->next=q; //将p的next指向q,实现按位插入
}
还有部分操作较为简单不一一展示。
源码部分:
第一步一定要进行初始化哦,还有得是,源码使用的是头插法建表,如果想用尾插法建表,只需要修改main方法中的 case 2部分哦(修改方式应该一眼就会,我就不过多解释了)。
#include<iostream>
using namespace std;
typedef struct node //typedef是函数的重命名
{
int data; //存储结点,包括 data域和 next域
struct node *next;
}LNode ,*LinkList;
//建立带头结点的单链表
void InitList(LinkList &L)
{
L=new LNode;
L->next=NULL;
}
//头插法建表 输入结果与输出结果相反
void InputList_H(LinkList &L,int n)
{
LNode *p; //用于专门开辟新的结点
cout<<"请输入这"<<n<<"个数:";
for(int i=1;i<=n;i++)
{
p=new LNode; //申请链表LNode的空间
cin>>p->data;
//将新结点插入头节点后面
p->next = L->next;
L->next = p;
}
}
//尾插法建表 输入顺序与输出顺序一致
void InputList_R(LinkList &L,int n)
{
LNode *p; //用于专门开辟新的结点
LNode *r; //用于指向表尾结点
r=L;
while(r->next!=NULL) //先遍历链表在插入
{
r=r->next;
}
cout<<"请输入这"<<n<<"个数:";
for(int i=1;i<=n;i++)
{
p=new LNode; //申请链表LNode的空间
cin>>p->data;
//将新结点插入表尾
r->next=p;
r=p; //将新插入的结点的指针p变为指针r,把插入的结点变为新的尾结点
}
r->next=NULL;
}
//链表显示
void ShowList(LinkList &L)
{
LNode *p; //用于专门开辟新的结点
p=L->next; //先将遍历指针指向头部,用头部往下进行遍历
cout<<"它的值如下:"<<endl;
while(p!=NULL)
{
cout<<p->data<<"\t";
p=p->next;
}
}
//计算表长 通过遍历的方法进行计算表的长度
void GetLength(LinkList &L)
{
LNode *p; //用于专门开辟新的结点
p=L->next; //先将遍历指针指向头部,用头部往下进行遍历
int i=0; //头结点不做计算
while(p!=NULL)
{
p=p->next;
i=i+1;
}
cout<<"该表长是:"<<i<<endl;
}
//在表尾进行出入
void InsertR(LinkList &L)
{
LNode *p; //用于专门开辟新的结点
p =new LNode; //申请链表LNode的空间
p->next=NULL;
cout<<"请输入插入的值:";
cin>>p->data;
LNode *r=L; //通过r的遍历找到表尾结点
while(r->next!=NULL)
{
r=r->next;
}
r->next=p;
}
//按位置进行查找
void ShowOne(LinkList &L,int n)
{
LNode *p; //用于专门开辟新的结点
p=L->next; //要向下进行遍历,所以该指针要先指向第一个(头结点的下一个)
for(int i=1;i<n;i++)
{
p=p->next;
}
cout<<"这个位置的值是:"<<p->data<<endl;
}
//按位置删除
void DelList_W(LinkList &L,int n)
{
LNode *p,*q; //开辟两个新的指针,一个用于先遍历查找到要删除的结点,
p=L;
for(int i=1;i<n;i++)
{
p=p->next;
}
q=p->next; //此时的q正指向要删除的的结点
p->next=q->next; //q指的是被删除的结点的前驱,删除q后,q后续的结点要向前
delete(q); //删除q
while(p->next!=NULL) //将q后续的结点推向前
{
p=p->next;
}
}
//安元素删除
void DelList_Y(LinkList &L,int n)
{
LNode *p,*q;
p=L->next;
while(p->data!=n)
{
p=p->next;
}
p=q->next; //此时的p正指向要删除的的结点
q->next=p->next; //q指的是被删除的结点的前驱,删除p后,p后续的结点要向前
delete(p); //删除p
while(q->next!=NULL) //将p后续的结点推向前
{
q=q->next;
}
}
//按位置插入
void DelList_I(LinkList &L,int n)
{
LNode *p,*q; //开辟两个新的指针,一个用于遍历,查一个用于指向开辟的新节点
p=L;
for(int i=1;i<n;i++)
{
p=p->next;
}
q=new LNode;
cout<<"请输入你要插入数据:";
int m;
cin>>m;
q->data=m;
q->next=p->next;
p->next=q;
}
int main()
{
LNode *head;
/*LinkList head;*/ //LinList head 等价于 LNode *head
int n;
do
{
cout<<"\t1 初始化"<<endl;
cout<<"\t2 输入"<<endl;
cout<<"\t3 显示"<<endl;
cout<<"\t4 长度"<<endl;
cout<<"\t5 尾插入"<<endl;
cout<<"\t6 位置查找"<<endl;
cout<<"\t7 按位置删除"<<endl;
cout<<"\t8 按位置插入"<<endl;
cout<<"\t9 删除某个元素"<<endl;
cout<<"\t0 退出操作"<<endl;
cout<<" 选择: ";
cin>>n;
switch(n)
{
case 1:
InitList(head); //创建单链表
cout<<endl;
break;
case 2:
int m;
cout<<"\n\t请输入数据量:";
cin>>m;
InputList_H(head,m); //头插法
//InputList_R(head,d); //尾插法
cout<<endl;
break;
case 3:
ShowList(head); //链表的显示
cout<<endl<<endl;
break;
case 4:
GetLength(head); //计算链表长度
break;
case 5:
InsertR(head); //在表尾借进行插入
break;
case 6:
int d;
cout<<"请输入查找的位置:";
cin>>d;
ShowOne(head,d); //位置查找
break;
case 7:
int p;
cout<<"请输入删除的位置:";
cin>>p;
DelList_W(head,p); //位置删除
break;
case 8:
int q;
cout<<"请输入插入的位置:";
cin>>q;
DelList_I(head,q);
break;
case 9:
int a;
cout<<"请输入删除的元素:";
cin>>a;
DelList_Y(head,a); //元素删除
break;
default:
break;
}
}while(n!=0);
return 0;
}