一、链表的简介
链表是一组任意的存储单元来存放线性表的结点,这组存储单元可以是连续的,也可以是不连续的,可以零散的分布在内存中的任意位置上。因此,链表中的逻辑次序和物理次序是不一定相同的。为了能正确表示结点的逻辑关系,在存储每个结点的同时,还必须存储指示其后继结点的地址信息,因此,链表中的结点结构由data(数据域)与next组成(指针域)。
单链表是链表的一种,这里只讲述关于单链表的一些简单的操作:创建、查找、插入以及删除。
二、单链表的创建
创建链表分有头结点与无头结点之分,动态的创建链表通常又分头插法和尾插法建表。
有头结点的链表相比五头结点的链表存在两个优势:
(1)由于开始结点的位置被存放在头结点的指针域中,所以链表的第一个位置上的操作就和在表的其他位置上的操作一致,就无需特殊处理。
(2)无论链表是否为空,其头指针是指向头结点的非空指针,因此空表与非空表的处理就同一了。
头插法建表与尾插法建表相比,两者存在这样的差别:头插法建表虽然简单,但生成的链表中结点的次序和输入顺序相反。若希望两者次序一致,可采用尾插法建表。尾插法建表必须增加一个尾指针,使其始终指向前链表的尾结点。
综上所述,本人根据个人喜好,在博客中的实例采用的是带头结点的尾插法建表。
尾插法建表的步骤如下:
(1)定义链表结点结构体
按照链表结点的特征,内容为data(数据域)+next(指针域),我们可以用C这样描述单链表:
typedef int datatype;
//节点类型定义
typedef struct node{
datatype data;
struct node *next;
}linklist;
linklist *head,*p; /*指针类型说明*/
(2)建立头结点
建立头结点一般分三步:
a.为头结点申请内存空间,C语言表示为:p = malloc(sizeof(linklist));
b.将头结点指针域清空、尾指针指向头结点。
(3)加入节点
加入新的节点与建立头结点有些相似,大体步骤如下:
a.为新节点申请内存空间(listnode*)malloc(sizeof(listnode));
b.给结点内部赋值;
c.将前一个节点的指针域指向新节点;
d.将标志位一道新结点;
e.如果是最后一个结点,需要将该节点的指针域清空。
三、单链表的查找
单链表的查找有两种:按值查找与按位置查找。
1、按位置查找
在链表中,技师知道被访问的结点的序号i,也不能像顺序表中那样直接按序号i访问结点,而只能从链表的头结点出发,顺链域逐个结点往下查找,知道查找到第i个位置为止。因此,链表不是随机存取结构。
2、按值查找
安置查找首先按照按位置查找的思想遍历整个链表,查找是否有结点值等于给定值key的结点。查找过程从开始结点出发,顺着链逐个将结点的值跟给定值比较。
四、单链表的插入
与创建单链表相类似,结点的插入也分前插与后插,两者并没有太多的区别,但必须都要生成的的结点,然后修改相应的指针,最后进行插入。本文实例采用的是后插法插入新的结点,插入运算的步骤如下:
1、判断插入位置是否合法
2、创建新结点q且为其赋值(上文已有,不再赘述);
3、找到需要插入的位置(i)的前一个位置p(i-1);
4、将新节点插在p之后,调整指针域,将原先p的指针域赋值给q,然后将jiang p的指针域内容换成q的地址。
五、单链表的删除
删除结点与结点的插入相类似,可以直接条畅指针域实现,但有一点非常重要,在删除完结点之后需要释放该节点的内存空间(free(p)),具体步骤如下:
1、判断位置是否合法;
2、找到删除位置的前一位i-1;
3、将i-1的指针域指向i+1;
4、释放原先i位置上结点的内存空间。
六、实例:create_list.c
/*************************************************
Date:2015-5-24 13:08
Filename:create_list.c
Author:Chen liusuo
E-mail:liusuochen@gamil.com
Describe:单向链表的创建、插入、删除、查找、输出
*************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
//结点结构体定义
struct Node
{
char name[10];
int score;
struct Node *next;
};
//函数声明
typedef struct Node ListNode;
//尾插法建立链表
ListNode *CreateList(int total)
{
ListNode *head; /*头节点指针*/
ListNode *p,*r;
int i;
//链表初始化
head = (ListNode*)malloc(sizeof(ListNode)); /*为头节点申请内存空间*/
head->next = NULL; /*将头节点的指针域清空*/
r = head; /*尾指针初值指向头节点*/
//通过for循环加入新节点
for ( i=1; i<=total; i++){
p = (ListNode*)malloc(sizeof(ListNode));/*为要插入的新节点分配内
存空间*/
printf("input name of the %d student\n",i);
printf("input name of the student:");
scanf("%s",p->name);
printf("input score of the student:");
scanf("%d",&p->score);
r->next = p; /*将p指向新节点插入链表指向的下个节点*/
r = p; /*用于指向下一个节点*/
}
p->next = NULL; /*最后将最后一个节点的指针域清空*/
return head; /*返回链表的首地址*/
}
//链表打印函数
void PrintList(ListNode *h)
{
ListNode *p;
p = h->next;
while(p){
printf("%s,%d",p->name,p->score);
p = p->next;
printf("\n");
}
}
//按位置查找节点,若找到则返回位置P,否则返回NULL
ListNode *GetNodeByNum(ListNode *h,int location)
{
int j = 0;
ListNode *p;
p = h;
while(p->next && j<location){
p = p->next;
j++;
}
if(j==location){
return p;
}else{
return NULL;
}
}
//按内容查找,若找到则返回该节点的存储位置
ListNode *GetNodeByKey(ListNode *h,char name[])
{
int j = 0;
ListNode *p;
p = h;
while(p != NULL){
if(p->name != name){
p = p->next;
}else{
break;
}
return p;
}
}
//查找调用函数
void Get(ListNode *h)
{
int choice;
int location;
char name[10];
printf("1.按值查找\n");
printf("2.按位置查找\n");
scanf("%d",&choice);
switch(choice){
case 1:
printf("Please input the name of student:");
scanf("%s",name);
GetNodeByKey(h,name);
break;
case 2:
printf("Please input the num of student:");
scanf("%d",&location);
GetNodeByNum(h,location);
break;
default:
break;
}
}
//链表节点插入函数
void InsertList(ListNode *h,int location,char name[],int score,int total)
{
ListNode *q,*p; //定义2个指向一个节点的指针
int j;
if(location<1 || location>total+1)
printf("Error!Please input again.\n");
else{
j = 0;
p = h;
//找到i-1的位置
while(j < location-1){
p = p->next;
j ++;
}
q = (ListNode*)malloc(sizeof(ListNode));
//节点数据赋值
strcpy(q->name,name);
q->score = score;
//调整指针域
q->next = p->next;
p->next = q;
}
}
//链表删除函数
void DeleteList(ListNode *h,int location,int total)
{
ListNode *p,*q;
int j;
char name[10];
int score;
if(1<location || location>total){
printf("Error! Please input again.\n");
}else{
j = 0;
p = h;
//找到i-1的位置
while(j< location-1){
p = p->next;
j ++;
}
q = p->next;/*q指向要删除位置*/
p->next = q->next;
strcpy(name,q->name);
score = q->score;
free(q);
printf("Delete name=%s,score=%d\n",name,score);
}
}
void main()
{
ListNode *h;//h指向结构体NODE
int choice ,total ,location,score; /*定义选项、节点数量、位置、分数*/
char name[10];
while(1){
printf("--------------------------\n");
printf("1.建立新的链表\n");
printf("2.添加元素\n");
printf("3.删除元素\n");
printf("4.查找元素\n");
printf("5.输出当前表中的元素\n");
printf("0.退出\n");
printf("--------------------------\n");
scanf("%d",&choice);
switch(choice){
case 1:
printf("The number of Node:");
scanf("%d",&total);
h = CreateList(total);
printf("list elements is:\n");
PrintList(h);
break;
case 2:
printf("input the position of insert elements:");
scanf("%d",&location);
printf("input name of the student:");
scanf("%s",name);
printf("input score of the student:");
scanf("%d",&score);
InsertList(h,location,name,score,total);
PrintList(h);
break;
case 3:
printf("input the position of delete element:");
scanf("%d",&location);
DeleteList(h,location,total);
printf("list elements in:\n");
PrintList(h);
break;
case 4:
Get(h);
break;
case 5:
printf("list elements is:\n");
PrintList(h);
break;
case 0:
return;
break;
default:
printf("Error! Try again!\n");
}
}
}