线性表的链式存储结构
单链表结构
将线性表L=(a 0 ,a 1 ,……,a n-1 )中各元素分布在存储器的不同存储块,称为结点,通过地址或指针建立它们
之间的联系,所得到的存储结构为链表结构。表中元素a i 的结点形式如图所示。
其中,结点的data域存放数据元素a i ,而next域是一个指针,指向a i 的直接后继a i+1 所在的结点。于是,线性表
L=( a 0 ,a 1 ,……,a n-1 )的结构如图所示。
例 设线性表L=(赵,钱,孙,李,周,吴,郑,王),各 元素在存储器中的分布如图所示。
结点类型描述
typedef int DateType;
typedef struct _node
{
DateType data; /* 结点的数据域 */
struct _node *next; /* 结点的后继指针域 */
}LISTNODE_T, *LINKLIST;
LISTNODE_T A;
LINKLIST p = &A;
则结构变量A为所描述的结点,而指针变量p为指向此类型结点的指针(p的值为结点的地址),如图
设p指向链表中结点a
获取a i ,写作:p->data;而取a i+1 ,写作:p->next->data.。 另外,若指针p的值为NULL,则它不指向任何结点,
此时取p->data或p->next是错误的。
• 可调用C C语言中malloc()函数向系统申请结点的存储空间,例如:
• LINKLIST p;
• p = (LINKLIST)malloc(sizeof(LISTNODE_T));
• 则创建一个类型为LISTNODE_T的结点,且该结点的地址已存入指针变量p中:
基本运算的相关算法
建立单链表
算法思路:依次读入表L=(a 0 ,…,a n-1 )中每一元素a i (假设为整型),若a i ≠结束符(-1),则为a i创建 一结点,然
后插入表尾,最后返回链表的头结点指针H。
算法描述
LINKLIST Linklist_Create2(void)
{
LINKLIST Header, r,p;
DateType val;
//先建立空的头节点header
Header = (LINKLIST)malloc(sizeof(LISTNODE_T));
if(NULL == Header)
{
puts(" malloc falied ");
return NULL;
}
Header->data = 0;
Header->next = NULL;
r = Header;
while(1)
{
puts(" input num (-1 exit)");
(void)scanf("%d",&val);
if( -1 == val)
break;
p = (LINKLIST)malloc(sizeof(LISTNODE_T));
if(NULL == p)
{
puts(" malloc falied");
return NULL;
}
p->data = val; //存入数据
p->next = NULL;//
r->next = p;//r指向新的节点
r = p; //移动r到链表尾部
}
return Header;
}
设L=(2,4,8,-1),则建表过程如下:
链表遍历
算法思路:从链表的a 0 起,判断下一个节点的地址是否为NULL,打印出所有的数据
void Linklist_Print(LINKLIST H)
{
while( H->next )
{
printf("%d ",H->next->data);
H = H->next;
}
puts("\n");
}
链表查找-按序号查找
从链表的a 0 起,判断是否为第i结点,若是则返回该结点的指针,否则查找下一结点,依次类推。
LINKLIST Linklist_Get(LINKLIST H, int pos)
{
LINKLIST p = H;
int index = -1;
if(pos <0)
{
puts(" position is invalid: <0 ");
return NULL;
}
while( p->next && index < pos )
{
p = p->next;
index++;
}
if( index == pos)
{
return p;
}
else
{
puts(" position is invalid: >length ");
return NULL;
}
}
链表查找-按值查找(定位)
算法思路:从链表结点a 0 起,依次判断某结点是否等于x,若是,则返回该结点的地址,若不是,则查找下一结点
a 1 ,依次类推。若表中不存在x,则返回NULL。
LINKLIST Linklist_Locate(LINKLIST H, DateType val )
{
LINKLIST p = H->next;
while( p && p->data != val)
{
p = p->next;
}
return p;
}
链表的插入:
算法思路:调用算法GetLinklist(h, i-1),获取结点a i-1 的指针p(a i 之前驱),然后申请一个q结点,存入x,并将
其插入p指向的结点之后。插入时的指针变化如图
int Linklist_Insert(LINKLIST H, int pos, DateType val)
{
LINKLIST p,q;
if(0 == pos)
p = H;
else
p = Linklist_Get(H, pos-1);
if(NULL == p)
{
puts("para is invalid");
return ERROR;
}
else
{
q = (LINKLIST)malloc(sizeof(LISTNODE_T));
if(NULL == p)
{
puts("malloc failed ");
return ERROR;
}
q->data = val;
q->next = p->next;
p->next = q;
return SUCCESS;
}
}
链表的删除
算法思路:同插入法,先调用函数Linklist_Get(h, i-1),找到结点a i 的前驱,然后如图所示,将结点a i 删除之。
int Linklist_Delete(LINKLIST H, int pos)
{
LINKLIST p,q;
if( 0 == pos)
{
p = H;
}
else
{
p = Linklist_Get(H, pos-1);
}
if(NULL == p || p->next == NULL )
{
puts("para is invalid ");
return ERROR;
}
else //若p及p->next所在的结点存在
{
q = p->next;
p->next = q->next;
free(q); //删除结点//
q = NULL;
return SUCCESS;
}
}
单链表倒置
void Linklist_Reverse(LINKLIST H)
{
LINKLIST p, q;
p = H->next;//令指针p指向结点a 0 //
H->next = NULL;//将原链表置空
while(p)
{
q = p;
p = p->next;//将结点a i 插入到头结点之后//
q ->next = H->next;
H->next = q;
}
}
单链表的有序插入
int Linklist_Order_Insert(LINKLIST H, DateType val)
{
LINKLIST p,q;
p = (LINKLIST)malloc(sizeof(LISTNODE_T));
if(NULL == p)
{
puts("malloc failed ");
return ERROR;
}
p->data = val;
q = H;
while(q->next && q->next->data < val)
{
q = q->next;
}
p->next = q->next;
q->next = p;
return SUCCESS;
}
单链表的排序
void Linklist_Sort(LINKLIST H)
{
LINKLIST p,q,r;
p = H->next;
H->next = NULL;
while(p)
{
q = p;
p = p->next;
r = H;
while( r->next && r->next->data < q->data )
r = r->next;
q->next = r->next;
r->next = q;
}
}
版权声明
内容摘取华清创客学院培训资料,个人水平有限,感谢华清创客学院的指导和帮助。