尾插法创建单链表
void CreatByRear(Node *head) //尾插法创建单链表;
{
Node *last,*pnew;
char name[20];
int number;
last = head;//last指向头结点;
printf("请输入学生的学号和姓名:\n");
while(1)
{
scanf("%d",&number);
if(number==0)
break;
scanf("%s",name);
pnew=(Node *)malloc(sizeof(Node));//分配每一个新结点的内存空间;
strcpy(pnew->name,name);
pnew->number=number;
last->next=pnew;//原来的结点指向新的结点,让上一个结构体中的next存放下一个结构体的首地址;
last=pnew;//(*last).next,让last存放最后一个结构体的地址,方便下一次循环时使用这个结构体的 next;
}
last->next=NULL;//链表的尾结点指针指向空,也就是结束循环后,让最后一个结构体中的 next指向空;
}
头插法创建单链表
void CreatByHead(Node *head) //头插法创建单链表;
{
Node *pnew;
char name[20];
int number;
printf("请输入学生的学号和姓名:\n");
while(1)
{
scanf("%d",&number);
if(number==0)
break;
scanf("%s",name);
pnew=(Node *)malloc(sizeof(Node));
strcpy(pnew->name,name);
pnew->number=number;
pnew->next=head->next;
head->next=pnew;
}
}
单链表的插入
插入一个结点,就是让插入链表的结点的指针域内存储下一个结点的地址(或者NULL),让上一个结点的指针域内存储所插入链表的结点的地址。
在表中添加结点
设计一个函数,在单链表的第i个位置上插入新结点,如下所示。
- 首先从链表的头结点开始,找到链表的第i-1个结点的地址p。
- 如果该结点存在,则可以在第i-1个结点后面插入第i个结点。为插入的新结点分配内存,然后向新结点输入数据。
- 插入时,首先将新结点的指针s指向原来第i个结点(s->next = p->next),然后将第i-1个结点指向新结点(p->next = s)。
i 的大小从首元结点开始计数,首元结点也就是第一元素结点,它是头结点后边的第一个结点。
void Insert(Node* head,int i)
{
Node *p=head,*s; //定义指针p,指向head;
int j=0;
while(j<i-1 && p) //j-1;
{
p=p->next;
j++;
}
if(p)
{
printf("请输入待添加学生的学号和姓名:\n");
s=(Node *)malloc(sizeof(Node)); //定义s指向新分配的空间;
scanf("%d",&s->number);
scanf("%s",s->name);
s->next=p->next; //新节点指向原来的第i个节点;
p->next=s; //新节点成为新链表的第i个节点;
}
}
在表首位置后添加结点
- 首先为插入的新结点分配内存,然后向新结点输入数据。
- 插入时,首先将新结点的指针指向链表的首元结点(s->next = head->next),然后将头节点的指针指向新结点(head->next = s)。
void InsertHead(Node *head)
{
Node *s;
printf("请输入待添加学生的学号和姓名:\n");
s = (Node *)malloc(sizeof(Node)); //定义s指向新分配的空间。
scanf("%d",&s->number);
scanf("%s",s->name);
s->next = head->next; //新结点的指针指向首元结点;
head->next = s; //头结点的指针指向新结点;
}
在链表最后添加结点
- 首先找到尾结点。
- 插入时,为插入的新结点分配内存,再向新结点输入数据,将尾结点的指针指向要插入的新结点(p->next = s),新结点则指向空指针(s->next = NULL)。
void InsertHead(Node *head)
{
Node *p=head,*s;
while(p && p->next) //找到链表最后一个结点的地址;
p=p->next;
if(p)
{
printf("请输入学生的学号和姓名:\n");
s = (Node *)malloc(sizeof(Node)); //定义s指向新分配的空间;
scanf("%d",&s->number);
scanf("%s",s->name);
p->next = s; //尾结点的指针指向新结点;
s->next = NULL; //新结点的指针指向NULL;
}
}
单链表的删除
- 声明一个Delete函数,函数中有两个参数,其中head表示链表的头指针,pos表示要删除结点在链表中的位置。定义整形变量j来控制循环次数,然后定义指针变量 p 表示该结点之前的结点。
- 接着用循环找到要删除结点的前一个结点 p。
- 如果该结点存在并且待删除结点存在,则将指针变量 q 指向待删除结点(q=p->next)。
- 再连接要删除结点两边的结点(p->next=q->next)。
- 并使用free函数将q指向的内存空间进行释放(free(q))。
void Delete(Node *head,int pos)
{
Node *p=head,*q;
int j=0;
printf("\n**********删除第%d个学生**********\n",pos);
while(j<pos-1 && p) //通过循环,找到第pos-1个结点的地址p;
{
p=p->next;
j++;
}
if(p==NULL || p->next==NULL) //第pos个结点不存在;
printf("the pos is ERROR!");
else
{
q=p->next; //q指向第pos个结点;
p->next=q->next;//连接被删除结点两边的结点;
free(q); //释放要删除结点的内存空间;
}
}
在main函数中添加代码 Delete(head,pos); //删除链表的第pos个元素。
单链表的查询
- 声明一个search函数,函数中有两个参数,其中head表示链表的头指针,name表示要查找的值。定义指针变量p,使其从首元结点开始到链表结束。
- 如果某结点的成员值和给定值不等,则继续查找下一个结点(p=p->next)。
- 如果查找成功,则返回结点的地址值。
- 如果查找失败,则打印提示信息,并返回NULL。
Node *search(Node *head,char name[]) //在单链表head中找到与name所存相同字符串的结点;
{
Node *p=head->next;
while(p)
{
if(strcmp(p->name,name)!=0)
p=p->next;
else
break; //查找成功;
}
if(p==NULL)
printf("没有找到值为%s的结点!",name);
return p;
}
此外,main函数中可以添加函数代码为如下所示:
void main()
{
Node* head; //定义单链表头指针;
Node* p; //定义指针变量;
head = initlist(); //初始化单链表;
CreatByRear(head); //尾插法创建单链表;
OutPut(head); //输出单链表;
printf("\n**********请输入查找学生的姓名**********\n") ;
char name[10000];
scanf("%s",name); //输入所要查找的东西;
p=search(head,name); //查找"name"的结点,并将其地址赋给指针变量p;
printf("\n**********查找到的信息如下**********\n");
printf("学号:%d\n\n",p->number); //输出学号;
printf("姓名:%s\n",p->name); //输出姓名;
}
单链表的长度
- 单链表的长度是隐形表示的,当从首元结点开始,一次遍历链表的所有结点,并同时统计结点个数。
- 最后返回结点个数值 。
int ListLength(LinkList head)
{
int count=0;
Node *p;
p=head->next; //指针变量p指向链表的首元结点;
while(p) //结点存在,表示链表没有遍历结束;
{
count++;
p=p->next; //指向当前结点的下一个结点;
}
return count;
}
main函数中需添加代码如下所示:
int length;
length = ListLength(head);
printf("\n共有%d条学生信息\n",length);
不带头结点的单链表
1.不带头结点单链表的插入
链表的插入操作如果在链表的首位置
首先为插入的新结点分配内存,然后将新结点的指针s指向原来首结点(s->next=head),最后将头指针指向新结点(head=s),这样就完成了插入结点的操作,很显然,这种情况下,头指针发生了改变,所以需要返回新的头指针。
链表的插入操作如果插入位置不是首位置,则与有头结点的链表插入操作相同。
2.不带头结点单链表的删除
删除的结点如果是链表的首结点
定义指针变量q指向待删除结点(q=head),再让头指针指向第二个结点(head=head->next)成为新的首结点,最后释放原来的首结点(free(q)),则这样就完成了删除首结点的操作。很显然,这种情况下头指针发生了改变,所以需要返回新的头指针。
删除的结点如果不是链表的首结点,则与有头结点的链表删除操作相同。
反转链表
迭代
有头结点
node *fanzhuan(node *head)
{
if(head==NULL || head->next==NULL)
{
return head;
}
node *beg,*mid,*end;
beg=NULL;
mid=head->next; //无头结点,mid=head;
end=head->next->next; //无头结点,end=head->next;
while(1)
{
mid->next=beg;
if(end==NULL)
{
break;
}
beg=mid;
mid=end;
end=end->next;
}
head->next = mid; //无头结点,head=mid;
return head;
}
头插法
所谓头插法,是指在原有链表的基础上,依次将位于链表头部的节点摘下,然后采用从头部插入的方式生成一个新链表,则此链表即为原链表的反转版。
创造新表
无头结点
node *fanzhuan(node *head)
{
if (head == NULL || head->next == NULL)
{
return head;
}
node *temp=NULL;
node *newhead=NULL;
while(head!=NULL)
{
temp=head;
head=head->next;
temp->next=newhead;
newhead=temp;
}
return newhead;
}
有头结点
node *fanzhuan(node *head)
{
if (head == NULL || head->next == NULL)
{
return head;
}
node *temp=NULL;
node *newhead=(node *)malloc(sizeof(node)); //有头结点,所有创造头结点;
newhead->next=NULL;
head=head->next; //先删掉原链表的头结点,让后来可以直接取第一个结点;
while(head!=NULL)
{
temp=head; //存Temp;
head=head->next; //删除存过的一个结点;
temp->next=newhead->next;//头插法,从新链表的头结点后开始连接结点;
newhead->next=temp;
}
return newhead;
}