2.3.1单链表的定义
线性表的链式存储又称单链表,它是通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。
引入头结点的优点:
1、由于第一个数据结点的位置被存放在头结点的指针域中,所以在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理
2、无论链表是否为空,其头指针都指向头结点的非空指针(空表中头节点的指针域为空),因此空表和非空表的处理得到了统一
typedef struct LNode{//定义单链表结点类型
ELemType data;//数据域
struct LNode *next;//指针域
}LNode,*LinkList;
2.3.2单链表上基本操作的实现
1、链表的建立
1、带头结点的头插法
LinkList List_Head(LinkList &L)//逆向建立单链表
{
LNode *s,x;
L=(LinkList)malloc(sizeof(LNode));//创建头结点
L->next=NULL;//初始化空链表
scanf("%d",&x);//输入节点的值
while(x!=9999){//输入9999表示结束
s=(LNode*)malloc(sizeof(LNode));//创建新结点
s->data=x;
s->next=L->next;
L->next=s;//将新结点插入表中,L为头指针
scanf("%d",&x);
}
return L;
}
2、不带头结点的头插法
void InsertByHead(pNode *pHead, int value)
{
pNode pNew = (pNode)malloc(sizeof(Node));
if (NULL == pNew)
{
printf("malloc free failed!\n ");
return;
}
pNew->value = value;
pNew->next = *pHead;
*pHead = pNew;
}
3、带头结点的尾插法
LinkList List_TailInsert(LinkList &L)
{
InitList(L);
LNode *s,*r=L;
ElemType e;
printf("输入元素(输入9999为停止)");
scanf("%d",&e);
while(e!=9999)
{
s=(LNode*)malloc(sizeof(LNode));
s->data=e;
r->next=s;
r=s;
scanf("%d",&e);
}
r->next=NULL;
return L;
}
4、不带头结点的尾插法
void InsertByTail(pNode *pHead, int value)
{
if (NULL ==*pHead)
{
InsertByHead(pHead, value);
}
else
{
pNode pNew = (pNode)malloc(sizeof(Node));
if (NULL == pNew)
{
printf("malloc free failed!\n ");
return;
}
pNew->value = value;
pNew->next = NULL;
pNode pos = *pHead;
while (pos->next != NULL)
{
pos = pos->next;
}
pos->next = pNew;
}
}
5、按序号查找结点值
LNode *GetElem(LinkList L,int i)
{
int j=1;
LNode *p=L->next;
if(i==0)
return L;
if(i<1)
return NULL;
while(p&&j<i){
p=p->next;
j++;
}
return p;
}
6、按值查找表结点
LNode *LocateElem(LinkList L,ElemType e){
LNode *p=L->next;
while(p!=NULL&&p->data!=e)
p=p->next;
return p;
}
7、插入节点操作
向某一结点后插入
p=GetElem(L,i-1);
s->next=p->next;
p->next=s;
向某一结点前插入
方法1
s->next=p->next;//修改指针域,不能颠倒
p->next=s;
temp=p->data;//交换数据域
p->data=s->data;
s->data=temp;
方法2
Q=P;
P=L;
while(P->next!=Q) P=P->next;
S->next=P->next;
P->next=S;
8、删除节点操作
带头节点
p=GetElem(L,i-1);//查找删除位置的前驱结点
q=p->next;//令q指向被删除结点
p->next=q->next;//将*q结点从链中"断开"
free(q);//释放结点的存储空间
不带头结点
//头删
void DeleteByHead(pNode *pHead)
{
if (*pHead != NULL)
{
pNode pos = *pHead;
*pHead = pos->next;
free(pos);
pos = NULL;
}
}
//尾删
void DeleteByTail(pNode *pHead)
{
if (NULL ==(*pHead)->next || NULL == *pHead)
{
DeleteByHead(pHead);
}
else
{
pNode pos = *pHead;
while (pos->next->next != NULL)
{
pos = pos->next;
}
free(pos->next);
pos->next = NULL;
}
}
9、表长
不带头结点求表长
int GetLength(pNode pHead)
{
pNode pos=pHead;
int count=0;
while(pos!=NULL)
{
pos=pos->next;
count++;
}
return count;
}
带头节点的
//得到带头结点的单链表表长
int Length(LinkList L)
{
int length = 0;
while(L->next != NULL)
{
length++;
L = L->next;
}
return length;
}