之前上传了一个单链表的博文,但是在实现上交互性较差,而且在给结点分配空间的时候是使用的malloc函数实现的,今天我们就使用c++中的new关键字来给结点分配内存空间。
话不多说,下面就是关于单链表操作的各个功能的函数。
一、用结构体创建一个结点数据类型
为了能够实现单链表的操作,结点里面主要有两部分,一部分是数据域,存放结点的数据值,另一个是指针域,存放下一个结点的地址。
typedef struct LNode{
int data;
struct LNode *next;
}LNode, *LinkList;
在这里LNode就是我们定义的结点类型,同时我们又声明了*LinkList的类型与LNode是保持一致的,本质上两者没有什么不一样。
二、对列表进行初始化
(1)首先是单纯的进行初始化,这就需要我们去声明一个头结点,用头指针L指向头结点,并且用头结点将指针域设置为空。
void InitList(LinkList &L){
L = new LNode;//生成新结点作为头结点,并且用头指针L指向头结点
L->next = NULL;//头结点的指针域设置为空
(2)如果想要在初始化的同时就对单链表进行数据的输入,那么这里有两种方式来实现。
第一种方式是尾插法,就是在链表的尾部将数据一个一个地插入进去,具体实现如下:
//用尾插法插入数据
void IniList_R(LinkList &L, int n){
L = new LNode; //创建一个新的结点
L->next = NULL; //并且将头结点设置为空
LinkList r; //声明一个尾指针
LinkList p; //声明一个指针p,用于创建新的结点
r = L; //对尾指针r初始化
for (int i=0; i<n; ++i){
cout<<"请输入第"<<i+1<<"个数据:";
p = new LNode;
cin>>p->data;
p->next = NULL;
r->next =p;
r = p;
}
}
三、上面我们完成了单链表的创建并且初始化传入数据,那么我们现在来写一个输出的函数将链表中的元素进行输出。
//输出链表中的所有数据
void showList(LinkList L){
cout<<"链表中的所有元素为:";
while(L->next){
cout<<L->next->data<<" ";
L = L->next;
}
cout<<endl;
}
在这里实际上就是对链表进行了一个遍历,同时需要注意形参是安置传递的,有很多同学往往在这里会按地址传递,导致在程序运行的过程中报错,原因在于当遍历完链表之后,头指针就移动到尾部,此时的链表实质上是一个空表。
四、求单链表的长度
单链表的长度实质上也是对链表进行了一个遍历,只是在遍历的时候对元素的个数进行了统计,具体代码如下。
//求链表的长度
int getLength(LinkList L){
int len = 0;
while(L->next){
len++;
L=L->next;
}
return len;
//cout<<"链表的长度为:"<<endl;
}
其实这里的函数也可以是无返回类型的,就是上面代码注释掉的地方。因为在后面的函数中要使用到这个函数,所以在这里我就定义为int返回类型的函数。
五、插入数据
下面这段代码就是实现单链表的插入,包括了三个形参,第一个是单链表的头指针,注意这里是按地址传递,第二个参数就是位置,第三个参数就是要插入元素的值。
//插入数据
void insertElem (LinkList &L, int i, int e) {
LinkList p = L;
int j = 0;
while(p && (j < j-1)){
p = p->next;
++j;
}
if(!p || j>i-1){
cout<<"输入位置有误!"<<endl;
}
LinkList s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
}
六、删除数据
这里删除数据有两种方式,一种是按照元素的值来删除数据,第二种是按照位置来删除数据。
在删除数据的时候,我们进行判断链表的长度是否为0,也就是链表中是否有元素。
首先是按照元素的值来删除数据。
//按值删除数据
void deleElem_Elem(LinkList &L, int x) { //删除值为x的结点(链表无重复值)
if (getLength(L) <= 0) {
cout << "表空,没有元素可删除" << endl;
return;
}
LinkList p;
LinkList q;
p= L->next;
q = L; //记录ptr的前一个位置的结点
while (p) {
if (p->data == x) {
q->next = p->next; //把x值的结点的前一个结点的next指向p的next结点
free(p); //释放空间
return;
}
q = p;
p = q->next;
}
}
下面是按照位置来删除数据。
//按位置删除数据
void deleElem_Loca(LinkList &L, int Loca){
if (getLength(L) <= 0) {
cout << "表空,没有元素可删除" << endl;
return;
}
LinkList p;
LinkList q;
p= L->next;
q = L; //记录ptr的前一个位置的结点
Loca = Loca - 1; //因为如果k = 1,直接用q->next = p->next就把p删掉了,所以要减1
while (Loca-- && p) {
q = p;
p = p->next;
}
if (p == NULL || Loca > 0) {
cout << "要删除的位置不存在" << endl;
}else {
q->next = p->next; //删除ptr结点
free(p); //释放空间
}
}
七、获取数据
//获取数据
int GetElemList(LinkList &L, int i) { //返回第i个位置的值
LinkList p = L;
int k = i; //标记i的值,以防不存在输出显示
while (i > 0 && p->next) {
p = p->next;
i --;
}
if (i == 0 && p != NULL) { //当i == 0 和 ptr 不为空代表找到了第i个位置的元素
return p->data;
}else {
cout << "第" << k << "个位置不存在" << endl;
return -1;
}
}
八、清空列表
//清空链表
void ClearList(LinkList &L) { //清空链表
LinkList p = L;
if (getLength(L) > 0) {
while (p->next) {
LinkList temp = p->next;
p->next = p->next->next;
free(temp); //释放空间
}
}
}
上面我们完成了单链表的基本功能,下面我们来写一个主函数实现对单链表的操作,为了提高可操作性,我写了一个while循环来实现对单链表的选择操作,具体代码如下:
void main(){
LinkList L;
cout<<"1--输入数据"<<endl;
cout<<"2--删除数据"<<endl;
cout<<"3--获取表长"<<endl;
cout<<"4--输出链表"<<endl;
cout<<"5--插入数据"<<endl;
cout<<"6--查找数据"<<endl;
cout<<"7--清空链表"<<endl;
cout<<"8--退出程序"<<endl;
while (true){
cout<<"请输入功能序号:";
cin>>num;
if (num == 1){
cout<<"请输入要输入数据的个数:";
cin>>num3;
IniList_R(L,num3); //初始化链表
}else if (num == 2){
while (true){
int num2;
cout<<"1--按位置删除数据"<<endl;
cout<<"2--按值删除数据"<<endl;
cout<<"3--退出删除功能"<<endl;
cout<<"请输入你要选择的功能:";
cin>>num2;
if (num2 == 1){
int position;
cout << "请输入要删除的位置: ";
cin >> position;
deleElem_Loca(L, position);
}else if(num2 == 2){
int delem;
cout<<"请输入你要删除的值:";
cin>>delem;
deleElem_Elem(L, delem); //确保链表中没有重复值元素,如果有默认删除第一个出现这个值得元素
}else if(num2 == 3){
break;
}else{
cout<<"数据输入错误";
break;
}
}
}else if(num == 3){
cout<<"表长为:"<<getLength(L)<<endl;
}else if (num == 4){
showList(L);
}else if (num == 5){
int i, data;
cout << "请输入要插入的位置和值:";
cin >> i;
cin >> data;
insertElem(L, i, data);
}else if (num == 6){
int n;
cout << "请输入要查找的位置: ";
cin >> n;
if (GetElemList(L, n) != -1)
cout << "第" << n << "个位置的值为: " << GetElemList(L, n) << endl;
}else if (num == 7){
ClearList(L);
}else if (num == 8){
break;
}else{
cout<<"非法输入!"<<endl;
}
}
}