今天主要整理一下链表的相关操作,首先还是先来说说线性结构的两种存储方式:顺序存储和链式存储。
两者有什么分别呢?从以下几方面来简单的说说:
1、逻辑结构
数组(静态)必须事先定义其固定的大小(长度),不能随着数据的需要而动态增加或减少其空间,所以当数据过大,会造成数据越界;数据量过小,会造成内存浪费。
链表则是动态申请的内存空间,根据需求动态的申请或删除内存空间,对于的是增加/删除数据,所以比数组要灵活。
2、物理存储即内存分配
数组是连续的内存空间,从栈中分配,访问数据时可以通过下标直接读取,时间复杂度为O(1),但插入和删除时移动量太大。
链表是物理上非连续的内存空间,从堆中分配,访问数据时需遍历整个链表直到找到要访问的数据,但插入和删除数据时可根据位置指针快速找到数据并实现增删。
3、除了需创建以外,链表在使用完之后还要进行空间释放,以免造成内存出错。
好了,下面回归正题,聊聊链表的几个基本操作。
1、创建
链表有带头结点和不带头结点之说,创建方法有两种:头插法和尾插法,经过排列组合,存在4种形式的创建,不过小编还是最喜欢带头结点的尾插法。(纯属个人喜好^_^)
2、求表长
要特别注意带头结点的链表求表长的时候是不包括头结点的。
3、查找
有按序号查找和按值查找,但由于单链表不具有按序号随机访问的特点,只能从头指针开始遍历,这增加了时间复杂度。
4、插入
前插入和后插入两种方式,但是时间复杂度却有很大的差别,后插法时间复杂度为O(1),前插法因为要找到待插入结点*p的前驱,时间复杂度为O(n)。
5、删除
删除结点,首先要找到待删除结点*p的前驱结点*q,然后进行指针的转移实现操作。需要特别注意,结点删除后一定要释放。
实现代码如下:
#include
#include
#include
#include
using namespace std;
typedef struct student //定义一个链表结点
{
int data;
struct student *next;
}Lnode,*LinkList;
Lnode *creat() //创建带头结点的单链表 ,尾插法
{
Lnode *H,*p,*s; //定义指针变量
int x,cycle=1;
H = (Lnode*)malloc(sizeof(Lnode)); //空间分配
p = H;
while(cycle)
{
printf("please input the data:");
scanf("%d",&x); //输入新结点的值
if(x!=0)
{
s=(Lnode*)malloc(sizeof(Lnode)); //分配空间保存新结点
s->data=x; //新结点赋值
p->next=s; //连接新结点,实现插入
p=s; //指针后移
}
else cycle=0;
}
if(p!=NULL)
p->next=NULL; //对于非空表,最后结点的指针域放空指针
return H;
}
//求表长
int length(Lnode *H)
{
int n=0;
Lnode *p;
p=H->next; //长度不包括头结点,需从下一结点开始计数
// if(H==NULL) return 0; //表空返回0
while(p!=NULL)
{
p=p->next; //指针后移
n++; //计数器更新
}
return n;
}
Lnode *Get_LinkList(LinkList H,int i)//查找
{
Lnode *p;
int j=0;
p = H;
while(p->next!=NULL && j
{
p = p->next;
j++;
}
if(j == i)
return p;
else return NULL;
}
int Insert_LinkList(LinkList H,int i,int x)//插入
{
Lnode *p,*s;
p=Get_LinkList(H,i-1);
if(p == NULL) //未找到插入点
return 0;
else
{
s=(Lnode*)malloc(sizeof(Lnode)); //新值开辟新空间
s->data=x;
s->next=p->next; //新结点插入
p->next=s;
return 1;
}
}
int Del_LinkList(LinkList H,int i)//删除
{
Lnode *p,*s;
p=Get_LinkList(H,i-1);
if(p==NULL||p->next==NULL)
{
printf("error!\n"); return 0;
}
else
{
s=p->next; //S指向第i个结点
p->next=s->next; //改变指向实现删除
free(s); //结点删除后要释放s
return 1;
}
}
void print(Lnode *H) //输出
{
Lnode *p;
int n;
n=length(H);
if(n==0)
printf("\nIt's NULL\n"); //表空
else
printf("\nNow,these %d records are :\n", n);
p=H->next;
if(H!=NULL) //判断表不为空
while(p!=NULL)
{
printf(" yyy %d \n",p->data);
p = p->next;
}
}
int main()
{
Lnode *L,*find; //头指针变量L
int len,i,x;
L=creat(); //创建
printf("The length:%d\n",length(L));
print(L);
printf("\n输入要查找的结点 i:"); //查找
scanf("%d",&i);
find=Get_LinkList(L,i);
printf("This number is: ", find->data);
printf("\n输入要插入的结点位置 i 和值 x:"); //插入
scanf("%d%d",&i,&x);
if(Insert_LinkList(L,i,x))
print(L);
else printf("ERROR!");
printf("\n输入要删除的结点 i:"); //删除
scanf("%d",&i);
if(Del_LinkList(L,i))
print(L);
system("pause");
return 0;
}