数据结构与算法分析——带有头结点的单链表的实现(C语言)

来源:互联网 发布:广告背景音乐制作软件 编辑:程序博客网 时间:2024/05/17 06:50

数据结构与算法分析——带有头结点的单链表的实现


第一次学习《数据结构与算法分析》时,是在大一的寒假里,当时刚把C语言基础学完,看的我头都大了,什么大O记法,完全不懂,强逼着自己看到了队列,然后大一下学期经学长推荐看了·《啊哈算法》,这本书真的不错,对一些经典的算法和简单的数据结构都能通俗易懂的讲解出来,之后就一直在刷ACM题,学习了一些基础算法和数据结构,大二一开学,感觉一个暑假学的东西虽然挺多但都没有深入的去学习,只是靠着模板写水的模板题,另外感觉把大把的时间用在刷ACM上而忽略了这些基础学科的学习有点本末倒置的感觉,一些典型数据结构如果不能自己完完整整的写出来,在ACM这条路上也走不远,所以又拿出来了这本书(学校里也开了数据结构课,但对那本用类C语言写的代码实在看不下去),打算把这本书上的所有代码都自己实现一遍。

想想第一次接触链表到现在也有七八个月了,这还是第一次玩完整的是实现,好了,废话不多说了

表——一种简单的数据结构,有两种实现方式,数组和链表,各有各的优点,用数组来写优点是查找一个元素花费O(1)的时间,缺点是事先并不知道元素个数需要预估的大一些,可能浪费空间,另外删除和插入花费O(N)的时间,用链表写的缺点是查找一个元素需要从头开始查找花费O(N)的时间,优点是采用了不连续存储,插入和删除都避免了线性开销,也不用预估元素个数了,因为在使用表这种数据结构时,会用到大量的插入与删除操作,所以表这种数据结构一般采用链表来实现

链表,每一个结点含有表元素和指向下一个结点的指针,主要操作有查找,插入,删除,大致有两种写法,一种是不带头结点的链表,另一种是带头结点的链表,使用头结点还是有好处的,在插入和删除时避免了对第一个结点的特判,在这里我采用了头结点

我是根据这本书上的函数写的,初次接触链表比较难理解的就是插入和删除这两个操作了,其实在纸上画出来是一个比较好的理解方法,其余的操作都挺简单的,短小精悍。

在单链表实现的基础上又有双向链表和循环链表的扩展,可以避免单链表每次都要从头结点开始查找的缺点,还有一些应用用到了链表,比如多项式、基数排序。

在ACM中,做的题用到链表的不多

代码细节还是挺多的,一次就写成功挺不容易的


/*实现一个带有头结点的单链表,*/#pragma warning(disable:4996);#include<stdio.h>#include<stdlib.h>struct Node;typedef int ElementType;typedef struct Node *PtrToNode;typedef PtrToNode List;typedef PtrToNode Position;struct Node {ElementType Element;Position Next;};List MakeEmpty(List L); //生成一个空链表int IsEmpty(List L);//判断是否为空链表int IsLast(Position P, List L);//判断是否为最后一个节点int Length(List L);//返回链表的长度Position Find(ElementType X, List L);//查找含有元素X的结点void Delete(ElementType X, List L);//删除含有元素X的节点Position FindPrevious(ElementType X, List L);//查找含有元素X结点的前驱元void Insert(ElementType X, List L, Position P);//在P位置之后插入一个结点void DeleteList(List L);//删除链表Position Header(List L);//返回头结点Position First(List L);//返回第一个节点Position Advance(Position P);//返回该节点的后继元ElementType Retrieve(Position P);//返回该节点的元素void Print(List L);//打印链表List MakeEmpty(List L) {if (L != NULL) {DeleteList(L);}L = (List)malloc(sizeof(Node));if (L == NULL) {printf("out of space\n");exit(1);}L->Next = NULL;return L;}int IsEmpty(List L) {return L->Next == NULL;}int IsLast(Position P, List L) {return P->Next == NULL;}Position Find(ElementType X, List L) {Position P;P = L->Next;while (P != NULL && P->Element != X) {P = P->Next;}return P;}Position FindPrevious(ElementType X, List L) {Position P;P = L;while (P->Next != NULL && P->Next->Element != X) {P = P->Next;}return P;}void Delete(ElementType X, List L) {Position P, TmpCell;P = FindPrevious(X, L);if (!IsLast(P, L)) {TmpCell = P->Next;P->Next = TmpCell->Next;free(TmpCell);}else {printf("Not Found the Element %d\n",X);}}void Insert(ElementType X, List L, Position P) {Position TmpCell;TmpCell = (Position)malloc(sizeof(Node));if (TmpCell == NULL) {printf("Out of space!\n");}TmpCell->Element = X;TmpCell->Next = P->Next;P->Next = TmpCell;}void DeleteList(List L) {Position P, tmp;P = L->Next;L->Next = NULL;while (P != NULL) {tmp = P->Next;free(P);P = tmp;}}void Print(List L) {Position P = L->Next;printf("输出链表所有元素: ");while (P != NULL) {printf("%d ", P->Element);P = P->Next;}printf("\n");}int Length(List L) {int Len;Len = 0;Position P = L->Next;while (P != NULL) {Len++;P = P->Next;}return Len;}Position Header(List L) {return L;}Position First(List L) {return L->Next;}Position Advance(Position P) {return P->Next;}ElementType Retrieve(Position P) {return P->Element;}int main(void) {List L = NULL;L = MakeEmpty(L);printf("已经创建了一个空表\n");if (IsEmpty(L)) {printf("该表是一个空表\n");}Position P;P = L;for (int i = 1; i <= 5; i++) {Insert(i, L, P);P = Advance(P);}printf("链表中共有 %d 个元素\n", Length(L));Print(L);printf("执行删除0-3的操作\n");for (int i = 0; i <= 3; i++) {Delete(i, L);}printf("链表中共有 %d 个元素\n", Length(L));Print(L);for (int i = 4; i <= 5; i++) {printf("%d \n", Retrieve(Find(i, L)));if (IsLast(Find(i, L), L)) {printf("%d是最后一个元素\n",i);}else {printf("%d不是最后一个元素\n",i);}}DeleteList(L);if (IsEmpty(L)) {printf("该链表为空表\n");}getchar();getchar();return 0;}
代码验证



原创粉丝点击