概述
链表是什么:
每个节点通过指针相连。
每个节点有一个前驱节点和一个后继节点(除首尾)。
节点的构造
typedef struct Node //typedef数据类型别名
{
int data; //指针域
struct Node *next; //数据域
}Node,*LinkList //Node相当于struct node,*linklist相当于 struct node *
创建单链表
创建单链表有两种方式,头插法和尾插法。
头插法
void create_head(Node*&L,int a[],int n)
{
Node *p;//定义一个新的结点p,用来指向新结点
int i;//循环变量
Chead = (Node*)malloc(sizeof(Node));//定义一个头结点
Chead->next = NULL; //将链表置为空
for(i=0;i<n;++i)
{
p=(Node*)malloc(sizeof(Node)); //为新结点申请空间
p-data = a[i]; //给数据域赋值
s->next = Chead->next;//s指向新结点的指针域next指向C中的开始结点
Chead->next = s;//头结点的指针域next指向s结点,即s为head下的第一个开始结点
}
}
尾插法
void create_tail(Node *&Ctail,int a[],int n) Ctail为需要改变的变量,所以用引用类型&C
{
Node *p,*r; //定义两个结点,p用来指向新申请的结点,r始终指向Ctail的终端结点
int i;
Ctail=(Node *)malloc(sizeof(Node)); //申请头结点空间
Ctail->next = NULL;//将头结点的下一个结点置为NULL
r = Ctail; //r指向头结点,此时只有头结点,所以也是尾结点
for(i=0;i<n;++i)
{
p=(Node*)malloc(sizeof(Node));//p指向新申请的结点
p->data = a[i];//循环将a数组的值存入链表
r->next = p; r结点为尾结点,用来接收新的结点
r=r->next;//r指向终端结点,下次还能接收新结点
}
r->next=NULL;//数组a中的所有元素都存入了链表Ctail中,C的终端结点指针域置为空,C链表建立完成
}
链表的具体 操作
除了定义链表的结构,创建链表。很重要的还有对链表的插入,删除。
插入
在链表插入数据的时候,会涉及到指针指向的改变,所以比顺序表要复杂一些。
int list_insert(LinkList &C,int i,int x) // i为链表的长度,x为要插入的值
{
Node *p,*s;
p=C;
int j=0;
while(p && i<j-1)
{
//循环找到链表的末尾,插入x
p=p->next;
++j;
}
if(!p||j>1)
retrun 0;//链表不存在,或者没有位置的错误情况
s = (Node)malloc(sizeof(Node));//申请s的空间,用来插入x。
s->data = x; //s当中存放要插入的值
p->next = s; //p的后继指向s
return 1;
}
删除
因为删除链表当中的数据,还需要将指针的指向也做出修改,所以与一般的顺序表的插入删除不一样。
因为删除也会是需要先查找,再进行删除的,所以查找代码就在删除当中。
int findAndDelete(Node *C,int x)
{
Node *p,*q;
p=C;
//先查找需要删除的x。
while(p->next!=NULL) //依次对比查找,只要链表还有值,就对比。
{
if(p->next->data == x)
break;//找到x了,就停止循环。
p=p->next;//将p->next的值,即找到的值,存入p中。
}
if(p->next==NULL)
{
return 0;//判断p当中是否存有值,没有值存在,就是没找到的情况直接结束。
}
else
{ //找到p的值,删除操作开始
q=p->next; //q作为中间结点来暂时存放p->next(需要删除的结点)
p->next = p->next->next;//p->next被删除了,那就指向p->next的下一个结点。
free(q);//释放q结点
return 1;
}
}
总结
链表的查,增,删已经基本完成,但链表还能够有很多灵活的用法需要学习。