大家好久不见(搞得这种辣鸡文章有人看一样。。。)
最近在忙学校里的项目和学车,再加上懒,好久没有更新这个系列了,emmmm,今天终于有点时间更新一下了,今天介绍数据结构中线性表的另一个知识点——链表。
链表的定义
线性表的链式存储特点是用任意的存储单元存储线性表的数据元素,其存储单元可以是连续,也可以是不连续的(顺序表一定是连续的),为了表示链表前后元素的关系,在元素中在其本身携带的数据基础上,添加一个指向后面一个节点的存储映像(也就是下一个节点的地址)。链表的一个节点中,存储数据的部分称为数据域,存储地址的部分称为指针域。
如图所示即链表的直观表示:
链表的存储结构
typedef struct LNode {
int data;
struct LNode *next;
}LNode, *LinkList;
其中data部分即数据域,他的类型可以是各种各样的,这里只是用int作为例子,next即为下一节点的地址。
链表的实现(增、删、顺序合并)
直接上代码:
stdafx.h
#include <stdio.h>
#include <stdlib.h>
typedef struct LNode {
int data;
struct LNode *next;
}LNode, *LinkList;
/************************************************************************/
/*创建链表 */
/************************************************************************/
LinkList initLinkedList();
/************************************************************************/
/*从链表中插入值 */
/*L:想要插入值的链表 */
/*i:想要插入的位置 */
/*data:想要插入的值 */
/************************************************************************/
int insertElement(LinkList L, int i, int data);
/************************************************************************/
/*从链表中插入值 */
/*L:想要插入值的链表 */
/*i:想要插入的位置 */
/*return: 0:删除失败 1:删除成功*/
/************************************************************************/
int deleteElement(LinkList L, int i);
/************************************************************************/
/* 合并两个有序列表 */
/************************************************************************/
LinkList mergeList(LinkList La, LinkList Lb);
// LinkedListTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
LinkList testInsert();
void testDelete();
void testMergeList();
int main(void)
{
//都是测试函数
testInsert();
testDelete();
testMergeList();
system("pause");
return 0;
}
//初始化函数
LinkList initLinkedList() {
LinkList L;
L = (LinkList)malloc(sizeof(LNode));
if (L)
{
L->next = NULL;
return L;
} else {
return 0;
}
}
//插入
int insertElement(LinkList L, int i, int data) {
int j = 0;
LinkList p = L;
LinkList node = initLinkedList();
if (node) {
node->data = data;
} else {
return 0;
}
while(p && j < i) {
p = p->next;
j++;
}
if (!p || j > i) {
return 0;
}
node->next = p->next;
p->next = node;
return 1;
}
//删除
int deleteElement(LinkList L, int i) {
int j = 0;
LinkList p = L;
LinkList q = L->next;
while(q && j < i) {
q = q->next;
p = p->next;
j++;
}
if (!q || j > i) {
return 0;
}
p->next = q->next;
free(q);
return 1;
}
//合并
LinkList mergeList(LinkList La, LinkList Lb) {
LinkList pa = La->next;
LinkList pb = Lb->next;
LinkList Lc, pc;
Lc = pc = La; //把A链表的头结点作为C链表的头结点
while(pa && pb) {
if (pa->data <= pb->data) {
pc->next = pa;
pc = pa;
pa = pa->next;
} else {
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
//插入剩余节点
pc->next = pa ? pa : pb;
//释放资源
free(Lb); //这里只要释放B链表的头就可以了
return Lc;
}
LinkList testInsert() {
int i = 0;
LinkList LHead = initLinkedList();
for (i = 0;i < 5;i++)
{
if (!insertElement(LHead, 0, i))
{
printf("插入第%d元素时失败",i);
break;
}
}
LinkList p = LHead->next;
if (i >= 5)
{
while(p) {
printf("%d\t", p->data);
p = p->next;
}
printf("\n");
}
return LHead;
}
void testDelete() {
LinkList LHead = testInsert();
deleteElement(LHead, 2);
LinkList p = LHead->next;
while(p) {
printf("%d\t", p->data);
p = p->next;
}
}
void testMergeList() {
LinkList La = initLinkedList();
LinkList Lb = initLinkedList();
insertElement(La, 0, 9);
insertElement(La, 0, 6);
insertElement(La, 0, 3);
insertElement(Lb, 0, 8);
insertElement(Lb, 0, 7);
insertElement(Lb, 0, 1);
LinkList Lc = mergeList(La, Lb);
LinkList pc = Lc->next;
while(pc) {
printf("%d\t", pc->data);
pc = pc->next;
}
printf("\n");
}
这几个功能比较简单,实现起来并不难,其中test开头函数都是测试增删以及合并功能的函数,偷懒就写的比较随意,看看就好了。
运行结果:
这里因为测试delete的时候顺便把insert也给测了,所以就运行了俩test函数
小结
可以看出,链表和顺序表虽然同为线性表,但是他们的区别以及特长都是不一样的,顺序表的存储结构是相邻的,访问数据方便但是插入删除非常耗时,而链表恰恰相反,他的删除和插入都很方便,但是遍历访问比较耗时,所以在实际运用中,具体选择哪种数据结构是根据具体情况来判断的,这一节就先到这里,下一节会介绍循环链表,双向链表以及一元二次多项式的问题。