链表
说明:链表也是一种线性表,但与顺序表不同,它在内存中并不是连续一段连续的内存,而是将存储单元分布在内存的任意地址上,由每个结点中的指针域连接起来
1.单链表
- 建立链表
- 链表合并
- 链表插入(头插、尾插、指定位插入)
- 链表排序
- 链表结点删除
2.双链表
- 建立
- 合并
- 插入(头插、尾插、指定位插入)
- 排序
- 链表结点删除
单链表代码
#include<iostream>
using namespace std;
typedef int Elemtype;
//定义链表结构
typedef struct node
{
Elemtype data; //数据域
struct node* next; //指针域
}LNode,* LinkList;
//函数区域
//生成大小为size的链表,并在生成过程中赋值
LinkList CreatLinkList(int size);
//头插入
void HeadInsert(LinkList& headnode, Elemtype data);
//尾插入
void TailInsert(LinkList& node, Elemtype data);
//指定位置插入
void InserLink(LinkList& headnode, Elemtype data, int n);
//销毁链表
void DirstLink(LinkList& HeadNode);
//int main()
//{
// LinkList p = CreatLinkList(5),k;
// k = p;
// InserLink(k, 3, 3);
// InserLink(k, 5, 5);
// InserLink(k, 6, 6);
// while (k != NULL)
// {
// cout << k->data << " ";
// k = k->next;
// }
//
// return 0;
//}
// 生成大小为size的链表并返回链表首地址
LinkList CreatLinkList(int size)
{
LinkList p, q, list = NULL;
p = q = NULL;
Elemtype data;
for (int i = 0; i < size; i++)
{
cin >> data;
p = new LNode;
p->data = data;
p->next = NULL;
if (list == NULL) //第一次赋值时将首地址赋给list
{
list = p;
}
else //之后的赋值都是通过q来向后增加空间
{
q->next = p;
}
q = p;
}
return list; //将首地址返回
}
// 链表头插入
void HeadInsert(LinkList& headnode, Elemtype data)
{
LinkList p = new LNode;
p->data = data;
p->next = NULL;
p->next = headnode; //先将新的空间连在headnode结点的前面
headnode = p; //然后把headnode的指向转为p
}
//链表尾插入
void TailInsert(LinkList& node, Elemtype data)
{
LinkList p = new LNode;
p->data = data;
p->next = NULL;
if (node == NULL) //判断链表是否为空链表
node = p;
else
{
LinkList q = node; //非空链表则找到最后一个空间
while (q->next != NULL) //最后一个空间的特征是它的指针域为空
{
q = q->next;
}
q->next = p; //将最后一个空间与要插入的空间连起来
}
}
//将数据插入到第n位
void InserLink(LinkList& headnode, Elemtype data, int n)
{
if (n <= 0) //判断插入的位置是否合法
{
cout << "插入位置非法!" << endl;
exit(0);
}
int i = 1;
LinkList p = headnode, r = NULL; //定义p来指向头结点
while (i != n) //通过循环找到第n个位置的结点
{
r = p; //r是p前一个结点
p = p->next;
i++;
}
if (p == headnode) //如果恰好插入到第一个
{
HeadInsert(headnode, data);
}
else
{ //不是插入到第一个
LinkList s = new LNode;
s->data = data;
s->next = NULL;
r->next = s; //令第n个结点的前一个结点r指向新结点s
s->next = p; //再令s的下一个为第n个结点p
}
}
//销毁链表
void DirstLink(LinkList& HeadNode)
{
LinkList p = HeadNode;
while (p != NULL) //通过循环进行每一个结点的内存释放
{
LinkList q = p;
p = p->next;
delete q;
}
HeadNode = NULL; //释放完后首指针指向NULL
}
双链表代码
#include<iostream>
using namespace std;
typedef int Elemtype;
//双向链表结构
typedef struct node
{
int data;
struct node* next, * last;
}LNode,*Link;
//链表生成
Link CreatLink(int size);
//头插入
void HeadInsert(Link& headnode, Elemtype data);
//尾插入
void TailInsert(Link& node, Elemtype data);
//任意插入
void InsertLink(Link& node, Elemtype data, int n);
//删除指定结点
void DelNode(Link& node, int n);
//销毁链表
void DirstLink(Link& node);
//int main()
//{
// Link p = CreatLink(2);
//
// InsertLink(p, 99, 1);
// InsertLink(p, 99, 2);
// InsertLink(p, 99, 4);
// DelNode(p, 1);
// DelNode(p, 1);
// DelNode(p, 2);
// Link q = p;
// while (q != NULL)
// {
// cout << q->data << " ";
// q = q->next;
// }
//
//
//
// return 0;
//}
//生成大小为size的链表并存入数据
Link CreatLink(int size)
{
Link p, q, list = NULL;
p = q = NULL;
for (int i = 0; i < size; i++) //存入size次数据
{
Elemtype data;
cin >> data;
p = new LNode;
p->data = data;
p->last = p->next = NULL; //将每次中间过程的空间在生成的时候都前后指针置空
if (list == NULL) //防止后面忘记而出现访问空指针
{
list = p; //如果list指针为空说明是第一次开辟空间
} //因此将首地址赋给list
else
{ //如果不是第一次开辟空间
q->next = p; //将空间q的后指针域指向它后面的空间p
p->last = q; //将空间p的前指针域指向前面的空间q
}
q = p; //令q向后移动一次
}
return list;
}
//链表头插入
void HeadInsert(Link& headnode,Elemtype data)
{
if (headnode == NULL) //如果插入时头结点为空将对头结点进行空间赋值
{
headnode = new LNode;
headnode->data = data;
headnode->last = headnode->next = NULL;
}
else
{ //头结点不为空则将新结点前指针域置空,后指针域指向
Link p = new LNode; //之前的头结点
p->data = data;
p->last = NULL;
p->next = headnode;
headnode->last = p;
headnode = p; //再令指向之前的头结点的指针移动到新生成的结点
}
}
//链表尾插入
void TailInsert(Link& node,Elemtype data)
{
Link q = node;
while (q->next != NULL) //遍历链表找到最后一个结点q
{
q = q->next;
}
Link p = new LNode;
p->data = data;
p->next = NULL;
p->last = q; //将p的前指针域连上q
q->next = p; //将q的后指针域连上p
}
//将数据插入到链表指定位置n
// 1<= n <=max
//如果 n>max则会插入到链表尾
void InsertLink(Link& node, Elemtype data, int n)
{
if (n <= 0) //判断插入的地方是否在范围内
{
cout << "插入位置非法!" << endl;
exit(0);
}
else
{
int i = 1;
Link p = new LNode, q = node, r = node;
while (i != n && q!= NULL &&r!= NULL) //找到插入的位置n的结点
{
r = q; //r始终是q的前一个结点
q = q->next;
i++;
}
p->data = data;
p->last = p->next = NULL;
if (n == 1) //如果是链头则与头插入一样
{
p->next = node;
node->last = p;
node = p;
}
else if (q == NULL) //q==NULL则表明插入到链尾
{
if(r!=NULL)
r->next = p;
p->last = r;
}
else
{ //插入的不是链头也不是链尾
p->next = q; //要将 p 插入到 r q的中间
q->last = p; //先让p的后面连上q
p->last = r; //再让q的前面连上p
r->next = p; //再让p的前面连上r,r的后面连上p
}
}
}
//删除第n个结点
// 1<= n <=max
void DelNode(Link& node, int n)
{
if (n <= 0) //要删除的结点位置必须合法
{
exit(0);
}
else
{
int i = 1;
Link q = node;
while (i != n && q != NULL) //定义i来寻找第n个结点
{ //删除最后一个结点
q = q->next;
i++;
}
if (n == 1) //如果删除的结点是首结点
{
Link p = node; //记住首结点的地址
node = node->next; //令首结点的指针指向第二个结点,因此第二个结点成为了首结点
node->last = NULL;
delete p; //释放首结点
}
else if (q == NULL) //q为NULL说明删除的第n个结点已经超过了链表已有数量,因此异常退出
{
exit(0);
}
else if(q->next == NULL) //q的next为空,说明此时q为最后的结点
{
q->last->next = NULL; //将q的前一个结点的next置为NULL再删除q结点即可
delete q;
}
else //q此时既不是首结点已不是尾结点,并且在链表中
{
q->last->next = q->next; //将q结点的前一个结点的next指向q的下一个结点
q->next->last = q->last; //将q结点的后一个结点的last指向q的前一个结点
delete q; //这样就完成了q的前后结点重新连接,q进行释放
}
}
}
//链表销毁
void DirstLink(Link& node)
{
Link p = node, r = NULL;
while (p != NULL)
{
r = p; //r始终是p的前一个结点,p更新到下一个结点时就可以对r,即p的前一个结点进行释放
p = p->next;
delete r;
}
node = NULL; //最后将链表首地址指向NULL
}