目录
一、单链表定义
单链表是用“链式存储”(存储结构)实现了“线性结构”(逻辑结构),一个节点存储一个数据元素,各个节点间的先后关系用一个指针表示,它的优点显著,不要求大片连续的空间,改变容量方便,但是不可以随机存取,要消耗一定的空间存放指针,单链表有带头结点和不带头结点两种形式,带头结点的在使用过程中更为出色,本文重点介绍带头结点的形式。
二、单链表的操作
2.1初始化操作
typedef struct LNode
{
int data;
struct LNode* next;
}LNode,*LinkList;
//初始化一个单链表
bool InitList(LinkList & L)
{
L = new LNode;
if (L == NULL)
{
return false;
}
L->next = NULL;
cout << "单链表初始化完成" << endl;
return true;
}
int main()
{
LinkList L; //声明一个指向单链表的指针
InitList(L);
}
以上三段代码块,第一段我们定义了一个LNode的结构体,包含了数据域和指向下一个节点的指针域,在末尾处我们定义了一个指向这个结构体的指针,并且在第三段我们声明了它为L,将它传给了第二段进行初始化。
在第二段我们首先在LNode单链表上使用new关键字申请了一块空间并且让L指向它,下面我们进行了判空操作,接着L->next = NULL;是使单链表的指针域为空的操作。
2.2传值操作
//单链表的传值
LinkList Chuan(LinkList& L)
{
int x;
L = new LNode;
LinkList s, r = L;
cout << "请传值,输入-1退出输值" << endl;
cin >> x;
while (x != -1)
{
LinkList s = new LNode;
s->data = x;
r->next = s;
r = s;
cin >> x;
}
r->next = NULL;
return L;
}
这里我们重点介绍while循环里的语句块,首先我们创建的s和r指针都是指向头结点的,下图中的第一个形态,接着由s指向一块新开辟的空间,并且使它的数据域为我们输入的x,对应下图的第二个形态,接着使r所指的头节点的指针域指针指向s所指向的新开辟的空间,最后使r等于s,即使r也指向s所指向的新开辟的空间,接着继续cin,直到我们的数据输入-1(这里可以改成任何你想要的数据)退出传值。
2.3单链表的插入
//单链表插入
bool Cha(LinkList& L)
{
int i, e;
cout << "请输入要插入的位序及数据" << endl;
cin >> i >> e;
if (i < 1)
{
return false;
}
LNode* p; //指针p指向当前扫描到的节点
int j = 0; //当前p指向的是第几个节点
p = L; //L指向头节点,头结点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{
return false;
}
LNode* s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
cout << "元素插入完成" << endl;
return true;
}
关于上述代码的理解主要有两个方面。
第一块是while循环里的代码块,这里的主要目的是让我们创造的p指针指向我们要插入位序的上一个节点,p本来指向位序为0号的头结点,j记录p当前的指向,在while循环里我们让p指针进行移动至我们要插入位序的上一号节点。这里最好画图帮助我们来理解记忆。
第二块便是最下面我们的具体插入操作,我们new一个新的空间,使s指向它,将我们要插入的数据e存入这里的数据域,下面我们改变s的next指针指向下一个节点,上一个p的next指针指向s指向的那个节点,下图希望帮助理解。
2.4单链表的删除
bool Shan(LinkList& L,int &e)
{
int i;
cout << "请输入要删除的位序" << endl;
cin >> i;
if (i < 1)
{
return false;
}
LNode* p; //指针p指向当前扫描到的节点
int j = 0; //当前p指向的是第几个节点
p = L; //L指向头节点,头结点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{
return false;
}
LNode* q = p->next;
e = q->data;
p->next = q->next;
cout << "数据删除完成" << endl;
return true;
}
这里的while循环的作用和插入操作的作用一样,这里不再赘述。我们直接看到下面删除的具体操作,这里我们用新建指针q指向我们要删除位序的那个节点,用e来替换抹除原来在这里的数据,最后让p的next指针跨过删除位序的节点直指被删除位序的下一个节点。
2.5单链表的查找操作
//单链表的查找
LNode* GetElem(LinkList & L)
{
int i;
cout << "请输入要查找数据的位序";
cin >> i;
if (i < 0)
{
return NULL;
}
LNode* p;
int j = 0;
p = L;
while (p != NULL && j < i)
{
p = p->next;
j++;
}
cout << "您查找的数据为" << p->data << endl;
return p;
}
其实我们上面的while循环的语句块就已经实现了按位查找的操作,只不过我们找到的是上一位罢了,同理我们要想找到我们要的这一位,使“j<i-1”变为“j<i”即可。再次强调画图帮助我们理解,我写的批注只能提供一些启示。
三、完整代码
#include<iostream>
using namespace std;
typedef struct LNode
{
int data;
struct LNode* next;
}*LinkList;
//初始化一个单链表
bool InitList(LinkList & L)
{
L = new LNode;
if (L == NULL)
{
return false;
}
L->next = NULL;
cout << "单链表初始化完成" << endl;
return true;
}
//单链表的传值
LinkList Chuan(LinkList& L)
{
int x;
LinkList s, r = L;
cout << "请传值,输入-1退出输值" << endl;
cin >> x;
while (x != -1)
{
LinkList s = new LNode;
s->data = x;
r->next = s;
r = s;
cin >> x;
}
r->next = NULL;
return L;
}
//打印单链表
void Printt(LinkList L)
{
cout << "当前单链表为" <<endl;
LNode* p;
p = L;
L = NULL;
while (p != NULL)
{
cout << p->data << "->";
p = p->next;
}
cout << "NULL" << endl;
}
//单链表插入
bool Cha(LinkList& L)
{
int i, e;
cout << "请输入要插入的位序及数据" << endl;
cin >> i >> e;
if (i < 1)
{
return false;
}
LNode* p; //指针p指向当前扫描到的节点
int j = 0; //当前p指向的是第几个节点
p = L; //L指向头节点,头结点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{
return false;
}
LNode* s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
cout << "元素插入完成" << endl;
return true;
}
//单链表删除
bool Shan(LinkList& L,int &e)
{
int i;
cout << "请输入要删除的位序" << endl;
cin >> i;
if (i < 1)
{
return false;
}
LNode* p; //指针p指向当前扫描到的节点
int j = 0; //当前p指向的是第几个节点
p = L; //L指向头节点,头结点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
if (p == NULL)
{
return false;
}
LNode* q = p->next;
e = q->data;
p->next = q->next;
cout << "数据删除完成" << endl;
return true;
}
//单链表的查找
LNode* GetElem(LinkList & L)
{
int i;
cout << "请输入要查找数据的位序";
cin >> i;
if (i < 0)
{
return NULL;
}
LNode* p;
int j = 0;
p = L;
while (p != NULL && j < i)
{
p = p->next;
j++;
}
cout << "您查找的数据为" << p->data << endl;
return p;
}
//求表的长度
int Length(LinkList L)
{
int len = 0;
LNode* p = L;
while (p->next != NULL)
{
p = p->next;
len++;
}
return len;
}
int main()
{
LinkList L; //声明一个指向单链表的指针
int e = 0;
InitList(L);
Chuan(L);
Printt(L);
GetElem(L);
Cha(L);
Printt(L);
Shan(L, e);
Printt(L);
cout << "表的长度为" << Length(L) << endl;
system("pause");
return 0;
}
脚印,它标志着自己走过的路。我宁愿曲折,不愿在某处徘徊。成长的道路,必须有承受挫折的勇气,唯有播种努力与汗水,才能收获成功与快乐。