头结点: 头结点是为了操作的统一、方便而设立的,放在第一元素结点之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等),有头结点后,对在第一元素结点前插入结点和删除第一结点,其操作与对其它结点的操作统一了。而且无论链表是否为空,头指针均不为空。
头指针: 头指针指向链表的第一个节点,若链表有头结点则指向链表的头结点,头指针具有标识作用,故对头指针常冠以链表的名字。
首元结点也就是第一元素结点,它是头结点后边的第一个结点。
链表的创建和逆序:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
typedef struct List{
int data;
struct List *next;
}List;
//顺序创建链表,有头结点和头指针。
List *list_create(void)
{
struct List *head,*tail,*p;
int e;
head=(List *)malloc(sizeof(List));
tail=head;
printf("/nList Create,input numbers(end of 0):");
scanf("%d",&e);
while(e){
p=(List *)malloc(sizeof(List));
p->data=e;
tail->next=p;
tail=p;
scanf("%d",&e);}
tail->next=NULL;
return head;
}
//使链表逆序,需有头指针。如果有头结点,会把头结点也逆序了。
List *list_reverse(List *head)
{
List *p,*q,*r;
if(head != NULL)
{
p=head;
q=p->next;
}
while(q!=NULL)
{
r=q->next;
q->next=p;
p=q;
q=r;
}
head->next=NULL;
head=p;
return head;
}
void main(void)
{
struct List *head,*p;
int d;
head=list_create();
printf("/n");
for(p=head->next;p;p=p->next)
printf("--%d--",p->data);
head=list_reverse(head);
printf("/n");
for(p=head;p->next;p=p->next)
printf("--%d--",p->data);
}
转置的其他方法: 1. 堆栈
2. 数组
这两种方法时间和空间效率都不高。
3. 递归算法(无头结点):
#include <stdio.h>
#include <malloc.h>
#define Malloc(x) (x *)malloc(sizeof(x));
typedef struct Lt {
char a;
struct Lt *next;
}List;
List* rev( List * head )
{
List *rHead;
if( !head )
{
return head;
}
else if( !head->next ) //只有一个结点
{
return head;
}
else
{
rHead = rev( head->next );
head->next->next = head;
head->next = NULL;
return rHead;
}
}
void output(List *h){
for(;h;h=h->next)
printf("%c ",h->a);
printf("/n");
}
int main()
{
List *h,*p;
int i;
h=Malloc(List);
p=h;
p->a='a';p->next=0;
for(i=0;i<5;i++){
p->next=Malloc(List);
p=p->next;
p->a='b'+i;p->next=0;
}
output(h);
h = rev(h);
output(h);
return 0;
}