升华笔记一:头指针和头结点的异同? 头指针: a.头指针是指链表指向第一个结点的存储位置指针,若链表有头结点,则是指向头结点的指针。 b.头指针具有标识作用,所以常用头指针冠以链表的名字; c.无论链表是否为空,头指针均不为空。头指针是链表的必要元素。 头结点: a.头结点是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(也可以存放链表的长度); b.有了头结点,对在第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就同一了; c.头结点不一定是链表必要素。
2.单链表 n个结点(ai的存储映像)链结成一个链表,即为线性表(a1,a2....an)的链式存储结构,因为此链表的每个结点只包含一个指针域,所以称之为单链表。
3.链式存储结构指针代码示例 /*线性表的单链表存储结构 * 结点由存放数据元素的数据域和存放后继结点地址的指针域组成*/ typedef int ElemType;
typedef struct Node { ElemType data; //int类型成员变量,作为结点的数据域 struct Node *next; //struct Node类型成员指针变量,作为结点的指针域 }Node; typedef struct Node *LinkList; //定义LinkList 注释: (1)Node相当于struct Node结构体;*LinkList相当于struct Node结构体 (2)假设指针p是指向线性表第i个元素的指针,则结点ai数据域和指针域为p->data、p->next即: p->data的值为该结点ai的数据域,内容是一个数据元素; p->next的值是一个指针,指向第(i+1)个元素(结点)的存储地址,即指向ai+1的指针 即p->data=ai p->next->data=ai+1
4.单链表的读取、插入与删除操作
(1)单链表的读取操作 实现操作: GetElem(LinkList L,int i,ElemType *e),从单链表L中取出第i个数据元素,存放到指针变量i指向的地址空间中。 算法思路:不像线性表的顺序存储结构可以很容易的从任意位置读取一个元素,单链表的数据元素读取必须从头开始找,即工作指针p后移。 a.声明一个结点p指向链表第一个结点,初始化j从1开始遍历 b.当j typedef int ElemType;
typedef struct Node *LinkList; //定义LinkList
Status GetElem(LinkList L,int i,ElemType *e) { int j; LinkList p; //声明一个结点p p=p->next; //让结点p指向链表L的第一个结点 j=1; while(p&&jnext; //让p指向下一个结点 j++; } if(!p "| j>i) return ERROR; *e=p->data; //查找成功,将链表中的第i个元素的数据存储到指针e指向的空间 return OK; } 注释:p为新定义的一个结点,while(p&&j (2)单链表插入操作 实现操作: ListInsert(LinkList *L,int i,ElemType e),将数据元素e插入到单链表L第i个位置 算法思路: s->next =p->next; p->next=s; a.声明一个结点p指向链表第一个结点,初始化j从1开始遍历 b.当jdata; -单链表的插入标准语句s->next=p->next,p->next=s 源码实现: /*初始条件:顺序线性表L已存在,1=《i<=ListLength(L) *操作结构:将数据元素e插入到单链表L第i个位置*/ #define OK 1 #define ERROR 0 typedef int Status;
typedef int ElemType;
Status ListInsert(LinkList *L,int i,ElemType e) { int j; LinkList p,s; //声明一个结点p p=*L; j=1; while(p&&jnext; //让p指向下一个结点 j++; } if(!p || j>i) return ERROR; s=(LinkList)malloc(sizeof(Node)); //生成新结点,即在内存中找了一小块空地,准备用来存放e数据s结点 s->data=e; //关键1:查找成功,将数据元素e赋值给s结点的数据域 s->next =p->next;//关键2:将结点p的后继结点赋值给s的后继(p->next为指向结点p下一个存储地址所在的结点) p->next=s; //关键3:设置结点p的后继结点为结点s return OK; } 注释:p为新定义的一个结点,while(p&&j(3)单链表删除操作 实现操作: ListDelete(LinkList *L,int i,ElemType *e),删除单链表L中第i个数据元素,并将数据存放至指针e指向的空间中 算法思路:{ p->next=p->next->next(或者q=p->next;p->next=q->next) } a.声明一个结点p指向链表第一个结点,初始化j从1开始遍历 b.当jnext赋值给q -设置结点p的后继结点为q->next,即p->next=q->next; -将结点q的数据域数据存放至e e.释放q结点,返回成功标识 源码实现: /*初始条件:顺序线性表L已存在,1=《i<=ListLength(L) *操作结构:删除单链表L中第i个数据元素,并将数据存放至指针e指向的空间中*/ #define OK 1 #define ERROR 0 typedef int Status;
typedef int ElemType;
typedef struct Node *LinkList; //定义LinkList
Status ListInsert(LinkList *L,int i,ElemType *e) { int j; LinkList p,q; //声明一个结点p p=*L; j=1; while(p->next&&jnext; //让p指向下一个结点 j++; } if(!p || j>i) return ERROR; q=p->next; //设置q为p的后继结点 p->next=q->next; //将q的后继结点设置为p的后继结点 *e=q->data; //将q结点中的数据给e free(q); //设置完成后,让 系统回收此结点,释放内存 return OK; }
升华笔记二:s、p、s->data、s->next、p->next辨析? (1)LinkList p,s:声明两个结点p、s,包含数据域和指针域; (2)s->data:为结点s的数据域,其值为一个数据 (3)s->next::为结点s的指针域,其值为下一个结点存储地址 (4)s->next=p->next:将结点p的