链表和数组两者的区别: 数组是一块连续的存储空间,长度固定。链表的存储空间是可以不连续的,并且其长度不固定(动态),每个结点需保留邻结点指针;数据查找方面,数组只需根据其序号就能直接找到,而链表需要顺序检索查找,效率是较低的;对于数据插入或删除问题,链表是更方便的,而数组则需要进行较大的数据移动操作。
链表拥有基本的就是结点,现定义如下结点结构:
typedef struct node
{
type data;
struct node *next;
}Node,*pNode;
结点中包含结点数据和指向下一结点的指针。
(1)创建一个单链表并输出
这里面涉及较多的就是malloc函数,为结点申请内存。注意和C++中的new()进行区别。
//创建一个单链表
pNode CreateList(type *val,int n)
{
int i;
pNode head=(pNode)malloc(sizeof(Node));
if(NULL==head)
{
printf("申请头结点内存失败!");
exit(-1);
}
head->data=-1;
head->next=NULL;
pNode p=head;
for(i=0;i<n;i++)
{
pNode newnode=(pNode)malloc(sizeof(Node));
if(NULL==newnode)
{
printf("申请新结点内存失败!");
exit(-1);
}
newnode->data=val[i];
newnode->next=NULL;
p->next=newnode;
p=newnode;
}
return head;
}
//打印单链表
void Printlist(pNode head)
{
pNode temp=NULL;
if(NULL==head)
{
printf("链表为空!");
exit(-1);
}
temp=head->next;
while(temp!=NULL)
{
printf("%d ",temp->data);
temp=temp->next;
}
printf("\n");
}
例子:创建 type a[6]={1,2,3,4,5,6}; 则结果为
在打印函数中,写成如下形式if(NULL==head),是为了防止出错。如果写为(head=NULL),编译器编译时将不会报错,运行会出错;反过来写为(NULL=head),会报错。
(2)逆转
//反转链表
pNode reverse(pNode head)
{
pNode pre=NULL,next,cur=head->next;
while(cur!=NULL)
{
next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
head->next=pre;
return head;
}
运行结果:
(3)查找链表中间结点
思想是应用快慢指针的思想,都从头结点出发,快指针一次移动2步,慢指针一次移动一步,当快指针移动至链表尾部时,慢指针刚好到达链表中间。
//寻找单链表中间借点 快慢指针
pNode FindMiddle(pNode head)
{
pNode fast,slow,temp;
if(NULL==head)
{
return NULL;
}
fast=slow=head;
while(NULL!=fast->next)
{
slow=slow->next; //慢指针走一步
fast=fast->next->next; //快指针走2步
}
return slow;
}
结果: