目录
2.1 知识点复习
线性表的值特性:数据元素必须 同类型、有限、有序
重要术语:表长、空表、表头、表尾、前驱、后继、位序(1开始)、下标(0开始)
基本操作:创建、销毁、增删改查(在结点前还是结点后?)、判断空表、长度、打印输出等等
存储/物理结构:顺序存储、链式存储(单链表、双链表、循环链表、静态链表)
2.2 代码+注释
快速定位:
功能 | 声明/函数体 行 | 功能 | 声明/函数体 行 | |
结构体定义 | 6/6 | 头插建表 | 23/120 | |
判断是否空表 | 16/33 | 增(第x个结点前) | 25/130 | |
求表长 | 17/38 | 增(第x个结点后) | 27/212 | |
输出链表数据 | 18/47 | 增(值x的结点前) | 26/171 | |
查(第x个结点值) | 19/58 | 增(值x的结点后) | 28/237 | |
查(值为x的结点) | 20/75 | 删(第x个结点) | 30/264 | |
尾插建表 | 22/101 | 删(值为x的结点) | 31/284 |
代码:
一些地方的合理性判断有略去,需要的可以自行添上。加注释的代码有点乱,后面有贴上无注释的版本的。水平有限,欢迎留言交流
#include<stdio.h>//null要用大写 NULL,不然会报错
#include<stdlib.h>//malloc的头文件
#include<iostream>//c++头文件,是为了c++使用输入输出语句,可以用printf、scanf替代cout、cin
using namespace std;//和c++ <iostream>配套的
struct Link{
int data;
struct Link* next;
}*Lhead=NULL,*Lnode,*Lnext;
/*头结点Lhead不存数据,只是为了操作方便;空表判断:head->next==null?
头结点Lhead不存数据,只是为了操作方便;空表判断:head->next==null?
Lnode:创建时,代表目前链表内存在的最新的结点
Lnext:创建时,代表即将加入链表的结点(即下一个结点)
struct {}结尾要用分号 ;
*/
bool isvoid(Link *t);//判空
int Getlength(Link *t);//表长
void print(Link *t);//打印
Link* Getdata_index(Link *t,int i);//查,第 i 个结点值
void Getdata_value(Link *t,int i);//查,值为 i 的结点位序
void init_tail(Link* &t,int x,int d);//尾插建表
void init_head(Link* &t,int x,int d);//头插建表
void add_before_index(Link* &t,Link* insert,int i);//增,第 i 个结点前插
void add_before_value(Link* &t,Link* insert,int i);//增,值为 i 的结点前插
void add_follow_index(Link* &t,Link* insert,int i);//增,第 i 个结点后插
void add_follow_value(Link* &t,Link* insert,int i);//增,值为 i 的结点后插
void deletenode_index(Link* &t,int i) ;//删,删第 i 个结点
void deletenode_value(Link* &t,int value);//删,删值为 i 的结点
bool isvoid(Link *t){//判断是否空表 ,true=void,false=not void
if(t==NULL)
return true;
return false;
}
int Getlength(Link *t){
if(isvoid(t)) return 0;//空表
int len=0;
while(t!=NULL){
len++;
t=t->next;
}
return len;
}
void print(Link *t){//从表头开始输出
cout<<"当前链表内容:";//
if(isvoid(t)){
cout<<"空表"<<endl;return ;
}
while(t!=NULL){
cout<<t->data<<" ";
t=t->next;
}
cout<<endl;
}
Link* Getdata_index(Link *t,int i){//根据位序查找,get第 i 个结点的值
int index=1;//位序是从1开始的,下标是从0开始的,这里用index代表位序
printf(" 查找第%d个结点的值,结果是:",i);
if(isvoid(t)){
cout<<"空表"<<endl;return NULL;
}
while(t!=NULL){//有查找的余地
if(index==i){
cout<<t->data<<endl;
return t; //找到了就结束
}else{
t=t->next;
index++;
}
}
cout<<"超出链表范围"<<endl; return NULL;
}
void Getdata_value(Link *t,int i){//根据结点值查找,get结点的值为 i 的结点位序
int index=1;//位序是从1开始的,下标是从0开始的,这里用index代表位序
int flag=0; //是否有符合条件的结点存在
printf(" 查找结点值为%d的结点位序是:",i);
if(isvoid(t)){
cout<<"空表"<<endl;return ;
}
while(t!=NULL){//有查找的余地
if(t->data==i){
cout<<index<<" ";//不结束的原因是,可能有多个结点符合条件
flag=1;
}
t=t->next;
index++;
}
if(flag==0)
{cout<<"不存在"<<endl;}
else cout<<endl;
}
/*用尾插法,顺序建表,输入data顺序和生成链表的数据顺序一样
函数两种写法:
一、使用指针返回值,main中引用的时候应该为 xx=init_tail(...);
二、使用 & ,最后可以不返回
*/
//Link* init_tail(Link* t,int x,int d){//写法一
void init_tail(Link* &t,int x,int d){//写法二 (链表,长度,值)如果自己输入值的话,可以去掉 d,下面加输入语句
while(x--){//
Lnext=(Link *)malloc(sizeof(Link));
Lnext->data=d;
Lnext->next=NULL;//NULL一定要大写
if(Lhead==NULL)//创建了第一个结点
Lhead=Lnode=Lnext;//头结点和链表内的最新结点都是Lnext
else
Lnode->next=Lnext;//让之前的最新结点next指针指向新建立的结点,二者链接
Lnode=Lnext;//之前的最新结点 更新 成新加入的结点
d++;
}
// //辅助输出,检查创建结果
// cout<<"init:";
// print(Lhead);//输出,查看创建结果: “1 2 3 4 5 6 7 8 9 10 ”
t=Lhead;//最后回到 t ,不要忘记了!!!
// return t;//写法一、记得把指针返回回去
}
void init_head(Link* &t,int x,int d){
while(x--) {
Lnext=(Link *)malloc(sizeof(Link));
Lnext->data=d;
Lnext->next=t;
t=Lnext;
d++;
}
}
void add_before_index(Link* &t,Link* insert,int i) {/*在已有的第 i个结点前面,插入新结点,t是要进行操作的链表,insert是要加入的新结点*/
// printf("1 %p\n",insert->next);//注释一、检查插入结点的next指针地址
Link* headtemp=(Link*)malloc(sizeof(Link));//Q2.1
headtemp=t; //Q2.1
/*Q2:为什么要再来一个headtemp?
A2:因为这里用的是 &t,对它的改变是“永久”的,headtemp和 t指向同一地址,但是headtemp的挪动不影响 t的值,如果直接用t,头结点的地址会发生改变
而前面的void print(...)就不会有这个问题
验证:把 Q2.1换成注释状态,之后(运行注释二代码,再把本函数内的headtemp替换成 t),比较两种情况的运行结果
PS:能正确运行的是Q2.1*/
// printf("1tou t=%p",t);//注释二、辅助检查,检查表头指针地址
// printf("1tou t=%p,headtemp=%p\n\n",t,headtemp);//Q2.1
printf("值%d插在第%d个结点前:\n",insert->data,i);
cout<<" 旧:"; print(headtemp);
i=i-1;//在第i个结点前面=在第i-1个结点后面,所以遍历到第 i-1个结点就可以操作了
int num=1;//
int len=Getlength(headtemp);
//接下来判断插入的位置是否合理
if(i>len||i<0||len==0){//超出表的范围 OR 空表
cout<<" 新:add error"<<endl;
return;
}else if(i==0){//插在原本的表头前面
insert->next=t;
// printf("2 %p",insert->next);//注释一、检查插入结点的next指针地址
t=insert;
}else{//插在表中间
while(headtemp!=NULL){//
if(num==i){
insert->next=headtemp->next;
headtemp->next=insert;
}
headtemp=headtemp->next;
num++;
}
}
//输出检查
cout<<" 新:"; print(t);
// printf("2tou t=%p\n\n",t);//注释二、辅助检查,检查表头指针地址
// printf("2tou t=%p,headtemp=%p\n\n",t,headtemp);//Q2.1辅助检查,检查表头指针地址
}
void add_before_value(Link* &t,Link* insert,int i) {/*在已有的第index个结点前面,插入新结点,t是要进行操作的链表,insert是要加入的新结点*/
//设定:有data==i 就插,可以插多个,只考虑插值,不考虑指针地址
printf("在值%d前插%d的结果是:",i,insert->data);
cout<<endl<<" 旧:"; print(t);
if(isvoid(t)){
cout<<"空表 error"<<endl;return;
}
Link* headtemp=(Link *)malloc(sizeof(Link));//上一个结点
headtemp=t;
Link* copy= (Link *)malloc(sizeof(Link));
copy->data=insert->data;//复制值
copy->next=NULL;
int flag=0; //是否存在符合条件的结点
if(t->data==i){//先把表头解决了
flag=1;
copy->next=t;
t=copy;
headtemp=headtemp->next; //往下挪一个结点,否则会出现第一个结点前重复插入
// cout<<"first ";//辅助输出检查
// print(t);
}
while(headtemp->next!=NULL){//NULL
if(headtemp->next->data==i){
flag=1;
Link* copy2= (Link *)malloc(sizeof(Link)); //每用一个都要重新malloc = 在硬件上申请一个地址给指针存放数据用,不申请就没地方放
copy2->data=insert->data; //复制值
copy2->next=headtemp->next; //这两句顺序不能颠倒,若先执行headtemp->next=copy,指向其原后继的指针就不存在,
headtemp->next=copy2;// 然后copy->next=headtemp 相当于的copy->next=copy,显然错误
headtemp=copy2->next;//画图感受一下,这里的结点关系
}else headtemp=headtemp->next;//简单的往下挪
}
cout<<" 新:"; print(t);
if(flag==0)
cout<<"不存在"<<endl;
}
void add_follow_index(Link* &t,Link* insert,int i) {//
Link* headtemp=(Link*)malloc(sizeof(Link));
headtemp=t;
int num=1,len=Getlength(t);
printf("值%d插在第%d个结点后:\n",insert->data,i);
cout<<" 旧:"; print(headtemp);
if(i>len||i<0||len==0){//超出表的范围 OR 空表
cout<<" 新:add error"<<endl;
return;
}
while(headtemp!=NULL){
if(num==i&&headtemp->next!=NULL){//不在表尾
insert->next=headtemp->next;
headtemp->next=insert;
}else if(num==i&&headtemp->next==NULL){//在表尾
headtemp->next=insert;
break;
}
headtemp=headtemp->next;
num++;
}
cout<<" 新:"; print(t);
}
void add_follow_value(Link* &t,Link* insert,int i) {
//设定:有data==i 就插,可以插多个,只考虑插值,不考虑指针地址
printf("在值%d后插%d的结果是:",i,insert->data);
cout<<endl<<" 旧:"; print(t);
if(isvoid(t)){
cout<<"空表 error"<<endl;return;
}
Link* headtemp=(Link *)malloc(sizeof(Link));//当前结点
headtemp=t;
int flag=0; //是否存在符合条件的结点
while(headtemp!=NULL){//NULL
if(headtemp->data==i){
flag=1;
Link* copy2= (Link *)malloc(sizeof(Link)); //每用一个都要重新malloc = 在硬件上申请一个地址给指针存放数据用,不申请就没地方放
copy2->data=insert->data; //复制值
copy2->next=headtemp->next; //这两句顺序不能颠倒,若先执行headtemp->next=copy,指向其原后继的指针就不存在,
headtemp->next=copy2;// 然后copy->next=headtemp 相当于的copy->next=copy,显然错误
}
headtemp=headtemp->next;//简单的往下挪
}
cout<<" 新:"; print(t);
if(flag==0)
cout<<"不存在"<<endl;
}
void deletenode_index(Link* &t,int i) {//
cout<<"删除第"<<i<<"个结点:"<<endl;
cout<<" 旧:";print(t);
if(i==1){
//新建一个结点=头结点
t=t->next;
//释放上面建的结点,这个过程略
}
else{
cout<<" ";
Link* front_node=Getdata_index(t,i-1);
cout<<" ";
Link* node=Getdata_index(t,i);
front_node->next=front_node->next->next;
free(node);
}
cout<<" 新:";print(t);
}
void deletenode_value(Link* &t,int value) {//
//删除第一个data等于value的结点
//把下面删除多个的,修改一下,遇到第一个符合条件的直接结束
//删除所有data等于value的结点
cout<<"删除值="<<value<<"的结点:"<<endl;
cout<<" 旧:";print(t);
//如果第一个结点data=value
if(t->data==value){
//释放过程略
t=t->next;
}
Link* temp=(Link*)malloc(sizeof(Link));
temp=t;
while(temp->next->next!=NULL)//头部和中间
{
if(temp->next->data==value)
{
Link* node=(Link*)malloc(sizeof(Link));
node=temp->next;
temp->next=temp->next->next;
temp=temp->next->next;
free(node);
}
else temp=temp->next;
}
if(temp->next->data==value)
temp->next=NULL;//释放过程略
cout<<" 新:";print(t);
}
int main(){
int x=10;//限定结点个数,方便用while创建
int d=1;//用顺序数填充数据域,通过输出便于观察头插尾插效果
//尾插建表
Link* tailLink=(Link*)malloc(sizeof(Link));//tail:尾部的意思
// tailLink=init_tail(tailLink,x,d);//尾插,写法一
init_tail(tailLink,x,d);//尾插,写法二
print(tailLink);//输出,查看创建结果 “1 2 3 4 5 6 7 8 9 10 ”
//头插建表
Link* headLink=(Link*)malloc(sizeof(Link));
headLink=NULL;
init_head(headLink,x,d);
print(headLink);
//查找,根据位序OR元素值查找
Getdata_index(tailLink,2);
Getdata_index(tailLink,11);
Getdata_value(tailLink,5);
Getdata_value(tailLink,12);
//
int addop[]={1,5,19,-1,Getlength(tailLink)};
//根据位序扦插, 在第 i 个结点前插入某个结点
for(int i=0;i<sizeof(addop)/sizeof(int)-1;i++){//addbefore
/*Q1:为什么使用循环?运行注释一的代码,看它们的输出,
发现 指针addtemp在运行过程中会被修改,所以每次操作需要重新malloc */
Link* addtemp=(Link*)malloc(sizeof(Link));
addtemp->data=99;
addtemp->next=NULL;
add_before_index(tailLink,addtemp,addop[i]);
cout<<" 表长:"<<Getlength(tailLink)<<endl;
}
//根据位序后插,在第 i 个结点后插入某个结点
for(int i=0;i<sizeof(addop)/sizeof(int);i++){//addfollow
Link* addtemp=(Link*)malloc(sizeof(Link));
addtemp->data=100;
addtemp->next=NULL;
add_follow_index(tailLink,addtemp,addop[i]);
cout<<" 表长:"<<Getlength(tailLink)<<endl;
}
//前插,在拥有某个特定元素值的结点后面插入某个结点
Link* addtemp=(Link*)malloc(sizeof(Link));
addtemp->data=101;
addtemp->next=NULL;
add_before_value(tailLink,addtemp,99);
//后插,在拥有某个特定元素值的结点后面插入某个结点
Link* addtemp2=(Link*)malloc(sizeof(Link));
addtemp2->data=200;
addtemp2->next=NULL;
add_follow_value(tailLink,addtemp2,101);
//删除,根据结点位序删除,删除第 i个结点
deletenode_index(tailLink,1);
deletenode_index(tailLink,5);
deletenode_index(tailLink,Getlength(tailLink));
//删除,根据结点值删除,删除第 i个结点
deletenode_value(tailLink,Getdata_index(tailLink,1)->data);
deletenode_value(tailLink,Getdata_index(tailLink,5)->data);
deletenode_value(tailLink,Getdata_index(tailLink,Getlength(tailLink))->data);//因为表长一直在变化,表尾的话直接调用函数求
return 0;
}
2.3 纯代码
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
struct Link{
int data;
struct Link* next;
}*Lhead=NULL,*Lnode,*Lnext;
bool isvoid(Link *t);//判空
int Getlength(Link *t);//表长
void print(Link *t);//打印
Link* Getdata_index(Link *t,int i);//查,第 i 个结点值
void Getdata_value(Link *t,int i);//查,值为 i 的结点位序
void init_tail(Link* &t,int x,int d);//尾插建表
void init_head(Link* &t,int x,int d);//头插建表
void add_before_index(Link* &t,Link* insert,int i);//增,第 i 个结点前插
void add_before_value(Link* &t,Link* insert,int i);//增,值为 i 的结点前插
void add_follow_index(Link* &t,Link* insert,int i);//增,第 i 个结点后插
void add_follow_value(Link* &t,Link* insert,int i);//增,值为 i 的结点后插
void deletenode_index(Link* &t,int i) ;//删,删第 i 个结点
void deletenode_value(Link* &t,int value);//删,删值为 i 的结点
bool isvoid(Link *t){
if(t==NULL)
return true;
return false;
}
int Getlength(Link *t){
if(isvoid(t)) return 0;
int len=0;
while(t!=NULL){
len++;
t=t->next;
}
return len;
}
void print(Link *t){
cout<<"当前链表内容:";
if(isvoid(t)){
cout<<"空表"<<endl;return ;
}
while(t!=NULL){
cout<<t->data<<" ";
t=t->next;
}
cout<<endl;
}
Link* Getdata_index(Link *t,int i){
int index=1;
printf(" 查找第%d个结点的值,结果是:",i);
if(isvoid(t)){
cout<<"空表"<<endl;return NULL;
}
while(t!=NULL){
if(index==i){
cout<<t->data<<endl;
return t;
}else{
t=t->next;
index++;
}
}
cout<<"超出链表范围"<<endl; return NULL;
}
void Getdata_value(Link *t,int i){
int index=1;
int flag=0;
printf(" 查找结点值为%d的结点位序是:",i);
if(isvoid(t)){
cout<<"空表"<<endl;return ;
}
while(t!=NULL){
if(t->data==i){
cout<<index<<" ";
flag=1;
}
t=t->next;
index++;
}
if(flag==0)
{cout<<"不存在"<<endl;}
else cout<<endl;
}
void init_tail(Link* &t,int x,int d){
while(x--){
Lnext=(Link *)malloc(sizeof(Link));
Lnext->data=d;
Lnext->next=NULL;
if(Lhead==NULL)
Lhead=Lnode=Lnext;
else
Lnode->next=Lnext;
Lnode=Lnext;
d++;
}
t=Lhead;
}
void init_head(Link* &t,int x,int d){
while(x--) {
Lnext=(Link *)malloc(sizeof(Link));
Lnext->data=d;
Lnext->next=t;
t=Lnext;
d++;
}
}
void add_before_index(Link* &t,Link* insert,int i) {
Link* headtemp=(Link*)malloc(sizeof(Link));
headtemp=t;
printf("值%d插在第%d个结点前:\n",insert->data,i);
cout<<" 旧:"; print(headtemp);
i=i-1;
int num=1;
int len=Getlength(headtemp);
if(i>len||i<0||len==0){
cout<<" 新:add error"<<endl;
return;
}else if(i==0){
insert->next=t;
t=insert;
}else
while(headtemp!=NULL){
if(num==i){
insert->next=headtemp->next;
headtemp->next=insert;
}
headtemp=headtemp->next;
num++;
}
}
cout<<" 新:"; print(t);
}
void add_before_value(Link* &t,Link* insert,int i) {
printf("在值%d前插%d的结果是:",i,insert->data);
cout<<endl<<" 旧:"; print(t);
if(isvoid(t)){
cout<<"空表 error"<<endl;return;
}
Link* headtemp=(Link *)malloc(sizeof(Link));
headtemp=t;
Link* copy= (Link *)malloc(sizeof(Link));
copy->data=insert->data;
copy->next=NULL;
int flag=0;
if(t->data==i){
flag=1;
copy->next=t;
t=copy;
headtemp=headtemp->next;
}
while(headtemp->next!=NULL){
if(headtemp->next->data==i){
flag=1;
Link* copy2= (Link *)malloc(sizeof(Link));
copy2->data=insert->data;
copy2->next=headtemp->next;
headtemp->next=copy2;
headtemp=copy2->next;
}else headtemp=headtemp->next;
}
cout<<" 新:"; print(t);
if(flag==0)
cout<<"不存在"<<endl;
}
void add_follow_index(Link* &t,Link* insert,int i) {//
Link* headtemp=(Link*)malloc(sizeof(Link));
headtemp=t;
int num=1,len=Getlength(t);
printf("值%d插在第%d个结点后:\n",insert->data,i);
cout<<" 旧:"; print(headtemp);
if(i>len||i<0||len==0){
cout<<" 新:add error"<<endl;
return;
}
while(headtemp!=NULL){
if(num==i&&headtemp->next!=NULL){
insert->next=headtemp->next;
headtemp->next=insert;
}else if(num==i&&headtemp->next==NULL){
headtemp->next=insert;
break;
}
headtemp=headtemp->next;
num++;
}
cout<<" 新:"; print(t);
}
void add_follow_value(Link* &t,Link* insert,int i) {
printf("在值%d后插%d的结果是:",i,insert->data);
cout<<endl<<" 旧:"; print(t);
if(isvoid(t)){
cout<<"空表 error"<<endl;return;
}
Link* headtemp=(Link *)malloc(sizeof(Link));
headtemp=t;
int flag=0;
while(headtemp!=NULL){
if(headtemp->data==i){
flag=1;
Link* copy2= (Link *)malloc(sizeof(Link));
copy2->data=insert->data;
copy2->next=headtemp->next;
headtemp->next=copy2;
}
headtemp=headtemp->next;
}
cout<<" 新:"; print(t);
if(flag==0)
cout<<"不存在"<<endl;
}
void deletenode_index(Link* &t,int i) {
cout<<"删除第"<<i<<"个结点:"<<endl;
cout<<" 旧:";print(t);
if(i==1){
t=t->next;
}
else{
cout<<" ";
Link* front_node=Getdata_index(t,i-1);
cout<<" ";
Link* node=Getdata_index(t,i);
front_node->next=front_node->next->next;
free(node);
}
cout<<" 新:";print(t);
}
void deletenode_value(Link* &t,int value) {
cout<<"删除值="<<value<<"的结点:"<<endl;
cout<<" 旧:";print(t);
if(t->data==value){
t=t->next;
}
Link* temp=(Link*)malloc(sizeof(Link));
temp=t;
while(temp->next->next!=NULL)
{
if(temp->next->data==value)
{
Link* node=(Link*)malloc(sizeof(Link));
node=temp->next;
temp->next=temp->next->next;
temp=temp->next->next;
free(node);
}
else temp=temp->next;
}
if(temp->next->data==value)
temp->next=NULL;
cout<<" 新:";print(t);
}
int main(){
int x=10;
int d=1;
Link* tailLink=(Link*)malloc(sizeof(Link));
init_tail(tailLink,x,d);
print(tailLink);
//头插建表
Link* headLink=(Link*)malloc(sizeof(Link));
headLink=NULL;
init_head(headLink,x,d);
print(headLink);
//查找,根据位序OR元素值查找
Getdata_index(tailLink,2);
Getdata_index(tailLink,11);
Getdata_value(tailLink,5);
Getdata_value(tailLink,12);
//
int addop[]={1,5,19,-1,Getlength(tailLink)};
//根据位序扦插, 在第 i 个结点前插入某个结点
for(int i=0;i<sizeof(addop)/sizeof(int)-1;i++){//addbefore
/*Q1:为什么使用循环?运行注释一的代码,看它们的输出,
发现 指针addtemp在运行过程中会被修改,所以每次操作需要重新malloc */
Link* addtemp=(Link*)malloc(sizeof(Link));
addtemp->data=99;
addtemp->next=NULL;
add_before_index(tailLink,addtemp,addop[i]);
cout<<" 表长:"<<Getlength(tailLink)<<endl;
}
//根据位序后插,在第 i 个结点后插入某个结点
for(int i=0;i<sizeof(addop)/sizeof(int);i++){//addfollow
Link* addtemp=(Link*)malloc(sizeof(Link));
addtemp->data=100;
addtemp->next=NULL;
add_follow_index(tailLink,addtemp,addop[i]);
cout<<" 表长:"<<Getlength(tailLink)<<endl;
}
//前插,在拥有某个特定元素值的结点后面插入某个结点
Link* addtemp=(Link*)malloc(sizeof(Link));
addtemp->data=101;
addtemp->next=NULL;
add_before_value(tailLink,addtemp,99);
//后插,在拥有某个特定元素值的结点后面插入某个结点
Link* addtemp2=(Link*)malloc(sizeof(Link));
addtemp2->data=200;
addtemp2->next=NULL;
add_follow_value(tailLink,addtemp2,101);
deletenode_index(tailLink,1);
deletenode_index(tailLink,5);
deletenode_index(tailLink,Getlength(tailLink));
deletenode_value(tailLink,Getdata_index(tailLink,1)->data);
deletenode_value(tailLink,Getdata_index(tailLink,5)->data);
deletenode_value(tailLink,Getdata_index(tailLink,Getlength(tailLink))->data);
return 0;
}