在C语言基础里,链表无疑是较为困难的一部分。但是作为具有逻辑性的东西,我们争取将复杂的问题具象化,便能使其迎刃而解。
考虑到问题的复杂性和个人能力,以下只介绍单向链表。
目录
1·创建链表
创建链表需先明确链表的结构:链表由多个数据项组成,每个数据项包括基本数据部分和指针部分;首个数据项由单独定义项指向链头。
随后我们创建链表只需在链头或链尾加入数据项即可。
而作为动态数据结构,我们需要引入动态变量。此时使用malloc函数。
#include<stdio.h>
#include<malloc.h>
struct cell {
int x;
struct cell* next;
};//单链表节点结构体定义
struct cell* build(void) {
struct cell* head, * tmp, * p;//定义三个数据项,head为链头,tmp待定,p为后续项
head = tmp = p = NULL;
int n;
head = (struct cell*)malloc(sizeof(struct cell));
scanf("%d", &head->x);
tmp = head;
tmp->next = NULL;//用tmp替代head;
if (head->x == 0)head = NULL;
else {
do {
p = (struct cell*)malloc(sizeof(struct cell));
scanf("%d", &p->x);
tmp->next = p;//相当于head->next=p
tmp = p;
tmp->next = NULL;//相当于p->next=NULL,此时p已经插入该链表
} while (p->x != 0);
}
return head;//建好的链表首节点地址返回
}
接下来我们来看完整例题:
创建单链表
根据从键盘随机输入以0结束的若干非零整数,建立一个单链表;之后将此链表中保存的数字顺次输出,相邻数字间以一个西文空格间隔,最后一个数字后无任何字符;若是空链表,则输出NULL。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<malloc.h>
struct cell {
int x;
struct cell* next;
};//单链表节点结构体定义
struct cell* build(void) {
struct cell* head, * tmp, * p;//定义三个数据项,head为链头,tmp待定,p为后续项
head = tmp = p = NULL;
int n;
head = (struct cell*)malloc(sizeof(struct cell));
scanf("%d", &head->x);
tmp = head;
tmp->next = NULL;//用tmp替代head;
if (head->x == 0)head = NULL;
else {
do {
p = (struct cell*)malloc(sizeof(struct cell));
scanf("%d", &p->x);
tmp->next = p;//相当于head->next=p
tmp = p;
tmp->next = NULL;//相当于p->next=NULL,此时p已经插入该链表
} while (p->x != 0);
}
return head;//建好的链表首节点地址返回
}
void print(struct cell* head) {
struct cell* p;
printf("%d", head->x);
p = head->next;
while (p->x != 0) {
printf(" %d", p->x);
p = p->next;//只要该项的数据不为零,该项的指针部分就指向下一项的数据部分,以链表结构形式进行
}//打印整个单链表
}
void release(struct cell* head) {
struct cell* p;
while (head != NULL) {
p = head;
head = p->next;
free(p);
}
}//释放单链表空间
int main(void) {
struct cell* head;
head = build();
if (head != NULL)
print(head);
else
printf("NULL");
release(head);
}
2·遍历链表
遍历链表是指从头到尾将链表的数据全部加工一遍
p=top;
while(p!=NULL){
加工p->
p=p->next;
}
在遍历链表时,经常在加工一项数据后,当连指针前移时,另外取一个指针保留其前驱项的位置,以备后续加工使用。
p0=NULL;
p=top;
while(p!=NULL){
加工p->
p0=p;
p=p->next;
}
3·在链表上检索
检索是指在单向链表上查找关键字等于某定值给定的节点,若找到则带回相应节点的指针,否则带回NULL。
设关键字域的域名为key;欲检索的关键字值为key0,则:
p0=NULL;
p=top;
while(p!=NULL&&p->key!=key0){
p0=p;
p=p->next;
}
下面来看完整的例题来理解遍历和检索:
题目名称:求单链表中间结点
题目描述:首先根据键盘随机输入,以0结束的若干非零整数建立单链表;
然后寻找处于链表中间位置的结点,若中间结点有两个,则设定前一个为中间位置结点;
最后将从中间结点开始到链表尾各结点值输出,相邻数字间以一个西文空格间隔,最后一个数字后无任何字符。
若是空链表,则输出NULL。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<malloc.h>
struct cell {
int x;
struct cell* next;
};
struct cell* build(void) {
struct cell* head, * tmp, * p;
head = tmp = p = NULL;
int n;
head = (struct cell*)malloc(sizeof(struct cell));
scanf("%d", &head->x);
tmp = head;
tmp->next = NULL;
if (head->x == 0)head = NULL;
else {
do {
p = (struct cell*)malloc(sizeof(struct cell));
scanf("%d", &p->x);
tmp->next = p;
tmp = p;
tmp->next=NULL;
} while (p->x != 0);
}
return head;
}//创建单链表,首节点地址返回
struct cell* mid(struct cell* head) {
struct cell* p0, * p;
int n = 0, i, j = 0;
if (head == NULL)head = NULL;
else {
p = head;
while (p != NULL) {
p = p->next;
n = n + 1;//遍历整个单链表
}
j = n / 2;
p0 = head;
while (j != 1) {
p0 = p0->next;
j--;
}
head = p0;//找到中间节点并返回 head是单链表首节点指针
}
return head;//就是返回中间节点
}
void print(struct cell* head) {
struct cell* p;
printf("%d", head->x);
p = head->next;
while (p->x != 0) {
printf(" %d", p->x);
p = p->next;
}
}
void release(struct cell* head) {
struct cell* p;
while (head != NULL) {
p = head;
head = p->next;
free(p);
}
}
int main(void) {
struct cell* head, * half;
head = build();
half = mid(head);
if (half != NULL)
print(half);
else
printf("NULL");
release(head);
}
题目名称:单链表倒数第K个结点
题目描述: 首先根据键盘随机输入,以0结束的若干非零整数建立单链表;
然后根据输入的整数K,输出链表倒数第K个结点的值,相邻数字间以一个西文空格间隔,最后一个数字后无任何字符;
若不存在则输出NULL。
#include<stdio.h>
#include<malloc.h>
struct cell{
int x;
struct cell*next;
};
struct cell*build(void){
struct cell*head,*tmp,*p;
head=tmp=p=NULL;
int n;
head=(struct cell*)malloc(sizeof(struct cell));
scanf("%d",&head->x);
tmp=head;
tmp->next=NULL;
if(head->x==0)head=NULL;
do{
p=(struct cell*)malloc(sizeof(struct cell));
scanf("%d",&p->x);
if(p->x==0)break;
tmp->next=p;
tmp=p;
}while(p->x!=0);
tmp->next=NULL;
return head;
}
struct cell*back(struct cell*head,int k){
struct cell*p,*p0;
int n=1,i;
if(head==NULL)head=NULL;
else{
while(p->next!=NULL){
n++;
p=p->next;
}
if(k>n){head=NULL;
return head;
}
n=n-k;
p0=head;
for(i=n;i>0;i--)
{
p0=p0->next;
}
head=p0;
p0->next=NULL;
}
return head;
}
void release(struct cell*head){
struct cell*p;
while(head!=NULL){
p=head;
head=p->next;
free(p);
}
}
int main(void){
struct cell*head,*result;
int k;
head=build();
scanf("%d",&k);
result=back(head,k);
if(result!=NULL)
printf("%d",result->x);
else
printf("NULL");
release(head);
}
以上简单介绍了三种链表的操作,下篇将介绍另外三种链表操作。
其主要特点皆为把握逻辑性,构造链表结构图。