线性表---单链表
typedef struct node {
ElemType data; //数据域
struct node *next; //指针域
}LNode, *LinkList; // LinkList为指向LNode类型的指针
结点:数据元素的存储映像
链表:n个结点链接成起来形成一个链表,即为线性表的 链式存储结构
单链表: 结点中只包含一个指针域
-
头指针:指向链表中第一个结点(或为头结点、或为首元结点)的指针
-
头结点:在链表的首元结点之前附设的一个结点;数据域内只放表长等信息,它不计入表
长度。其作用是统一空表、和非空链表的形式 -
首元结点:指链表中存储线性表第一个数据元素a1的结点
线性表的链式表示和实现
(1)单链表的建立
- 先开辟头指针,建立头结点;
- 为每个新元素开辟存储空间,并赋值
- 将新结点链接到表尾
1、尾插法
/*例1:用尾插法建立26个字母的带表头结点的单链表*/
/*算法1-1*/
LinkList createLinkList1() //尾插法建立带表头结点的单链表
{
LNode *L,*p,*s; //L头指针, p指向尾结点, s指向新结点
L=(LNode *) malloc(sizeof(LNode)); //申请空白结点, L指向头结点
L->next =NULL; //建立了头结点
p=L; //p指向当前的尾结点
for(i=1;i<=26;i++)
{
s=(LNode *) malloc(sizeof(LNode)); //申请空白结点, s指向
s->data=i+‘a’-1; //给s->data 赋值
p->next=s; s->next =NULL; //s指向的结点插入单链表的表尾
p=s; //p总是指向当前链表的尾结点 , 等价于p=p->next
}
return L;
}
/*算法1-2*/
void createLinkList2(LinkList *L)
{
//尾插法建立带表头结点的单链表 ,L指向头结点的指针的指针
Lnode *p,*s; //p指向尾结点, s指向新结点
*L=(LNode *) malloc(sizeof(LNode)); //申请空白结点, *L指向头结点
if (*L==NULL) exit(0);
*L->next =NULL; //建立了头结点
p=*L; //p指向当前的尾结点
for(i=1;i<=26;i++)
{
s=(LNode *) malloc(sizeof(LNode)); //申请空白结点, s指向
if (!s) exit(0);
s->data=i+‘a’-1; //给s->data 赋值
p->next=s; s->next =NULL; //s指向的结点插入单链表的表尾
p=s; //p总是指向当前链表的尾结点 , 等价于p=p->next
}
}
2、头插法
/*例2:用头插法建立26个字母的带表头结点的单链表*/
/*算法2-1*/
LinkList createLinkList1() /头插法建立带表头结点的单链表
{
LNode *L,*s; //L头指针, s指向新结点
L=(LNode *) malloc(sizeof(LNode)); //申请空白结点, L指向头结点
L->next =NULL; //建立了头结点
for(i=26;i>=1;i--)
{
s=(LNode *) malloc(sizeof(LNode)); //申请空白结点, s指向
s->data=i+‘a’-1; //给s->data 赋值
s->next=L->next;
L->next =s; //s指向的结点插入头结点后面
}
return L;
}
/*算法2-2*/
void createLinkList2(LinkList *L)
{
//L指向头结点的指针的指针
LNode *s; //p指向尾结点, s指向新结点
*L=(LNode *) malloc(sizeof(LNode)); //申请空白结点, *L指向头结点
if (*L==NULL) exit(0);
*L->next =NULL; //建立了头结点
for(i=26;i>=1;i--)
{
s=(LNode *) malloc(sizeof(LNode)); //申请空白结点, s指向
if (!s) exit(0);
s->data=i+‘a’-1; //给s->data 赋值
s->next=*L->next;
*L->next =s; //s指向的结点插入头结点的后面
}
}
(2)单链表的查找
思路:从头指针开始逐一查询
/*例3:单链表的查询*/
LNode* GetElem_L2(LinkList L, ElemType x)
{
//在带头结点的单链表L中 查找元素值为x的结点,
//若找到返回指向该结点的指针,否则返回NULL.
LNode *p;
p=L->next; //p指向首元结点
while (p->data!=x && p)
{
p=p->next; //p指针后移
}
return p;
}
算法的时间复杂度:O(n)
(3)单链表的插入
在单链表中第i个位置插入一个元素x的示意图如下:
/*例4:单链表的插入*/
bool ListInsert_L(LinkList *L, int i, ElemType e)
{
// L 为指向带头结点的单链表的头指针的指针
//在链表中第i 个结点之前插入新的元素 e
LNode *p; int j;
p = *L; j = 0;
while (p && j < i-1)
{
p = p->next; ++j;
} // 寻找第 i-1 个结点
if (!p || j > i-1)
{
return false; // i 大于n+1或者小于1
}
s = (LinkList) malloc(sizeof(LNode)) ; // 生成新结点
if ( s == NULL)
{
return false;
}
s->data = e;
s->next = p->next; p->next = s; // 插入
return true;
} // LinstInsert_L
算法的时间复杂度:O(n)
(4)单链表的删除
/* 删除单链表 */
void deleteList(LNode *pHead)
{
LNode *p1,*p2;
p1 = pHead;//p1指向第一个结点
while(p1->next != pHead)//当p1不指向头结点时
{
p2 = p1->next;
free(p1);//删除第n个链表
p1 = p2;
}
free(pHead);//删除头结点
}
算法时间复杂度:O(n)