单链表的基本操作
在线性表的顺序存储结构中,往往存在着插入和删除需要移动大量的结构。这将极大的耗费时间。那么有没有方法可以解决这个问题呢,当然答案是有的嘛!
采用链式存储结构。
链式存储结构
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着,这些数据元素可以存在内存中未被占用的任意位置上。
相较于顺序结构,只需要存储数据的元素信息就可以了。而链式结构中,除了要存储数据元素信息外,还要存储它的后继元素的存放地址。但这一代价所带来的好处是可观。
通常,把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称为指针或链。这两部分信息(数据域+指针域)组成数据元素的存储映像,称为结点。
而n个结点链结成一个链表,即为线性表的链式存储结构。
一般链表中第一个结点的存储位置叫做头指针。
线性链表的最后一个结点指针为空
而在单链表的第一个结点前附设一个结点,称为头结点。头结点的数据域不存储任何信息。
单链表的常规操作定义
void initList(listLink L);//链表初始化
void createList_H(listLink L);//头插法 链表实现
void createList_R(listLink L);//尾插法 链表实现
bool listInsert(listLink L, int i, elemType e);//链表后插
bool listInsertFront(listLink L, int i, elemType e);//链表前插
bool listDelete(listLink L, int i, elemType* e);//链表删除
bool getListElem(listLink L, int i, elemType* e);//获取链表中第i个位置中的元素的值
bool searchListElem(listLink L, int* i, elemType e);//查找链表中的元素位置
void printList(listLink L);//遍历链表,并打印出来
void clearList(listLink L);//删除整张链表
单链表的存储结构
struct ListNode
{
int val;
ListNode* next;
//结点的构造函数
//对val next进行初始化,省去重复定义初始化函数的苦恼
ListNode() :val(0), next(nullptr) {}
ListNode(int x) :val(x), next(nullptr) {}
ListNode(int x, ListNode* next) :val(x), next(next) {}
};
单链表初始化
//初始化链表
void initList(listLink L)
{
L->next = nullptr;
}
单链表创建的两种方式
//使用头插法建立链表
void createList_H(listLink L)
{
cout << "请输入要建立的结点数目" << endl;
int num;
listLink lTemp;
cin >> num;
if (num <= 0)
{
cout << "输入的数目有误,必须>0" << endl;
}
else
{
for (int i = 0; i < num; i++)
{
lTemp = new ListNode;
cout << "请输入第" << i + 1 << "个结点的值" << endl;
cin >> lTemp->val;
//结点插入在头部
lTemp->next = L->next;
L->next = lTemp;
}
}
}
//使用尾插法创建链表
void createList_R(listLink L)
{
cout << "请输入要建立的结点数目" << endl;
int num;
listLink lTemp, rTemp;
cin >> num;
//rTemp指向尾部结点的指针
rTemp = L;
if (num <= 0)
{
cout << "输入的数目有误,必须>0" << endl;
}
else
{
for (int i = 0; i < num; i++)
{
lTemp = new ListNode();
cout << "请输入第" << i + 1 << "个结点的值" << endl;
cin >> lTemp->val;
lTemp->next = nullptr;
//结点插入在尾部
rTemp->next = lTemp;
rTemp = lTemp;
}
}
}
单链表中插入值的两种方式
//在链表的指定位置上插入一个值,在链表L的第i-1个位置后,插入e元素
bool listInsert(listLink L, int i, elemType e)
{
int j = 1;
listLink p;
//当p=L时,其指向的是L的头结点,头结点不含值
//当p=L->next,其指向的是L的第一个结点。
p = L;
while (p->next && j < i)
{
//递增j,直到找到第i个结点,或者p指向链表的尾部
p = p->next;
j++;
}
if (!p || j > i)
{
cout << "第" << i << "个结点不存在";
return 0;
}
listLink s = new ListNode;
s->val = e;
//将结点s插入到第i-1个结点之后。
s->next = p->next;
p->next = s;
return 1;
}
bool listInsertFront(listLink L, int i, elemType e)
{
int j = 0;
listLink p;
p = L;
while (p->next && j < i)
{
//递增j,直到找到第i个结点,或者p指向链表的尾部
p = p->next;
j++;
}
if (!p || j > i)
{
cout << "第" << i << "个结点不存在";
return true;
}
listLink s = new ListNode;
s->next = p->next;
s->val = p->val;
p->next = s;
p->val = e;
return true;
}
单链表删除指定位置的值
//删除链表中指定位置的结点
bool listDelete(listLink L, int i, elemType* e)
{
int j = 1;
listLink p, q;
//当p=L时,其指向的是L的头结点,头结点不含值
//当p=L->next,其指向的是L的第一个结点。
p = L;
while (p->next && j < i)
{
//递增j,直到找到第i个结点,或者p指向链表的尾部
p = p->next;
j++;
}
if (!(p->next) || j > i)
{
cout << "第" << i << "个结点不存在";
return false;
}
q = p->next;
p->next = q->next;
//将要删除的结点保存
*e = q->val;
delete q;
return true;
}
单链表查询某个位置的值
bool getListElem(listLink L, int i, elemType* e)
{
int j = 0;
listLink p;
p = L;
while (p->next && j < i)
{
//递增j,直到找到第i个结点,或者p指向链表的尾部
p = p->next;
j++;
}
if (!p || j > i)
{
cout << "第" << i << "个结点不存在";
return true;
}
*e = p->val;
return true;
}
单链表搜索某个值第一次出现的位置
//查找链表中第一个出现的e的位置
bool searchListElem(listLink L, int* i, elemType e)
{
int position = 1;
//p不能指向头结点
listLink p = L->next;
while (p)
{
if (p->val == e)
{
*i = position;
return true;
}
//p指向下一个结点
position++;
p = p->next;
}
return false;
}
单链表清除整张链表
//删除整张链表
void clearList(listLink L)
{
listLink p, q;
p = L->next;
while (p)
{
q = p->next;
delete p;
p = q;
}
L->next = nullptr;
}
单链表遍历输出每个结点的位置和值
//遍历输出链表中各个结点的值
void printList(listLink L)
{
//头结点为空,跳过头结点
//p指向当前链表头结点的下一个位置
listLink p = L->next;
int i = 0;
while (p)//当p不为空,一直执行
{
i++;
cout << "链表的第" << i << "个值" << p->val << endl;
p = p->next;
}
if (!(L->next))
{
cout << "当前并没有链表" << endl;
}
}
程序运行的主函数
int main()
{
int elem, position;
listLink L;
L = new ListNode;
initList(L);
createList_H(L);
cout << "使用头插法遍历出来的数据" << endl;
printList(L);
cout << endl;
listInsert(L, 2, 33);
cout << "尾插结点后的链表" << endl;
printList(L);
cout << endl;
listInsertFront(L, 2, 40);
cout << "前插结点后的链表" << endl;
printList(L);
cout << endl;
listDelete(L, 2, &elem);
cout << "删除结点后的链表" << endl;
printList(L);
cout << endl;
cout << "删除的结点的值为:" << elem << endl;
cout << endl;
getListElem(L, 3, &elem);
cout << "第3个结点的值是:" << elem << endl;
cout << endl;
cout << "请输入要查找的结点的值";
cin >> elem;
searchListElem(L, &position, elem);
cout << "链表中的结点值为" << elem << "的位置是位于第" << position << "个" << endl;
cout << endl;
cout << "删除整张链表" << endl;
clearList(L);
printList(L);
cout << endl;
listLink H;
H=new ListNode;
initList(H);
createList_R(H);
cout << "使用尾插法遍历出来的数据" << endl;
printList(H);
}