数据结构(精讲)----链表Linklist----应用篇

链表又称单链表、链式存储结构,用于存储逻辑关系为“一对一”的数据。

和顺序表不同同,使用链表存储数据,不强制要求数据在内存中集中存储,各个元素可以分散存储在内存中。

所以在链表中,每个数据元素可以配有一个指针用于找到下一个元素即节点,这意味着,链表上的每个“元素”都长下图这个样子:

链表的特性

逻辑结构:线性结构

存储结构:链式结构

特点:内存不连续,需要通过指针链接,大小不固定。解决顺序表插入麻烦的问题

操作:增删改查

struct node

{

int data; //数据域:存储数据

struct node *next; //指针域:存储下一个节点的地址

};

单向链表

有头链表:存在一个头节点,头节点数据域无效,指针域有效

无头链表:每一个节点的数据域和指针域都有效

遍历无头单项链表

#include

#include

typedef char datatype;

typedef struct node

{

datatype data; // 数据域用来保存数据

struct node *next; // 指针域用来保存下一个节点的地址

} node_t, *node_p;

int main(int argc, char const *argv[])

{

// 定义四个节点

node_t A = {'a', NULL};

node_t B = {'b', NULL};

node_t C = {'c', NULL};

node_t D = {'d', NULL};

// 连接四个节点

A.next = &B;

B.next = &C;

C.next = &D;

//定义一个头指针指向第一个节点

node_p p = &A;

//通过指针遍历无头单向链表

while (p != NULL)

{

printf("%c ", p->data);

p = p->next;

}

putchar('\n');

return 0;

}

遍历有头单向链表:

#include

#include

typedef char datatype;

typedef struct node

{

datatype data; // 数据域用来保存数据

struct node *next; // 指针域用来保存下一个节点的地址

} node_t, *node_p;

int main(int argc, char const *argv[])

{

// 定义四个节点

node_t A = {'a', NULL};

node_t B = {'b', NULL};

node_t C = {'c', NULL};

node_t D = {'d', NULL};

// 连接四个节点

A.next = &B;

B.next = &C;

C.next = &D;

//定义一个头结点,数据域无效,指针域有效

node_t S = {'\0',&A};

//定义一个头指针指向头结点

node_p p = &S;

#if 0

p = p->next;

while (p != NULL)

{

printf("%c ", p->data);

p = p->next;

}

putchar('\n');

#else

while (p->next != NULL)

{

p = p->next;

printf("%c ",p->data);

}

#endif

return 0;

}

链表尾插法练习:

写一个有头单向链表,用于保存输入的学生成绩,实现一输入学生成绩就创建一个新的节点,将成绩保存起来。再将该节点链接到链表的尾,直到输入-1结束。

要求:每个链表的节点由动态内存分配得到 , 也就是用malloc。

过程:

malloc申请空间link_node_t大小作为头节点

将新节点放到链表尾部

//链表尾插法

#include

#include

typedef struct student

{

int score;

struct student *next;

} link_node_t, *link_node_p;

int main(int argc, char const *argv[])

{

// 循环输入学生成绩,直到-1结束

link_node_p p = (link_node_p)malloc(sizeof(link_node_t));

if (NULL == p)

{

printf("error!\n");

return -1;

}

p->next = NULL;//初始化头结点

link_node_p ptail = p;//尾节点一开始先指向头结点

int sum = -1;

//循环输入学生成绩,直到-1结束,创建新节点保存学生成绩,尾插到链表

while (1)

{

printf("input:");

scanf("%d", &sum);

if (-1 == sum)

break;

link_node_p pnew = (link_node_p)malloc(sizeof(link_node_t));//创建新节点来保存学生成绩

if (NULL == pnew)

{

perror("pnew malloc err!\n");

return -1;

}

pnew->score = sum;

pnew->next = NULL;//新节点指针域置空

ptail->next = pnew;//尾节点的指针域保存新节点的地址

ptail = pnew;//尾节点移动到新节点,因为尾指针ptail要一直指向最后一个节点

}

//循环遍历

while (p->next != NULL)

{

p = p->next;

printf("%d ", p->score);

}

putchar('\n');

return 0;

}

有头单向链表的函数操作:

插入指定节点

删除指定节点:

删除指定数据节点:

链表转置:

1) 将头节点与当前链表断开,断开前保存下头节点的下一个节点,保证后面链表能找得到,定义一个q保存头节点的下一个节点,断开后前面相当于一个空的链表,后面是一个无头的单向链表。

2) 遍历无头链表的所有节点,将每一个节点当做新节点插入空链表头节点的下一个节点(头插),插入之前先用t保存一下q的下一个节点以防插入完找不到原来链表。