链表的基本操作:
遍历
空判断
查找
清空
销毁
求长度
删除结点
插入结点
算法:
狭义的算法是与数据的存储方式密切相关的
广义的算法是与数据的存储方式无关的
泛型:
利用某种达到的效果就是:不同的存储方式,执行的操作是一样的
链表定以后,每一个节点是不用定义其名字的
//链表的一系列基本操作 # include <stdio.h> # include <malloc.h> # include <stdlib.h>//exit(1); struct LinkList { int date; struct LinkList * next; }; struct LinkList * create_LinkList(); //创建链表 void traverse_LinkList (struct LinkList *); //遍历输出 bool is_empty (struct LinkList *); //判断链表是否为空 int lenth_Linklist (struct LinkList *); //求链表长度 bool insert_LinkList (struct LinkList *, int pos, int); //插入 bool delete_LinkList (struct LinkList *, int pos, int*); //删除 void sort_LinkList (struct LinkList *); //排序 int main () { int pos, val; struct LinkList * pHead = create_LinkList(); traverse_LinkList (pHead); int len = lenth_Linklist (pHead); printf ("链表长度为%d\n", len); printf("插入的位置:"); scanf("%d", &pos); printf("插入的数字:"); scanf("%d", &val); insert_LinkList (pHead, pos, val); traverse_LinkList (pHead); int depos, deval; printf("删除的位置:"); scanf("%d", &depos); delete_LinkList (pHead, depos, &deval); traverse_LinkList (pHead); printf ("删除结点的值为:%d\n", deval); return 0; } struct LinkList * create_LinkList() { int a, b, val; //创建头结点 struct LinkList * pHead = (struct LinkList *)malloc(sizeof(struct LinkList) ); if (pHead == 0) { printf ("生成失败。"); exit(1); } else pHead->date = NULL;//头结点的数据域为空 struct LinkList * pTail = pHead;//pTail,pHead都指向头结点, pTail->next = NULL; //清空头结点指针域,pTail->next和pHead->next是等价的,指针域清空了后用pTail->next = 写入新的指针域,写入后,就保存在pHead->next里面 //浪费时间的原因:最开始的时候,我一直在思考,怎么让pHead指向下一个结点,我觉得pTail->next指向的下一个节点和pHead->next似乎没啥关系 //或者说我那时想的pHead->next=pTail->next->next我还想过弄一个首指针加俩if判断,好在想通了,蛮干不如多思考 printf ("请输入你要生成链表成员的个数。"); scanf ("%d", &a); //建立链表 for (b=0;b<a;b++) { printf ("请输入链表第%d个成员的值:", b+1); scanf ("%d", &val); //新结点 struct LinkList * pNew = (struct LinkList *)malloc(sizeof(struct LinkList) ); if (pNew == 0) { printf ("生成失败。"); exit(1); } pNew->date = val; pTail->next = pNew;//头结点指针域指向pNew pTail = pNew; //不断循环后,向后赋值 } pTail->next = NULL; //放在for循环外面,给尾结点,放在里面会执行很多次,但是也是正确的 return pHead; } void traverse_LinkList (struct LinkList * pHead) { int i=1; struct LinkList * p = pHead->next; while(p != NULL)//这里是不为空,要等到循环到尾结点才为空,循环终止 { printf ("链表第%d个数为:%d\n", i, p->date); p = p->next; i++; } return; } bool is_empty (struct LinkList * pHead) { if (pHead->next == NULL) //(pHead->next->date==NULL)不行,万一首结点的数据域就是NULL。。。头结点的指针域为空,就只有一个头结点,是空链表 return true; //printf ("链表为空。"); else return false; } int lenth_Linklist (struct LinkList * pHead) { struct LinkList * p = pHead->next; int len = 0; //if ( bool is_empty(pHead) ==false)多余了,链表为空就是长度为0 while (p!=NULL) { len++; p = p->next;//这里p = p->next,p要是等于pHead->next,那么p的值会一直刷新到pHead->next,循环不会完成,一直循环,就显示不出printf ("链表长度为%d", len); } return len; } bool insert_LinkList (struct LinkList *pHead, int pos, int val) { int i=1;//i不能等于0,等于0就是从0开始遍历,即i=0 ++,要遍历到pos上去 //判断链表是否为空,不需要这个步骤,为空就在头指针后面插一个 struct LinkList *p = pHead; struct LinkList *t; while (p->next&& i<pos)//遍历寻找第pos-1个结点,p->next和p是一个效果,我也不知道为什么,想不通。我曹,他是&&循环才截止,达到一个过后还要达到另一个,都会遍历到p->next==NULL才完,所以两个是一样的。 { p=p->next; i++; } printf ("i=%d\n",i); if (p == NULL || i>pos)//判断插入的位置在不在链表内,此处是p不是p->next,若是p->next则尾插的时候指向了最后一个的最后一个必然不存在的,尾插插不了 { printf ("链表没有第%d个结点\n", pos); return false; } struct LinkList * pNew = (struct LinkList *)malloc(sizeof(struct LinkList));//创建结点 pNew->date = val; t=p->next; p->next = pNew; pNew->next=t;//插入:t=p->next,p->next = pNew->next,pNew->next=t; return true; } bool delete_LinkList (struct LinkList * pHead, int pos, int * val) { int i=1; struct LinkList *p = pHead; struct LinkList *q; while (p && i < pos )//是while (p==NULL && i < pos )这里错了,后面那个//p=p->next->next ;也是错的,为什么? { p=p->next ; i++; } if (p == NULL || i>pos) { printf ("链表没有第%d个结点\n", pos); return false; } //p=p->next->next ; q=p->next;//p->next被删除元素的 p->next=q->next; *val = q->date; free(q); return true; }
排序有点难啊,不太搞得懂,看是今天晚上还是明天来排。
嗯,首行缩进三个字符都是异端,就是这样