第一部分 线性表的链式存储(二)--无头结点
原创
©著作权归作者所有:来自51CTO博客作者lhq_vip的原创作品,请联系作者获取转载授权,否则将追究法律责任
(二)不带头结点的单链表
与带头结点的单链表相比,不带头结点的单链表比较直观,但在插入和删除第一个元素时于插入和删除其他元素的操作不同。而带结点的单链表其操作都是统一的。
不带头结点的单链表基本操作:
/*初始化*/
/*重置为空表*/
/*判断是否为空表*/
/*返回数据元素的个数*/
/*当第i个元素存在时,赋值给e,并返回OK,否则返回ERROR*/
/*返回链表中第一个与e满足compare关系的数据元素的为序*/
/*在不带头结点的单链表中第i个位置之前插入元素e*/
/*在不带头借点的单链表中删除第i个元素*/
/*一次对表中的每一个元素调用函数visit*/
/*若cur_e是链表中的元素,且不是第一个,用pre_e返回它的前驱,成功返回OK,失败返回false*/
/*若cru_e是链表中的元素,且不是最后一个,用next_e返回它的后继,成功返回OK,失败返回false*/
/程序前边定义的结构、数据类型与(一)中相同
/*初始化*/ void InitList(pLinkList L) { L = NULL; }
/*重置为空表*/ void ClearList(pLinkList L) { pLinkList p; while(p) { p = L; L = p->next; free(p); } }
/*判断是否为空表*/ Status ListEmpty(pLinkList L) { if(L) return FALSE; else return TRUE; }
/*返回数据元素的个数*/ int ListLength(pLinkList L) { int i = 0; pLinkList p = L; while(p) { i++; p = p->next; } return i; }
/*当第i个元素存在时,赋值给e,并返回OK,否则返回ERROR*/ Status GetElem(pLinkList L,int i,elemtype *e) { int j = 1; pLinkList p; while(j<i && p) { p = p->next; j++; } if(i == j && p) { *e = p->data; return OK; } return ERROR; }
/*返回链表中第一个与e满足compare关系的数据元素的为序*/ int LocateElem(pLinkList L,elemtype e,Status(*compare)(elemtype,elemtype)) { // 对比:
int i = 1; // int i =0;
pLinkList p = L; // pLinkList p =L;
while(p && !compare(p->data,e)) // while(p)
{ // { i++;
i++; // if(compare(p->next,e))
p = p->next; // return i;
} // p = p->next;
if(p) // }
return i; // return 0;
return 0; }
/*在不带头结点的单链表中第i个位置之前插入元素e*/ //一下是《数据结构算法解析》高一凡著,清华出版 31页原程序
//发现错误没?
Status ListInsert(pLinkList L,int i,elemtype e) { int j = 1; pLinkList s,p=L; if(i<1) return ERROR; s = (pLinkList)malloc(sizeof(LinkList)); s->data = e; if(i == 1)//i=1时特殊处理。
{ s->next = L; L = s; } else { while(p&&j<i-1) //寻找第i-1个结点
{ j++; p = p->next; } if(!p) return ERROR; s->next = p->next; p->next = s; } return OK; } /*逻辑没问题,问题出在我们新手使用指针都很容易忽视的问题,就是存在内存泄漏的隐患! 看来编书人也忽视了,当i大于表长加1时,直接return返回函数了,别忘了我们的指针s已经指向了一块分配过大小的内存上, 函数结束s的生命周期结束了,但是那块分配过的内存却与世长辞了。 解决办法很简单,在执行return ERROR;之前先执行free(s)就可以了,或者干脆在真要插入结点了之前建立新节点。*/
/*在不带头借点的单链表中删除第i个元素,并把数据返回到e中*/ Status ListDelete(pLinkList L,int i,elemtype * e) { int j = 1; pLinkList q,p = L; if(!p) return ERROR; else if (i == 1) { L = p->next; *e = p->data; free(p); } else { while(!p->next && j<i-1)//p指向要删除元素的前驱,指向第i-1个元素,且i要小于表长 { j++; p = p->next; } if(!p->next || j>i-1) // i<1 或着 i大于表长 return ERROR; q = p->next; //q指向要删除的元素 *e = q->data; p->next = q->next; free(q); } return OK;
}
/*一次对表中的每一个元素调用函数visit*/ void ListTraverse(pLinkList L,void(*visit)(elemtype *)) { pLinkList p = L; while(p) { visit(&p->data); p = p->next; } }
/*若cur_e是链表中的元素,且不是第一个,用pre_e返回它的前驱,成功返回OK,失败返回false*/ Status PriorElem(pLinkList L,elemtype cur_e,elemtype *pre_e) { pLinkList p = L; while(!p->next) { if(p->next->data == cur_e) { *pre_e = p->data; return OK; } p = p->next; } return ERROR; }
/*若cru_e是链表中的元素,且不是最后一个,用next_e返回它的后继,成功返回OK,失败返回false*/ Status NextElem(pLinkList L,elemtype cur_e,elemtype *next_e) { pLinkList p = L; while(!p->next) { if(p->data == cur_e) { *next_e = p->next->data; return OK; } p = p->next; } return ERROR; } |