数据结构之动态单链表代码实现
2015-10-08 17:31
148 查看
链式存储结构:哪里有空位就放在哪里,只是让每个元素知道他下一个元素的位置在哪里
特点:用一组人的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。通过存储后继元素的存储地址来实现
存储数据元素信息的域称为数据域,把存储直接后继文职的域称为指针域。指针域中的存储的信息称作指针或链,这两部分信息组成数据元素的存储映像,称为结点(Node)
头指针:链表中第一个结点的存储位置
头指针与头结点的异同点:
头指针:头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;头指针具有编址作用,所以常用头指针冠以链表的名字; 无论链表是否为空,头指针均不为空。头指针是链表的必要元素
头结点:头结点是为了操作的统一和方便而设立你的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度);有了头肩点。对在第一元素节点前插入结点和删除第一结点,其操作与其他家电的操作就统一了;头结点不一定是链表的必要元素
单链表结构与顺序存储结构优缺点:
存储分配方式:顺序存储结构用一段连续的存储单元依次存储线性表的数据元素
单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素
时间性能:查找——顺序结构O(1),单链表 O(n)
插入和删除 ——顺序存储结构需要平均移动表长一半的元素,时间为O(n);单链表 O(1)
空间性能——顺序存储结构 需要预分配存储空间,分大了,浪费,分小了容易发生上溢;单链表不需要分配存储空间,只要有就可以分配,元素个数不受限制
线性表用于频繁的查找,很少进行插入和删除操作;知道元素个数有多大时
单链表用于频繁的插入和删除;不知道多大或者变化较大时
特点:用一组人的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。通过存储后继元素的存储地址来实现
存储数据元素信息的域称为数据域,把存储直接后继文职的域称为指针域。指针域中的存储的信息称作指针或链,这两部分信息组成数据元素的存储映像,称为结点(Node)
头指针:链表中第一个结点的存储位置
头指针与头结点的异同点:
头指针:头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;头指针具有编址作用,所以常用头指针冠以链表的名字; 无论链表是否为空,头指针均不为空。头指针是链表的必要元素
头结点:头结点是为了操作的统一和方便而设立你的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度);有了头肩点。对在第一元素节点前插入结点和删除第一结点,其操作与其他家电的操作就统一了;头结点不一定是链表的必要元素
单链表结构与顺序存储结构优缺点:
存储分配方式:顺序存储结构用一段连续的存储单元依次存储线性表的数据元素
单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素
时间性能:查找——顺序结构O(1),单链表 O(n)
插入和删除 ——顺序存储结构需要平均移动表长一半的元素,时间为O(n);单链表 O(1)
空间性能——顺序存储结构 需要预分配存储空间,分大了,浪费,分小了容易发生上溢;单链表不需要分配存储空间,只要有就可以分配,元素个数不受限制
线性表用于频繁的查找,很少进行插入和删除操作;知道元素个数有多大时
单链表用于频繁的插入和删除;不知道多大或者变化较大时
#include<stdio.h> #include<string.h> #include<malloc.h>//动态分配函数所要用到的宏 typedef struct studentList//typedef的作用是为了用student来声明结构体(struct是声明结构体,自己可以看看书) { char name[20];//学生名字 int age;//学生年龄 struct studentList *next;//用于指向下一结点 }student;//student可以自己定义为其他名称,但是以后声明结构体的时候得用你定义的那个名称 student *create()//student开始起作用了,用它来声明一个结构体函数 { student *head,*previous,*current;//声明三个指向结构体的指针,head为指向头指针,previous为上一指针,current是指向现在结构体的指针,链表的重要思想就是用指针把不是连续的空间串起来 head=NULL; puts("let us create a student's list,please input first student's name:"); while(1) { current=(student *)malloc(sizeof(student));//分配空间 if(head==NULL)//第一次分配 { previous=current; head=current;l//头指针指向头结点 } else previous->next=current;//上一结点的指针指向新分配的空间地址 current->next=NULL;//把新分配的空间指针设为NULL,表示目前的末结点 scanf("%s",current->name);//给新空间的名字赋值 puts("please input the student's age(0 to quit):"); scanf("%d",¤t->age);//年龄赋值 if(current->age==0)//如果年龄为0 ,表示退出 break; puts("please input the next student's name:"); previous=current;//又循环 分配空间 } current->next=NULL; return head; //返回链表的起始位置 } student *print(student *head)//打印链表 { student *current; current=head; puts("Now the list is followed:"); puts("name age"); while(current->next!=NULL)//判断是否是末节点 { printf("%-20s%d\n",current->name,current->age); current=current->next;//指针后移一位 } printf("%-20s%d\n",current->name,current->age); return head; } student *add(student *head,student *end)//在末尾添加新结构 { student *current; current=head; while(current->next!=NULL)//循环至末结点 current=current->next; current->next=end;//添加 end->next=NULL;//把新添加进来的指针域设置为NULL return head; } student *dele(student *head,int n)//删除年龄第一个为n的student结构体 { student *previous,*current; current=head; while(current->next!=NULL&¤t->age!=n)//没有循环至末结点 并年龄不为n,就一直往下移动 { previous=current; current=current->next; } if(current->age==n)//判断是否是年龄为n(有可能是循环至末结点) { if(current==head)//判断是否是第一个结点,因为第一个结点和中间结点的处理方式不同 head=current->next;//head直接指向第二结点 else previous->next=current->next; //否则当前结点的指针域指向下结点的指针域(也就是下下结点开始位置) } else puts("not exit"); return head; } int main(void) { student *head,*end; int n; head=create(); print(head); end=(student *)malloc(sizeof(student)); puts("let us add a student's information,please input name and age."); printf("name:"); scanf("%s",end->name); printf("age:"); scanf("%d",&end->age); add(head,end); print(head); puts("please input the age of student you want to delete:"); scanf("%d",&n); dele(head,n); print(head); return 0; }