1.链表的介绍
//链表的意义:减少不必要的空间浪费+不占用连续的一片内存空间
a.链表的结构:链表结构由若干环节组成,每个环节称为一个结点或节点(C++中链表的环节用结构体变量实现),结点内部空间是连续的,结点与结点间的存储空间不一定需要连续,通过指针建立结点之间的链接,由一个结点找到另一个结点。
每一结点的结构eg.
typedef struct
{
int age;
char n[10];
STU *next; //指向下一结点的指针
}STU;
b.链表的类型:
单向链表(简称单链表)
//单链表又分为
//不带头结点的单链表:所有结点都存储数据序列中的数据
//带头结点的单链表:从第2个结点开始存储数据带头结点的链表可以使操作变得简单
双向链表
单向循环链表
双向循环链表等
//单链表实现:有一个头指针(首指针)指向头结点/首元结点,每个结点中有包含指向下一结点的指针,最后一个结点的值为NULL(即空指针,不指向任一结点,链表结束)。
//不带头结点的单链表 VS 带头结点的单链表
不带头结点的单链表:直接由一个头指针指向首元结点。
带头结点的单链表:头指针指向头结点,头结点内包含的指针指向首元结点。
c.链表结构的优点:插入、删除结点数据时,链表结构的算法效率比较高(只需改变指针指向)。
d.链表结构的缺点:指针占用额外的存储空间;结点本身的存储空间需要动态申请和释放。
//在解决实际问题时,需依据长期编程积累的经验来决定使用哪一种数据结构较为有利
- 习惯动态申请空间的写法
动态空间只能用指针间接访问
a.
int *p;
p = new int;
delete p;
b.
int *p;
p = new int(8);
delete p;
c.
int *p;
p = new int[10];
delete []p;
delete [10]p;
d.
int (*p)[4];
p = new int[3][4];
delete []p;
delete [3]p;
3.习惯const的写法
a.
//const型变量
const float pi = 3.14;
float const pi = 3.14;
b.
//指针常量
int * const p = &a;
c.
//指向常量的指针
const int *p;
//指针作为函数参数:在调用时,是传值调用,传递的是地址值,系统需要分配内存空间给形参变量
//setw() 默认向右对齐,左侧填充空格
4.链表的常用算法 [注:这里的链表指不带头结点的单链表]
a.首先,定义结构体类型:
struct node //定义结构体类型,只能这么定义,不能用typedef
{
int data;
node *next;
};
重点理解:要改变链表中某结点内指针的指向,要访问next 并修改它
b.创建无序链表
//返回链表的头指针//学习迭代思想
node *create()
{
cout << "正在创建一条无序链表" << endl; //调试语句
node *p1, *p2 = NULL, *head = NULL;
int a;
cin >> a;
while(a <= 0)//前提:假设输入的数都为正整数,当输入的数为非正整数时,则结束创建结点。//应具体问题具体分析。
{
p1 = new node; //迭代:申请一个结点
p1->data = a; //赋值结构体内的变量数值
p1->next = NULL;
if(head == NULL)
head = p1;
else
p2->next = p1;//迭代:此时的 p2 指上一结点 //学习
p2 = p1;//p2存为副本
cin >> a;
}
return head;
}
c.创建有序链表
—有序链表:一个链表中各结点的数据域值的大小从头到尾依次递增或递减。依次递增的为升序链表;依次递减的为降序链表。注意空链表是升序链表。
—创建有序链表可采用的方法是:循环输入数值,建立一个新结点,其数据域就是输入的数值,调用插入结点函数,将该新结点插入到链表中,使链表始终保持升序。
//返回链表头指针
node *create_sort()
{
cout << "正在创建一条升序链表" << endl; //调试语句,输出了,表示调用成功
node *p, *head = NULL;
int a;
cin >> a;
while(a != -1)
{
p = new node;
p->data = a;
head = insert(head, p);
cin >> a;
}
return head;
}
d.插入一个结点(本节算法适用于升序链表)
—算法思路:插入结点时,若原链表为空链表,则构造一个具有一个结点的链表,首结点指向该结点即可。若原链表是非空链表,则插入结点时分三种情况:1.插入原链表首结点之前;2.插入在链表中间;3.插入在链表尾结点之后。
//插入结点;返回头指针 //向一个升序链表中插入一个新结点,结果链表仍然是升序的
node *insert(node *head, node *p)
{
node *p1 = head, *p2 = NULL;
if(head == NULL)//当为空表时
{
head = p;
p->next = NULL;
return head;
}
else //如果原链表不是空表,则 先找插入位置;再修改指针的指向
{//算法:从头到尾找下去;当找到比p->data大的结点(这个结点)时,停止,把p插入到这个结点的前面(把这个结点前面的结点next指向p,把p的next指向这个结点)
while(p1 != NULL)
{
if(p1->data >= p->data)//当找到了这个结点时
{
if(p1 == head)//这个结点是头结点
{
head = p;
p->next = p1;
return head;
}
else//如果为中间结点
{
p2->next = p;
p->next = p1;
return head;
}
}
else
{
p2 = p1;//p2做副本
p1 = p1->next;
}
}
p2->next = p;//插入末尾
p->next = NULL;
return head;
}
}
e.遍历链表(查找结点)
—含义:依次访问链表的各个结点。
—应用:依次输出各结点数据值;在链表中查找某个结点是否存在.
—使用const:一方面保护指针所指向的值; 另一方面保护查找到的结点。
//打印链表
void print(const node *p) //需要 头指针 参数
{//打印各结点数据值
cout << "打印链表" << endl;
while(p != NULL)
{
cout << setw(4) << (p->data);
p = p->next;//迭代
}
cout << endl;
}
//查找第一个值为num的结点位置 //找到了:返回num的结点位置;找不到:返回NULL
node *search(node *head, int num)
{
cout << "正在查找值为" << num << "的结点的位置" << endl; //调试语句
node *p = head;
while(p != NULL)
{
if(p->data == num)
return p;
p = p->next;
}
return NULL;//返回空指针:用 return NULL; 即可
}
f.删除一个结点
—删除结点的含义:删除链表中满足一定条件的结点。当有多个符合删除条件结点,则只删除第一个。
—head为空—无需删除
head为非空 —找不到待删除结点 无须删除
找到待删除结点—待删除结点为首结点,删后要重新设置首指针head
待删除结点为其他结点,此时不需要修改首指针,但要修改被删除的结点的上一结点的next指针指向。
//删除第一个值为num的结点;返回删除后链表的头指针;
node *delete_one_node(node *head, int num)
{
cout << "正在删除值为" << num << "的第一个结点" << endl;//调试语句
node *p1 = head;//p1遍历
node *p2 = NULL;
while(p1 != NULL)
{
if(p1->data == num)//先找:找到了
{
if(p2 == NULL)//说明p1是头指针
{
head = p1->next;
delete p1;
return head;
}
else
{
p2->next = p1->next;//算法,当找到时,先把前一结点的next值更新为当前结点的next值,然后删除当前结点
delete p1;
return head;
}
}
else //找不到
{
p2 = p1;//记住上一结点
p1 = p1->next;
}
}
return head;
}
g.释放链表
—含义:释放链表全体结点空间。
—算法思路:一个一个删
//释放链表
void delete_chain(node *head)
{
cout << "正在释放链表" << endl;//调试语句
node *p1 = head, *p2 = NULL;
while(p1 != NULL)
{
p2 = p1;//p2做副本
p1 = p1->next;
delete p2;//删除p2所指的内存空间
}
}
h.主函数样例:
#include <iostream>
#include <iomanip>
using namespace std;
......//各类函数
int main()
{
node *head;
int num;
head = create(); //创建一条无序链表
cout << "完成" << endl;
print(head); //打印创建好的链表
cout << "输入待删除结点上的整数:";
cin >> num;
head = delete_one_node(head, num); //删除结点
print(head); //打印删除一个结点后的链表
cout << "输入要查找的整数:";
cin >> num;
if(search(head, num) != NULL) //查找
cout << num << "在链表中" << endl;
else
cout << num << "不在链表中" << endl;
delete_chain(head); //释放无序链表空间
cout << "释放了无序链表" << endl;//改进
cout << "---------------" << endl;
head = create_sort();//创建一条升序链表
cout << "完成" << endl;
print(head); //打印创建好的升序链表
delete_chain(head); //释放升序链表空间
cout << "释放了升序链表" << endl;
return 0;
}
欢迎大家在下方积极留言(✪ω✪)