鲜衣怒马少年时,不负韶华行且知
链表
线性表基本概念
链表属于线性表的一种。
而线性表有两种表示方式,一种是顺序表示,另一种是链式表示。
-
顺序表示:
-
概念:指的是用一组地址连续的存储单元一次存储线性表的数据元素。
-
这个很好理解,主要凸显了这么几个字 地址连续 ,一次存储
-
也就是说元素在计算机内"物理地址"上是相邻的,我们只需要知道第一个元素的地址,线性表上的任意一个元素都可以随机存取。
-
虽然随机存取很方便,但是缺点也油然而生,当我们需要增加或者删除元素的时候,就需要在末尾进行增加删除。如果我们在中间进行插入或者删除,那么插入或者删除的位置之后的元素的地址都需要改变(因为物理地址是连续的)。这样是非常麻烦的。
-
于是链式表示(链表)变出现了
-
-
-
链式表示:
-
概念:是一组任意的存储单元存储线性表上的数据元素(这组存储单元可以是连续的,也可以是不连续的)
-
这便解决了增加和删除麻烦的问题(因为可以不连续)。但是伴随着的就是存取不方便。
-
那么有的小伙伴该产生疑问了:
链表的数据元素的地址可以不是连续的,那么如何访问这些元素呢?
-
在顺序表示的情况下,我们只需要知道第一个数据元素的地址,便可依次读出所有的数据元素
-
但是在链式情况下,这种方法就不适用了。因此我们就需要两部分信息,一部分是数据元素本身,而另一部分是指向下一个元素的地址。由这两部分组成的一个整体,我们称之为结点。链表就是一个个结点构成的。而其中用来存储数据元素信息的域称为数据域,用来存储直接后继存储位置的域称为指针域。
什么是单链表?循环链表?双向链表?
-
单链表:每个结点中只包含一个指针域。
-
双向链表:含有两个指针域,其一指向直接后继,另一指向直接前驱。
-
循环链表:每个结点只包含一个指针域,但是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
代码实现
代码实现是对链表整体上的一个实现,中间包含了链表的初始化,销毁链表,清空链表,返回链表长度,指定元素的位置,指定位置的元素,求某元素的前驱和后继等等操作。
直接复制代码粘贴即可运行,一步到位。
代码为原创,其中一些思路或者细节,如果发现错误或者逻辑问题的话,欢迎在评论区留言指正~
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
#define OK 1
#define error 0
typedef int ElemType;
typedef int Status;
//声明节点
typedef struct Node{
ElemType data;//数据域
struct Node *next; //指针域
}Node;
//初始化,创建一个空链表
Node* ListInitiate(){
Node *head=(Node *)malloc(sizeof(Node));//生成头结点内存空间
head->next=NULL;//头结点指向地址为空
return head;//返回头结点
}
//销毁链表
Status DestoryLinkList(Node *head){
Node *p;//定义一个指针对链表进行遍历
while(head!=NULL){
p=head;//遍历
head=head->next;
free(p);//释放内存空间
}
return OK;
}
//清空链表
Status ClearList(Node *head){
head->next=NULL;//直接将头结点指针指向空,即清空
return OK;
}
//链表长度
Status Length(Node *head){
Node *cur=head;//定义一个指针指向头结点地址,用来遍历
int m=0;
if(head->next==NULL){//如果链表为空,返回error
return error;
}
//遍历
int sum=0;
while(true){
//到最后一个元素
if(cur->next==NULL){
break;
}
cur=cur->next;
sum++;
}
return sum;
}
//指定位置的元素值
Status GetPlace(Node *head,int i){
//先求链表长度,考虑i的位置是否合法
int sum=0;
Node *cur1=head;
while(cur1->next!=NULL){
cur1=cur1->next;
sum++;
}
//判断i的位置是否合法
if(i>sum+1||i<1){
return error;
}
Node *cur=head;
int now=0;
//从头结点开始遍历,定义一个指针进行遍历,头结点是第0个,没有数据。当遍历到第i个的时候,返回数据
while(now!=i){
cur=cur->next;
now++;
}
return cur->data;
}
//链表已存在元素的位序
Status GetData(Node *head,int i){
//定义一个指针进行遍历
Node *cur=head;
int now=0;
//如果当前结点的数据不符合条件,并且结点不为空,一直遍历,直到符合条件或者结点为空
while(cur->data!=i&&cur!=NULL){
cur=cur->next;
now++;
}
//如果为空,返回error
if(cur==NULL){
return error;
}
//如果不为空,说明符合条件,直接返回数据
return now;
}
//求输入元素的直接前驱
Status GetPre(Node *head,int i){
//定义结点进行遍历
Node *cur=head;
//如果头结点下一个结点的数据域为指定元素,直接返回错,因为头结点不存数据
if(head->next->data==i){
return error;
}
//如果下一个结点的数据不等于指定数据,并且下一个元素不为空,就进行遍历。直到等于指定元素或者为空,停止。
while(cur->data!=i&&cur!=NULL){
cur=cur->next;
}
//为空
if(cur==NULL){
return error;
}
//否则返回数据
return cur->data;
}
//求输入元素的直接后驱
Status GetNext(Node *head,int i){
Node *cur=head;
//如果当前所指结点数据匹配成功或者当前结点为空,或者下一个结点为空0,结束循环
while(cur->data!=i&&cur!=NULL&&cur->next!=NULL){
cur=cur->next;
}
//如果当前结点为空或者下一个结点为空,返回error
if(cur==NULL||cur->next==NULL){
return error;
}
return cur->next->data;
}
//在第i个位置插入元素
Status addNode(Node *head,int i,int e){
//先求链表长度,考虑i的位置是否合法
int sum=0;
Node *cur1=head;
while(cur1->next!=NULL){
cur1=cur1->next;
sum++;
}
//判断i的位置是否合法
if(i>sum||i<1){
return error;
}
else{
//辅助遍历
Node *cur=head;
int now=0;
while(now!=i-1){
//第i-1个位置结束循环 ,因为要在第i个位置插入元素
cur=cur->next;
now++;
}
Node *e1=(Node*)malloc(sizeof(Node));
e1->data=e;
e1->next=cur->next;
cur->next=e1;
return OK;
}
}
//删除第i个位置的元素
Status deleteNode(Node *head,int i){
//链表为空,不能删除节点
if(head->next==NULL){
return error;
}
//先求链表长度,考虑i的位置是否合法
int sum=0;
Node *cur1=head;
while(cur1->next!=NULL){
cur1=cur1->next;
sum++;
}
//判断i的位置是否合法
if(i>sum||i<1){
return error;
}
else{
Node *cur=head;
int now=0;
while(true){
//第i-1个位置结束遍历,因为要把第i个删掉
if(now==i-1){
break;
}
cur=cur->next;
now++;
}
//第i-1个位置的下一个为第i+1的地址
cur->next=cur->next->next;
return OK;
}
}
//输出有的链表元素
Status ScanNode(Node *head){
Node *cur=head->next;
while(cur!=NULL){
cout<<cur->data<<endl;
cur=cur->next;
}
return OK;
}
//初始化并用头插法或尾插法插入元素
Status hahaha(Node *head,int e){
//先求链表长度,考虑i的位置是否合法
int sum=0;
Node *cur1=head;
while(cur1->next!=NULL){
cur1=cur1->next;
sum++;
}
//辅助遍历
Node *cur=head;
int now=0;
while(now!=sum){
//第i-1个位置结束循环 ,因为要在第i个位置插入元素
cur=cur->next;
now++;
}
Node *e1=(Node*)malloc(sizeof(Node));
e1->data=e;
e1->next=cur->next;
cur->next=e1;
return OK;
}
//实现单链表的逆序输出
Status Nixu(Node *head){
int sum=0;
Node *cur1=head;
while(cur1->next!=NULL){
cur1=cur1->next;
sum++;
}
//将链表中的数据存放在一个数组中,并且逆序输出即可
int a[sum];
for(int m=0;m<sum;m++){
a[m]=head->next->data;
head=head->next;
}
for(int n=sum-1;n>=0;n--){
cout<<a[n];
}
}
int main(){
ElemType i;
ElemType e;
int jieguo;
Node *head;
Node *head1;
bool flag=false;
bool fg=false;
bool flag1=false;
cout<<"********************************************"<<endl;
cout<<"*---------1.初始化一个链表-----------------*"<<endl;
cout<<"*---------2.销毁链表-----------------------*"<<endl;
cout<<"*---------3.清空链表-----------------------*"<<endl;
cout<<"*---------4.求链表长度 --------------------*"<<endl;
cout<<"*---------5.指定位置的元素值---------------*"<<endl;
cout<<"*---------6.链表已存在元素的位序-----------*"<<endl;
cout<<"*---------7.求输入元素的直接前驱-----------*"<<endl;
cout<<"*---------8.求输入元素的直接后继-----------*"<<endl;
cout<<"*---------9.在第i个位置插入一个元素--------*"<<endl;
cout<<"*---------10.删除第i个位置的元素-----------*"<<endl;
cout<<"*---------11.输出链表----------------------*"<<endl;
cout<<"*---------12.初始化并用尾插法插入元素------*"<<endl;
cout<<"*---------13.退出该程序--------------------*"<<endl;
cout<<"*---------14.实现单链表的逆序存放----------*"<<endl;
cout<<"********************************************"<<endl;
int m=0;
cout<<endl;
while(!fg){
cout<<"请输入所需操作:"<<endl;
scanf("%d",&m);
switch(m){
case 1:
head=ListInitiate();
flag=true;
break;
case 2:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
jieguo=DestoryLinkList(head);
cout<<jieguo<<endl;
}
break;
case 3:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
jieguo=ClearList(head);
cout<<jieguo<<endl;
}
break;
case 4:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
jieguo=Length(head);
cout<<"链表长度为";
cout<<jieguo<<endl;
}
break;
case 5:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
cout<<"请先输入指定位置"<<endl;
cin>>i;
jieguo=GetPlace(head,i);
cout<<jieguo<<endl;
}
break;
case 6:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
cout<<"请输入指定元素"<<endl;
cin>>i;
jieguo=GetData(head,i);
cout<<jieguo<<endl;
}
break;
case 7:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
cout<<"请输入指定元素"<<endl;
cin>>i;
jieguo=GetPre(head,i);
cout<<jieguo<<endl;
}
break;
case 8:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
cout<<"请输入指定元素"<<endl;
cin>>i;
jieguo=GetNext(head,i);
cout<<jieguo<<endl;
}
break;
case 9:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
cout<<"请输入元素插入的位置"<<endl;
cin>>i;
cout<<"请输入需要插入的元素"<<endl;
cin>>e;
jieguo=addNode(head,i,e);
cout<<jieguo<<endl;
}
break;
case 10:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
cout<<"请输入想要删除位置"<<endl;
cin>>i;
jieguo=deleteNode(head,i);
cout<<jieguo<<endl;
}
break;
case 11:
if(flag!=true){
cout<<"请先初始化链表"<<endl;
}else{
ScanNode(head);
}
break;
case 12:
head1=ListInitiate();
cout<<"您现在可以插入元素,如果输入000即可结束输入"<<endl;
while(true){
cout<<"请输入元素"<<endl;
cin>>i;
if(i==000){
break;
}
hahaha(head1,i);
}
ScanNode(head1);
flag1=true;
break;
case 13:
fg=true;
case 14:
if(flag1!=true){
cout<<"请先进行操作12创造一个链表"<<endl;
}else{
Nixu(head1);
break;
}
}
}
}