赞
踩
最近在学习数据结构中的链表,可能是刚刚接触的吧,感觉有点难度,它结合了指针及结构体,所以,当你在看这篇博客时,你应该对C语言的指针及其结构体要有了解,不然的话,你会在看这篇博客时,会说,这个博主在写什么乱七八糟的东西啊,不知道怎么敢发。哈哈,我可不想听到大家对我说这样的话。鉴于此,我会将每一步讲的十分仔细的。
先来了解一下基础的知识吧。
好了,接下来实战。
#define OK 1 #define ERROR 0 #define TURE 1 #define FALSE 0 #define MAXSIZE 20 typedef int Status; //Status为函数的类型 typedef int ElemType; typedef struct Node{ ElemType data; struct Node *next; }; typedef struct Node *LinkList; //定义LinkList
在单链表中,由于第i个元素没办法一开始就知道,必须得从头开始找。因此,对于单链表实现第i个元素的数据的操作GetElem。
在读取第i个数据的算法思路:
Status GetElem(LinkList L,int i,ElemType *e){ int j=1; LinkList p //申明一个结点 p=L->next; //让p指向第一个结点 while(p&&j<i){ p=p->next; //每次循环都将指向下一个结点,直到直到第i个结点 ++j; } if(!p||j>i){ return ERROR; } *e=p->data; //用e的返回查找的数 return OK; }
上述代码的算法就是遍历每一个元素,基本上和刚开始学的数组是差不多的,然而不同的是这里是用指针的指向去遍历元素,而数组是用索引去遍历元素。
在单链表里,我们就不必像数组那样将一些数组中的元素后移或者是前移,而是,将指针的指向要插入的元素,而插入的元素指针指向它前面元素在它未插入前指向的元素即可,所以,在这一方面链表显然更为灵活。
//单链表L存在,i表示在在第i个数前面插入数为e的元素 Status ListInsert(LinkList *L,int i,ElemType e){ int j=1; ListLink p,s; p=*L; while(p&&j<i){ p=p->next; ++j; } if(!p||j>i){ return ORRER; } s=(LinkList)malloc(sizeof(Node)); //申请新的结点; s->data=e; s->next=p->next; p->next=s; return OK; }
当然,对于单链表的删除,我们现在应该有一定的意识了吧,在这里,我们可以将要删除的元素的前一元素指向其的后一位元素,简单的说就是,指针在指向下一元素时,跳过要删除的元素。在这里,是不是为链表的灵活连连叫好。
Status ListDelete(LinkList *L,int i,ElemType *e){ int j=1; LinkList p,q; p=*L; while(j<i&&p->next){ //这里判断的是p->next是因为要指向被删除元素的后一位元素,所以要判断它是否存在 p=p->next; ++j; } if(j>i||!(p->next)){ return ORRER; } q=p-next; p->next=q->next; *e=q->data; free(q); //回收此结点 return OK; }
创建单链表的过程,其实就是动态创建一个链表的过程依次建立结点,并插入元素,在这里,我介绍两个方法插入元素,一个是头插法,一个是尾插法。对于,头插法,就是将每个插入的元素放在第一个结点,然后依次类推,当然,尾插法,就是将每个要插入的元素放在最后一个结点,以此类推。
头插法:
尾插法:
//头插法 void CreateListHead(LinkList *L,int n){ LinkList p; int i; srand(time(0)); *L=(LinkList)malloc(sizeof(Node)); (*L)->next=NULL; //建立一个带头结点链表 for(i=0;i<n;i++){ p=(LinkList)malloc(sizeof(Node)); p->data=rand()%100+1; //生成100以内的数字 p->next=(*L)->next; (*L)->next=p; //插入到表头 } }
//尾插法 void CreateListTail(LinkList *L,int n){ LinkList p,r; int i; srand(time(0)); *L=(LinkList)malloc(sizeof(Node)); r=*L; for(i=0;i<n;i++){ p=(LinkList)malloc(sizeof(Node)); p->data=rand()%100+1; r->next=p; r=p; } r->next=NULL; //当前链表结束 }
想到整表的创建,那么肯定有整表的删除吧。
删除单链表是十分有用的,它可以腾出空间留给其他程序或软件的使用。
其算法思路是蛮简单的,就是一个一个的释放结点。
Status ClearList(LinkList *L){ LinkList p.q; p=(*L)->next; while(p){ q=p->next; free(p); //释放结点 p=q; } (*L)->next=NULL; return OK; }
上面我是分步给大家伪代码的,以方便大家能够理解,当然啦,接下来,我给出一些其在main()函数被调用时的用法,不过在调用其时,还要去定义一些函数,以便输出元素。
Status vis(ElemType e){ printf("%d ",e); return OK; } // 定义单链表长度的函数 int ListLength(LinkList L){ int i=0; LinkList p=L->next; while(p){ p=p->next; i++; } return i; } //定义一个将单链表中每个元素输出的函数 Status ListPrint(LinkList L){ LinkList p=L->next; while(p){ vis(p->data); p=p->next; } printf("\n"); return OK; }
int main(){ LinkList L; //申明一个单链表 ElemType e; //元素的值 Status i; //相当于int i; int k,j; for(k=1;k<=10;k++){ ListInsert(&L,1,k); } printf("插入后的链表为:"); ListPrint(L); printf("单链表的长度为:%d\n",ListLenght(L)); ClearList(&L); printf("清空后,其单链表的长度为:%d",ListLenght(L)); for(j=1;j<=10;j++){ ListInsert(&L,j,j); } printf("插入数据后,单链表为:"); ListPrint(L); printf("单链表的长度为:%d\n",ListLength(L)); GetElem(L,6,&e); printf("第6个元素为;%d\n"); ListDelete(&L,3,&e); ListPrint(L); ClearList(&L); Create(ListHead(&L,20); printf("头插法创建单链表的元素为:"); ListPrint(L); ClearList(&L); CreateListTail(&L,20); printf("尾插法创建单链表的元素为:"); ListPrint(L); return 0; }
好了,今天的博客就要在这里结束了,不过在下一个博客我还会介绍静态链表,循环链表的相关知识。不过呢,我也十分感谢CSDN上有些大牛的博客让我学会了单链表。最后,希望大家能够多多支持。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。