数据结构之链表
数据结构——链表
在c++中,数组对应着一个连续存储的内存块,将同类型的元素一个一个地排列起来,是组织数据的很好的方法。声明数组的同时我们需要告诉编译器数组的大小,以便开辟足够大小的内存。但是,在解决实际问题时,元素的个数通常是不确定的,此时该如何声明数组呢?接下来,我将讲一下链表这个数据结构,它很好的解决了数组大小不易控制的问题。
链表元素通常称为链表结点,每个节点是一个结构体,包含数据域和指针域。指针域链接结点的下一个结点。如果将链表比作一串珠子,头结点head就是绳头,找珠子就要从头结点开始,头结点指向的结点1是链表的第一个数据结点。
提示:链表的存取 必须 从头指针开始进行,最后一个结点的指针域为空(NULL);头结点的数据域可以不包含任何信息,也可以存储诸如元素个数等附加信息,或者干脆用一个指针代替头结点,如果链表为空,头结点为空。
链表与结构数组存在很大差别
1:结构数组中的各元素是连续存放的,而链表中的结点可以不连续存放;
2:结构数组元素可以通过下标运算或相应指针变量的“移动”进行顺序或随机访问;而链表中结点不便于随机访问,只能从头结点一个一个的顺序访问。
3:结构数组在定义时就能确定其元素,不能动态增长,链表可以动态的增长。
下面是最简单的一个结构体的示例:
1 struct student 2 { 3 int score; 4 struct student*next;//指向另一个结构体的指针 5 };
从内存申请结点空间的语句为:
head=(struct student*)malloc(sizeof(student));
下面是实现一个最简单的动态单链表的源代码
1 #include <iostream> 2 #include <stdlib.h> 3 #include <string> 4 using namespace std; 5 //创建一个结构体 6 struct student 7 { 8 int score; 9 struct student*next;//指向另一个结构体的指针 10 }; 11 struct student* List_create() 12 { 13 struct student *head; 14 struct student *pnew=NULL;//创建的新结点的地址 15 struct student *tail=NULL;//原链最后一个结点的地址 16 17 head=(struct student*)malloc(sizeof(student)); 18 //良好的编程习惯,创建一个指针后转而判断该指针是否为空 19 if(head==NULL) 20 { 21 cout<<"cannot create it"; 22 } 23 24 head->next=NULL; 25 tail=head;//先将头结点尾结点设置为一点 26 27 int s; 28 29 while(1) 30 { 31 cin>>s;//输入数据 32 if(s)//当数据不为零 33 { 34 pnew=(struct student*)malloc(sizeof(student));//创建一个新结点 35 if(pnew==NULL) 36 { 37 cout<<" create error"; 38 } 39 pnew->score=s; 40 pnew->next= NULL; 41 42 tail->next=pnew;//将尾结点的指针指向新结点 43 tail=pnew;//将新结点设置为尾结点 44 } 45 else break; 46 } 47 //因为到目前为止head中并没有数据,所以我们需要先将head设置为head->next,然后释放 48 pnew=head 49 head=head->next; 50 51 free(pnew); 52 return head; 53 } 54 55 int main() 56 { 57 struct student*a=List_create(); 58 while(1) 59 { 60 if(a==NULL)break; 61 else 62 { 63 cout<<a->score<<endl; 64 a=a->next; 65 66 } 67 68 } 69 return 0; 70 }
代码分析:首先用head指针动态申请内存创建一个头结点,让头结点的指针域为NULL;而后在while结构中为实际数据申请内存创建结点,用指针pnew指向它,并将用户输入的数据放入该结点的数据域内,设置其指针为NULL,时刻保持尾结点tail指向链表尾部。最后修正head指针的位置,使其指向第一个数据结点。