前言:
顺序表可以随时存取表中的任意一个元素,它的存储位置可以用一个简单直观的公式表示,但插入和删除操作需要移动大量元素。链式存储线性表时,不需要使用地址的连续存储单元,即不要求逻辑上相邻元素在物理地址上也相邻,它通过"链"建立起数据元素之间的逻辑关系,因此插入和删除元素操作不需要移动元素,而只需要修改指针,但也会失去顺序表可随机存取的优点
1.定义单链表
typedef struct node
{
int data;
struct node* next; //指针指向下一个节点
}node,*list;
(1)typedef是重定义struct,这样后面可以写node* s = (node*)malloc(sizeof(node)) 来定义新节点,否则就得sturct node* s = (sturct node*)malloc(sizeof(sturct node))
(2)括号后面的node表示是对struct node 的重命名,*list实际上是typedef struct node *list(指向node的指针)
node * L 等价于 list L ,都表示一个指向单链表第一个结点的指针
但是list L 强调这是一个单链表,node*L强调这是一个结点
2.初始化链表
注意头结点不存储数据
bool InitList(list&L) {
L = (node*)malloc(sizeof(node));
if (L == NULL)
return false;
L->next = NULL;
return true;
}
3.按位查找
node* getelem(list L, int i)
{
if (i < 0)
return NULL;
node* p;
int j = 0;
p = L;
while (p != NULL && j < i)
{
p = p->next;
j++;
}
return p;
}
4.按值查找
node* locate(list L, int e)
{
node* p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
5.按位序插入
bool insert(list& L, int i, int e)//i表示插入的位置,e表示插入的元素
{
if (i < 1)
return false;
node* p;//指针p当前扫描到的结点
int j = 0;
p = L;
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
return false;
node* s = (node*)malloc(sizeof(node));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
我们可以利用3.按位查找的代码,将代码修改成这样,封装后使代码更加简洁
bool insert(list& L, int i, int e)//i表示插入的位置,e表示插入的元素
{
node* p = getelem(L, i - 1);
if (p == NULL)
return false;
node* s = (node*)malloc(sizeof(node));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
6.指定结点的前插操作
因为我们不知道目标结点的前一个结点是什么,所以我们有两个办法实现
(1)循坏查找目标结点的前一个结点
(2)在目标结点后增加一个结点s,然后再交换data
代码如下
bool Insert(node* p, int e)
{
if (p == NULL)
return false;
node* s = (node*)malloc(sizeof(node));
if (s == NULL)
//内存分配失败
return false;
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
return true;
}
7.指定结点的删除
本质上是先找到要删除结点的前一个结点,然后"架空"要删除的结点(通过next来实现)
bool Ldelete(list& L, int i, int&e)//用e返回被删除元素的值
{
node* p = getelem(L, i - 1);//找到要删除的结点p
if (p == NULL)
return false;
if (p->next == NULL)
return false;
node* q = p->next;//让q指向被删除的结点
e = q->data;
p->next = q->next;//将*q结点从链表中断开
free(q);
return true;
}
8.尾插
bool weiinsert(list& L, int i,int e)
{
node* p = getelem(L, i - 1);
if (p == NULL)
return false;
node* s = (node*)malloc(sizeof(node));
s->data = e;
s->next = p->next;
p->next = s; //成功将s连到p之后
return true;
}
9.打印链表
void Print(list& L) {
node* p = NULL;
if (!L) { cout << "此链表为空" << endl; return; }
p = L->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
10.销毁链表
void Destroy(list& L) {
node* p = L;
cout << "销毁链表" << endl;
while (p) {
L = L->next; //L指向下一个结点
delete p; //删除当前结点
p = L; //p移向下一个结点
}
}