目录
基本概念
- 线性表最常用且简单的一种数据结构,一个线性表是n个元素的有限序列
- 线性结构:在数据元素的非空有限集合中,有以下几种特点
存在唯一的一个被称作"第一个的元素" |
存在唯一的一个被称作"最后一个的元素" |
除第一个以外,集合中的每一个数据元素均只有一个前驱 |
除最后一个以外,集合中的每一个数据元素均只有一个后继 |
单链表的特点
- 用任意的存储单元存储数据元素
- 存储单元可以是连续的,也可以是不连续的
- 每个存储单元除了存储其本身数据以外,还需存储器直接后继的存储位置
- 便于数据的插入与删除操作
部分算法分析
- 头插法创建单链表
//初始化单链表(头插法),创建n个链表节点长度的单链表 Status InitLinkListHead(LinkList& L, int n) { cout << "为" << n << "个节点赋值:" << endl; //创建头结点,此时头指针的地址为头结点地址 L = (LinkList)malloc(sizeof(LNode)); //判断结构体指针是否为NULL,即空间是否分配成功 if (!L) return ERROR; //将头结点的next指针只想NULL L->next = NULL; //创建n个链表节点 LinkList p; for (int i = n; i > 0; --i) { //分配新的节点,并给节点赋值 p = (LinkList)malloc(sizeof(LNode)); if (!p) return ERROR; cin >> p->data; p->next = L->next; L->next = p; } cout << "头插法链表创建成功" << endl; return OK; }
头插法节点的插入位置始终在头结点之后插入新节点,所以当创建节点时输入 34、21、56,遍历单链表时输出为逆序即 56、21、34
- 尾插法创建单链表
//初始化单链表(尾插法)
Status InitLinkListTail(LinkList& L, int n) {
cout << "为" << n << "个节点赋值:" << endl;
LinkList p,rear;
L = (LinkList)malloc(sizeof(LNode));
if (!L)
return ERROR;
rear = L;
for (int i = 0; i < n; ++i) {
p = (LinkList)malloc(sizeof(LNode));
if (!p)
return ERROR;
cin >> p->data;
//使上一个节点指向新节点
rear->next = p;
//使rear指针始终指向最末尾的一个节点
rear = p;
}
rear->next = NULL;
cout << "尾插法创建单链表成功" << endl;
return OK;
}
尾插法始终在rear指针(始终指向单链表的最后的一个节点)后添加新的节点,使用尾插法创建单链表时输入 34、21、56,在遍历单链表时输出为正序即 34、21、56
- 单链表节点的插入操作
//单链表节点的插入操作:在第i个位置插入节点
Status InsertLinkList(LinkList& L, int i, ElemType elem) {
//此时p为头结点
LinkList p = L;
int j = 0;
//找到插入位置节点的前一个节点
while (p && j < i - 1) {
p = p->next;
++j;
}
//判断该节点是否存在
if (!p || j > i)
return ERROR;
//创建新节点
LinkList node = (LinkList)malloc(sizeof(LNode));
if (!node)
return ERROR;
node->data = elem;
node->next = p->next;
p->next = node;
return OK;
}
找到插入位置的前一个节点,即节点p,让node指向p的下一个节点,再让p指向新节点node即可
线性表的链式表示和实现
- global.h
- LinkList.h
- LinkListTest.h
global.h
相关头文件的引用,以及相应全局变量、常量的声明
#pragma once
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<windows.h>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define EQ(a,b) ((a) == (b))
#define LT(a,b) ((a) < (b))
#define LQ(a,b) ((a) <= (b))
#define MT(a,b) ((a) > (b))
#define MQ(a,b) ((a) >= (b))
typedef int Status;
LinkList.h
单链表结构的定义,以及单链表的相关操作算法
#pragma once
#include"global.h"
#define ElemType int
/*
* 线性表的链式表示
*/
/*----------线性表的但单链表存储结构----------*/
typedef struct LNode {
//数据域
ElemType data;
//指针域
struct LNode* next;
}LNode,*LinkList;
//初始化单链表(头插法),创建n个链表节点长度的单链表
Status InitLinkListHead(LinkList& L, int n) {
cout << "为" << n << "个节点赋值:" << endl;
//创建头结点,此时头指针的地址为头结点地址
L = (LinkList)malloc(sizeof(LNode));
//判断结构体指针是否为NULL,即空间是否分配成功
if (!L)
return ERROR;
//将头结点的next指针只想NULL
L->next = NULL;
//创建n个链表节点
LinkList p;
for (int i = n; i > 0; --i) {
//分配新的节点,并给节点赋值
p = (LinkList)malloc(sizeof(LNode));
if (!p)
return ERROR;
cin >> p->data;
p->next = L->next;
L->next = p;
}
cout << "头插法链表创建成功" << endl;
return OK;
}
//初始化单链表(尾插法)
Status InitLinkListTail(LinkList& L, int n) {
cout << "为" << n << "个节点赋值:" << endl;
LinkList p,rear;
L = (LinkList)malloc(sizeof(LNode));
if (!L)
return ERROR;
rear = L;
for (int i = 0; i < n; ++i) {
p = (LinkList)malloc(sizeof(LNode));
if (!p)
return ERROR;
cin >> p->data;
//使上一个节点指向新节点
rear->next = p;
//使rear指针始终指向最末尾的一个节点
rear = p;
}
rear->next = NULL;
cout << "尾插法创建单链表成功" << endl;
return OK;
}
//单链表的遍历,输出单链表内的所有节点数据
void ShowLinkList(LinkList L) {
//L->next指的是头结点后的一个节点,头节点不存储数据
LinkList p = L->next;
if (!p) {
cout << "单链表内的数据为空" << endl;
}
cout << "单链表内的节点数据:";
while (p) {
cout << p->data << " ";
//指向下一个节点
p = p->next;
}
cout << endl;
}
//获取单链表内的第i个节点数据
Status GetLinkListElem(LinkList L, int i, ElemType& elem) {
LinkList p;
p = L->next;
int j = 1;
//找到第i个节点
while (p && j < i) {
p = p->next;
++j;
}
//判断第i个节点是否存在
if (!p || j > i)
return ERROR;
elem = p->data;
return OK;
}
//单链表节点的插入操作:在第i个位置插入节点
Status InsertLinkList(LinkList& L, int i, ElemType elem) {
//此时p为头结点
LinkList p = L;
int j = 0;
//找到插入位置节点的前一个节点
while (p && j < i - 1) {
p = p->next;
++j;
}
//判断该节点是否存在
if (!p || j > i)
return ERROR;
//创建新节点
LinkList node = (LinkList)malloc(sizeof(LNode));
if (!node)
return ERROR;
node->data = elem;
node->next = p->next;
p->next = node;
return OK;
}
//单链表节点的删除操作:删除第i个节点
Status DeleteLinkList(LinkList& L, int i) {
LinkList p = L;
int j = 0;
while (p && j < i - 1) {
p = p->next;
++j;
}
if (!p || j > i - 1)
return ERROR;
//q为第i个节点,即所要删除的节点
LinkList q = p->next;
if (!q)
return ERROR;
//让p指向q的下一个节点
p->next = q->next;
//释放该节点的空间
free(q);
return OK;
}
//对单链表进行升序操作(并未交换节点之间的指向,仅仅交换了节点之间的数据)
Status LinkListIsAscending(LinkList& L) {
LinkList p = L->next;
while (p) {
LinkList r = p->next;
while (r) {
if (p->data > r->data) {
ElemType elem = r->data;
r->data = p->data;
p->data = elem;
}
r = r->next;
}
p = p->next;
}
return OK;
}
//将两个有序的单链表合并为一个有序的单链表
Status MergeLinkList(LinkList& Lc, LinkList& La, LinkList& Lb) {
LinkList pa = La->next;
LinkList pb = Lb->next;
//使用La的头结点作为Lc的头结点
LinkList pc = Lc = La;
while (pa && pb) {
//比较pa与pb节点内的数据大小,将小的节点插入Lc链表内
if (pa->data <= pb->data) {
pc->next = pa;
pc = pa;
pa = pa->next;
}
else {
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
//将pa或pb剩余的节点插入Lc节点(前提:La与Lb均是有序链表)
pc->next = pa ? pa : pb;
if (!Lb)
return ERROR;
free(Lb);
return OK;
}
LinkListTest.cpp
#include"LinkList.h"
int main() {
LinkList list;
int n;
cout << "(头插法)输入创建单链表的节点数:" << endl;
cin >> n;
InitLinkListHead(list,n);
ShowLinkList(list);
LinkList list2;
cout << "(尾插法)输入创建单链表的节点数:" << endl;
cin >> n;
InitLinkListTail(list2, n);
ShowLinkList(list2);
cout << "单链表的节点插入操作:" << endl;
cout << "输入插入节点的位置:" << endl;
cin >> n;
ElemType elem;
cout << "输入插入节点的数据:" << endl;
cin >> elem;
InsertLinkList(list, n, elem);
ShowLinkList(list);
cout << "单链表节点删除操作:" << endl;
cout << "请输入删除节点的位置:" << endl;
cin >> n;
DeleteLinkList(list2, n);
ShowLinkList(list2);
cout << "单链表的合并操作:" << endl;
LinkListIsAscending(list);
ShowLinkList(list);
LinkListIsAscending(list2);
ShowLinkList(list2);
LinkList Lc;
MergeLinkList(Lc, list, list2);
ShowLinkList(Lc);
}
运行结果
(头插法)输入创建单链表的节点数:
4
为4个节点赋值:
10 5 34 76
头插法链表创建成功
单链表内的节点数据:76 34 5 10
(尾插法)输入创建单链表的节点数:
6
为6个节点赋值:
12 3 6 85 34 89
尾插法创建单链表成功
单链表内的节点数据:12 3 6 85 34 89
单链表的节点插入操作:
输入插入节点的位置:
3
输入插入节点的数据:
21
单链表内的节点数据:76 34 21 5 10
单链表节点删除操作:
请输入删除节点的位置:
2
单链表内的节点数据:12 6 85 34 89
单链表的合并操作:
单链表内的节点数据:5 10 21 34 76
单链表内的节点数据:6 12 34 85 89
单链表内的节点数据:5 6 10 12 21 34 34 76 85 89F:\DataStructureForC++\Project\Debug\Project1.exe (process 2244) exited with code 0.