之前用C语言写过数据结构的链式队列 链接http://t.csdn.cn/sgDme感兴趣的朋友可以看一下。
今天再写一个数据结构里面最基础的链表(后附完整代码),链表作为数据结构的基本,掌握其写法是非常重要的。
链表的数据结构如图所示
节点是由数据域和指针域两个部分组成,其中数据域里面的数据类型可以是任何形式的数据,包括结构体数据类型,在本例中为了方便说明就以整形为例。指针域里面存放指针。
一般在写数据结构之前,都要对节点进行定义,节点定义如下
//定义节点
typedef struct Node
{
int data; //节点的数据域
struct Node* next; //节点的指针域
}NODE;
一般单向链表可以分为有表头和没有表头两种,本例描述有表头的单向链表。表头的定义如下
//创建链表头
NODE* createHead()
{//这次以有表头的链表为例
NODE* mylist = (NODE*)malloc(sizeof(NODE));
mylist->data = 0; //表头里面的这个参数用来记录链表里面的系点数
mylist->next = NULL;
return mylist;
}
定义节点后就要设计函数创建节点,创建节点函数如下
//创建节点
NODE* createNode(int data)
{//所谓创建节点就是初始化节点里面的参数
NODE* newnode = (NODE*)malloc(sizeof(NODE));
newnode->data = data;
newnode->next = NULL; //初始化时,指针域指向空
return newnode;
}
现在我们有了链表头和创建节点函数,就可以给链表中加入节点元素了,加入节点的方法一般用两种,即头插法和尾插法,头插法函数如下
//头插法
void insertNodeByHead(NODE* mylist, int data)
{
NODE* newnode = createNode(data);
if (mylist->data == 0)
{
mylist->next = newnode; //当链表为空,直接将新节点放在表头的后面
}
else //当链表不为空
{
NODE* tmp = mylist->next; //创建临时指针指向链表当前的第一个元素
newnode->next = tmp; //将新节点的指针域指向临时指针所指向的地址,即原先链表的第一个节点
mylist->next = newnode; //链表头的指针域在指向新节点的地址,这样新节点在空间上就处于链表的第一位了
}
mylist->data++; //插入新节点后,计数加一
}
尾插法函数如下
//尾插法
void insertNodeByTail(NODE* mylist, int data)
{
NODE* newnode = createNode(data); //插入前,先创建新节点
if (mylist->data == 0)
{
mylist->next = newnode; //如果链表为空,则直接将新节点插入表头后面
}
else
{
NODE* tmp = mylist->next; //创建一个临时指针用来找到链表尾部
while (tmp->next) //当临时节点后面的节点不是空时
{
tmp = tmp->next; //临时指针指向下一个节点
}
tmp->next = newnode; //最终跳出循环的临时指针后面所指为空,此时临时指针就是链表尾部
}
mylist->data++; //插入节点后,计数值加一
}
有加入节点的方法,就应该有删除节点的方法,本例的链表默认每个元素的数据域数值大小不同,删除节点函数如下(其实删除节点的方法有很多种,比如定义删除链表的第几个元素),本例删除节点的依据是数据域的值为我们要删除的对象
//删除节点
void deleteNode(NODE* mylist,int data)
{
NODE* pre = mylist; //创建新指针指向链表的表头地址
NODE* cur = mylist->next; //创建新指针指向链表的第一个节点地址
while (cur->data != data && cur->next!=NULL) //当cur的数据域不等于要删除的节点数据时,
//且cur的下一个节点不为空
{
pre = cur; //pre指向cur
cur = cur->next; //cur指向下一个节点位置
}
//跳出这个循环后,cur所指向的位置要么为空,要么是要删除的节点(本例设定链表元素数值都不同)
if (cur == NULL) //当cur所指向的位置为空时
{
printf("该链表没有这个节点\n"); //打印提示
}
else //当cur指向了要删除的节点
{
pre->next = cur->next; //由之前的while循环,pre一直指向cur的前一个节点。
//此时让pre指向cur的后一个节点(这里需要空间想象)
free(cur); //free掉cur,即删除链表中这个节点
mylist->data--; //删除一个节点,计数需要减一
}
}
这样我们对于链表的一些基础操作都有了,在将链表的每个元素从第一个当最后一个打印出来
//打印链表
void print(NODE* mylist)
{
NODE* tmp = mylist->next; //创建临时指针指向第一个节点地址
while(tmp) //当临时指针不为空
{
printf("%d ", tmp->data); //打印节点的数据域
tmp = tmp->next; //临时指针指向下一个节点
}
printf("\n"); //打印完所有节点的数据域之后,换行
}
测试代码
int main()
{//测试
//创建链表头
NODE* mylist = createHead();
//头插法
insertNodeByHead(mylist, 1);
insertNodeByHead(mylist, 2);
insertNodeByHead(mylist, 3);
insertNodeByHead(mylist, 4);
insertNodeByHead(mylist, 5);
//打印所有节点
print(mylist);
//尾插法
insertNodeByTail(mylist, 10);
insertNodeByTail(mylist, 9);
insertNodeByTail(mylist, 8);
insertNodeByTail(mylist, 7);
//打印所有节点
print(mylist);
//删除数据域为3的节点
deleteNode(mylist, 3);
//打印所有节点
print(mylist);
return 0;
}
测试结果
完整代码
#include<stdio.h>
#include<malloc.h>
//定义节点
typedef struct Node
{
int data; //节点的数据域
struct Node* next; //节点的指针域
}NODE;
//创建节点
NODE* createNode(int data)
{//所谓创建节点就是初始化节点里面的参数
NODE* newnode = (NODE*)malloc(sizeof(NODE));
newnode->data = data;
newnode->next = NULL; //初始化时,指针域指向空
return newnode;
}
//创建链表头
NODE* createHead()
{//这次以有表头的链表为例
NODE* mylist = (NODE*)malloc(sizeof(NODE));
mylist->data = 0; //表头里面的这个参数用来记录链表里面的系点数
mylist->next = NULL;
return mylist;
}
//尾插法
void insertNodeByTail(NODE* mylist, int data)
{
NODE* newnode = createNode(data); //插入前,先创建新节点
if (mylist->data == 0)
{
mylist->next = newnode; //如果链表为空,则直接将新节点插入表头后面
}
else
{
NODE* tmp = mylist->next; //创建一个临时指针用来找到链表尾部
while (tmp->next) //当临时节点后面的节点不是空时
{
tmp = tmp->next; //临时指针指向下一个节点
}
tmp->next = newnode; //最终跳出循环的临时指针后面所指为空,此时临时指针就是链表尾部
}
mylist->data++; //插入节点后,计数值加一
}
//头插法
void insertNodeByHead(NODE* mylist, int data)
{
NODE* newnode = createNode(data);
if (mylist->data == 0)
{
mylist->next = newnode; //当链表为空,直接将新节点放在表头的后面
}
else //当链表不为空
{
NODE* tmp = mylist->next; //创建临时指针指向链表当前的第一个元素
newnode->next = tmp; //将新节点的指针域指向临时指针所指向的地址,即原先链表的第一个节点
mylist->next = newnode; //链表头的指针域在指向新节点的地址,这样新节点在空间上就处于链表的第一位了
}
mylist->data++; //插入新节点后,计数加一
}
//删除节点
void deleteNode(NODE* mylist,int data)
{
NODE* pre = mylist; //创建新指针指向链表的表头地址
NODE* cur = mylist->next; //创建新指针指向链表的第一个节点地址
while (cur->data != data && cur->next!=NULL) //当cur的数据域不等于要删除的节点数据时,
//且cur的下一个节点不为空
{
pre = cur; //pre指向cur
cur = cur->next; //cur指向下一个节点位置
}
//跳出这个循环后,cur所指向的位置要么为空,要么是要删除的节点(本例设定链表元素数值都不同)
if (cur == NULL) //当cur所指向的位置为空时
{
printf("该链表没有这个节点\n"); //打印提示
}
else //当cur指向了要删除的节点
{
pre->next = cur->next; //由之前的while循环,pre一直指向cur的前一个节点。
//此时让pre指向cur的后一个节点(这里需要空间想象)
free(cur); //free掉cur,即删除链表中这个节点
mylist->data--; //删除一个节点,计数需要减一
}
}
//打印链表
void print(NODE* mylist)
{
NODE* tmp = mylist->next; //创建临时指针指向第一个节点地址
while(tmp) //当临时指针不为空
{
printf("%d ", tmp->data); //打印节点的数据域
tmp = tmp->next; //临时指针指向下一个节点
}
printf("\n"); //打印完所有节点的数据域之后,换行
}
int main()
{//测试
//创建链表头
NODE* mylist = createHead();
//头插法
insertNodeByHead(mylist, 1);
insertNodeByHead(mylist, 2);
insertNodeByHead(mylist, 3);
insertNodeByHead(mylist, 4);
insertNodeByHead(mylist, 5);
//打印所有节点
print(mylist);
//尾插法
insertNodeByTail(mylist, 10);
insertNodeByTail(mylist, 9);
insertNodeByTail(mylist, 8);
insertNodeByTail(mylist, 7);
//打印所有节点
print(mylist);
//删除数据域为3的节点
deleteNode(mylist, 3);
//打印所有节点
print(mylist);
return 0;
}