1.单链表定义
每个节点包括一个数据域一个指针域,节点在内存中地址可以不连续,但是节点内部地址必然连续。
2.结构定义
typedef struct Lnode{
int data;
struct Lnode *next;
}Lnode,*LinkList;
3.单链表的创建
1)头插法
//头插法建立带头结点的单链表
LinkList create1(LinkList &L){
Lnode *s;
int x;
L=(LinkList) malloc( sizeof(Lnode));//创建头结点
L->next = NULL; //初始化
printf("往链表中添加数据,99999结束\n");
scanf("%",&x);
while(x!=99999){
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d",&x);
}
return L;
}
2)尾插法
//尾插法建立单链表
LinkList create2(LinkList &L){
int x;
L=(LinkList) malloc( sizeof(Lnode));//创建尾结点
Lnode *s,*r = L;//S为插入节点指针,r为尾指针
printf("往链表中添加数据,99999结束\n");
//scanf("%",&x);
while(x!=99999){
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
scanf("%d",&x);
s->data = x;
r->next = s;
r = s; //r指向新的表尾
}
r->next = NULL;//尾节点指针置空
return L;
}
4.单链表的查找
1)按值查找
//按值查找表节点,返回节点位序,查找失败返回-1
int locateElem(LinkList L, int e){
Lnode *P = L->next;
int j=1;
while (P!=NULL&&P->data!=e){
P = P->next;
j++;
}
if(P->next == NULL && P->data == e)
return j;
else if(P->next != NULL && P->data == e)
return j;
else
return -1;
}
//按值查找表节点,返回节点指针,这是方便链表运算实现
Lnode *locateElem2(LinkList L, int e){
Lnode *P = L->next;
while (P!=NULL&&P->data!=e){
P = P->next;
}
return P;//失败则返回空指针
}
2)按序号查找
//按序号查找表节点,返回节点值
int getElem(LinkList L,int i){
int j = 1;
Lnode *P = L->next;
if(i==0)
return 0;//如果i=0,则返回头结点的值,但头结点不存值故返回0
if(i<0)
return -1;//错误序号则返回-1
while(P&&j<i)//P非空
{
P= P->next;
j++;
}
return P->data;
}
//按序号查找表节点,返回节点指针,这是方便链表运算实现
Lnode *getElem1(LinkList L, int i){
int j = 1;
Lnode *P = L->next;
if(i==0)
return L;//如果i=0,则返回头结点
if(i<0)
return NULL;//错误序号则返回NULL
while(P&&j<i)//P非空
{
P= P->next;
j++;
}
return P;
}
4.单链表表长
int getLength(LinkList L){
int count = 0;
while(L->next->next!=NULL)//此处指针因人而异,思想就是尾节点指针为空结束循环
{
L = L->next;
count ++;
}
return count;
}
5.插入节点
//插入节点算法1(后插,前插一般不考虑)
//指定位置插入节点
int insertElem1(LinkList L,int i,int e){
if (i<=1||i>getLength(L))
{
return 0;
}
else
{
Lnode *s,*p;
p = getElem1(L,i-1);//获取插入位置前驱
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
s->data = e;
s->next = p->next;//此句和下面那句代码不可颠倒,单链表只可找到后继,所以后继指针不能被先覆盖
p->next = s;
return 1;
}
}
//插入节点算法2
//只交换数据,不改变指针,在已知节点位置的基础上这个是最优算法
int insertElem2(LinkList L,int i,int e){
int temp;
if (i<=1||i>getLength(L))
{
return 0;
}
else
{
Lnode *s,*p;
p = getElem1(L,i);//获取插入位置前驱
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
s->data = e;
s->next = p->next;
p ->next = s;
temp = p->data;//这里做个数据交换
p->data = s->data;
s->data = temp;
return 1;
}
}
6.完整代码
#include <stdio.h>
#include <stdlib.h>//malloc函数头文件
//单链表定义
typedef struct Lnode{
int data;
struct Lnode *next;
}Lnode,*LinkList;
//头插法建立带头结点的单链表
LinkList create1(LinkList &L){
Lnode *s;
int x;
L=(LinkList) malloc( sizeof(Lnode));//创建头结点
L->next = NULL; //初始化
printf("往链表中添加数据,99999结束\n");
scanf("%",&x);
while(x!=99999){
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d",&x);
}
return L;
}
//尾插法建立单链表
LinkList create2(LinkList &L){
int x;
L=(LinkList) malloc( sizeof(Lnode));//创建尾结点
Lnode *s,*r = L;//S为插入节点指针,r为尾指针
printf("往链表中添加数据,99999结束\n");
//scanf("%",&x);
while(x!=99999){
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
scanf("%d",&x);
s->data = x;
r->next = s;
r = s; //r指向新的表尾
}
r->next = NULL;//尾节点指针置空
return L;
}
//求单链表表长
int getLength(LinkList L){
int count = 0;
while(L->next->next!=NULL)
{
L = L->next;
count ++;
}
return count;
}
//按序号查找表节点,返回节点值
int getElem(LinkList L,int i){
int j = 1;
Lnode *P = L->next;
if(i==0)
return 0;//如果i=0,则返回头结点的值,但头结点不存值故返回0
if(i<0)
return -1;//错误序号则返回-1
while(P&&j<i)//P非空
{
P= P->next;
j++;
}
return P->data;
}
//按序号查找表节点,返回节点指针,这是方便链表运算实现
Lnode *getElem1(LinkList L, int i){
int j = 1;
Lnode *P = L->next;
if(i==0)
return L;//如果i=0,则返回头结点
if(i<0)
return NULL;//错误序号则返回NULL
while(P&&j<i)//P非空
{
P= P->next;
j++;
}
return P;
}
//按值查找表节点,返回节点位序,查找失败返回-1
int locateElem(LinkList L, int e){
Lnode *P = L->next;
int j=1;
while (P!=NULL&&P->data!=e){
P = P->next;
j++;
}
if(P->next == NULL && P->data == e)
return j;
else if(P->next != NULL && P->data == e)
return j;
else
return -1;
}
//按值查找表节点,返回节点指针,这是方便链表运算实现
Lnode *locateElem2(LinkList L, int e){
Lnode *P = L->next;
while (P!=NULL&&P->data!=e){
P = P->next;
}
return P;//失败则返回空指针
}
//插入节点算法1(后插,前插一般不考虑)
//指定位置插入节点
int insertElem1(LinkList L,int i,int e){
if (i<=1||i>getLength(L))
{
return 0;
}
else
{
Lnode *s,*p;
p = getElem1(L,i-1);//获取插入位置前驱
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
s->data = e;
s->next = p->next;//此句和下面那句代码不可颠倒,单链表只可找到后继,所以后继指针不能被先覆盖
p->next = s;
return 1;
}
}
//插入节点算法2
//只交换数据,不改变指针,在已知节点位置的基础上这个是最优算法
int insertElem2(LinkList L,int i,int e){
int temp;
if (i<=1||i>getLength(L))
{
return 0;
}
else
{
Lnode *s,*p;
p = getElem1(L,i);//获取插入位置前驱
s = (Lnode*)malloc(sizeof(Lnode));//创建新节点
s->data = e;
s->next = p->next;
p ->next = s;
temp = p->data;//这里做个数据交换
p->data = s->data;
s->data = temp;
return 1;
}
}
int main(){
LinkList L,L1;
/*
create1(L);
LinkList temp = L->next;
while(temp->next != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("头插法与存数据的顺序相反\n");
*/
create2(L1);
LinkList temp2 = L1->next;
while(temp2 ->next != NULL)
{
printf("%d ", temp2->data);
temp2 = temp2->next;
}
printf("尾插法与存数据的顺序相同\n");
int length;
length = getLength(L1);
printf("单链表长度为:%d\n",length);
/*
printf("输入取值位序\n");
int i;
scanf("%d",&i);
printf("第%d位值为%d\n",i, getElem(L1,i));
printf("输入查找值\n");
int e;
scanf("%d",&e);
printf("值为:%d位序为:%d\n",e, locateElem(L1,e));
*/
//插入节点算法1
/*
int x1,x2;
printf("插入节点算法1\n");
printf("插入位置:");
scanf("%d",&x1);
printf("插入值:");
scanf("%d",&x2);
int desert = insertElem1(L1,x1,x2);
if(desert == 1)
{
printf("插入成功\n");
LinkList temp3 = L1->next;
}
else
{
printf("插入失败,位置不合法\n");
}
printf("打印链表(插入算法1)\n");
LinkList temp3 = L1->next;
while(temp3 ->next != NULL)
{
printf("%d ", temp3->data);
temp3 = temp3->next;
}
*/
//插入节点算法2
int x3,x4;
printf("插入节点算法2\n");
printf("插入位置:");
scanf("%d",&x3);
printf("插入值:");
scanf("%d",&x4);
int desert1 = insertElem2(L1,x3,x4);
if(desert1 == 1)
{
printf("插入成功\n");
LinkList temp4 = L1->next;
}
else
{
printf("插入失败,位置不合法\n");
}
printf("打印链表(插入算法2)\n");
LinkList temp4 = L1->next;
while(temp4 ->next != NULL)
{
printf("%d ", temp4->data);
temp4 = temp4->next;
}
return 0;
}
7.小结
单链表作为链表中最简单的一种,摆脱了顺序表对空间的束缚,可以很好的支持动态操作。但是其问题也很明显,每个节点只能找到其直接后继,而找不到其前一节点。在查找时需要从表头开始遍历表,会增加时间复杂度。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。