单链表(线性表链式存储)
1.单链表初始化(结点存放数据元素和下个结点指针)
1.1定义一个带头结点的单链表:
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode* next;
}LNode,*link_list;//强调是单链表用linklist,强调是节点用LNode*
bool InitList ( link_list &L ){//链表初始化
L = ( LNode* )malloc(sizeof(LNode) );//申请一个头结点空间
if( L==NULL )//内存不足,分配失败
return false;
L->next==NULL;//头结点之后没有节点
return true;
}
bool isEmpty( link_list L){//判断链表是否为空
return (L == NULL);
}
int main( int argc, char const*argv[] )
{}
1.2定义一个不带头结点的单链表
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode *next;
}LNode, *LinkList;
bool InitList( LinkList &L ){
L = NULL;//头指针不指向任何结点,空表
return true;
}
2.单链表的插入
2.1按位序插入
2.1.1按位序插入(带头结点)
typedef struct LNode{
int data;
struct LNode* next;
}LNode, *LinkList;
bool InsertList (LinkList &L, int i, int e){//单链表L第i位置插入元素e
if( i<1 )//位置非法
return false;
LNode* p = L;//指针p指向当前扫描到的结点,L为头结点
int j = 0;//j为扫描到第几个结点
if( p!=NULL && j<i-1 ){//扫描结点不为空且没有到i位置
p = p->next;
j++;
}
if( p == NULL )//i值不合法,如共有三个元素,要往第十个位置插
return false;
LNode* s = (LNode*)malloc(sizeof(LNode) );//申请空节点存元素e
s->data = e;
s->next = p->next;//先连后断
p->next = s;
return true;
}
2.1.2按位序插入(不带头结点)
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode* next;
}LNode, *LinkList; //LNode*与LinkList相同
//不带头节点的单链表按位序插入
bool Insertlist( LinkList &L, int i, int e){
if(i<1)
return false;
if(i==1){
LNode *s = (LNode*)malloc( sizeof(LNode) );
s->data = e;
s->next = L; //新结点指针s->next指向头指针L指的结点,即原本的第一个结点
L = s; //头指针指向新插入的第一个结点
return true;
}
LNode* p;
p = L;
int j = 1;
while( p!=NULL && j<i-1 ){
j++;
p = p->next;
}
if(p==NULL)
return false;
LNode*s = (LNode*)malloc( sizeof(LNode) );
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
int main(){
}
2.2指定结点的后插操作
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode* next;
}LNode, *LinkList;
//指定结点的后插操作
bool InsertNextNode( LNode*p, int e ){
if(p==NULL)//指定结点为空时返回false
return false;
LNode* s = (LNode*)malloc(sizeof(LNode) );//申请空结点存传入值e
if(s==NULL)//申请空间失败
return false;
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
2.3指定结点的前插操作
还有一种思路是:传入头结点,遍历找到前插位置的前驱结点,再进行后插。
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode* next;
}LNode, *LinkList;
情况一://给定值情况(需要申请内存)
bool InsertPriorNode ( LNode* p, int e ){//给定值情况
if( p==NULL )//如果指定结点为空则错误
return false;
LNode* s = (LNode*)malloc( sizeof(LNode) );
if(s==NULL)//分配内存失败
return NULL;
s->next = p->next;
p->next = s;
s->data = p->data;//偷天换日
p->data = e;
return true;
}
情况二://直接给指针(需要定义临时变量)
bool InsertPriorNode ( LNode*p, LNode*s ){
if( p==NULL || s==NULL )
return false;
s->next = p->next;
p->next = s;
int temp = p->data;//申请零时变量存指定结点数据域
p->data = s->data;
s->data = temp;
return true;
}
3.单链表的结点删除操作
3.1按位序删除
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode {
int data;
struct LNode*next;
}LNode, *LinkList;
传入链表(即链表的头指针)、指定位置、e返回被删值
bool ListDelete ( LinkList &L, int i, int e ){
if(i<1)
return false;
LNode* p = L;//定义扫描指针
int j = 0;//记录位置
while( p!=NULL && j<i-1 ){//删第i个,找第i-1个
p = p->next;
j++;
}
if(p==NULL)//i值非法
return false;
if(p->next == NULL)//指定位置为空
return false;
LNode*q = p->next;//定义一个指针指向位置i,即指定删除位置
e = q->data;
p->next = q->next;
free(q);//不要忘记释放删除的结点
return true;
}
3.2删除指定结点
此段代码有bug,应该从头遍历找到指定结点的前驱结点
bool LinkListDelete( LNode*p ){
if( p==NULL )
return false;
LNode* q = p->next;
p->data = p->next->data;//p->next可能为NULL
p->next = q->next;
free(q);
}
4.单链表的查找操作
4.1按位查找
#include<stdio.h>
typedef struct LNode{
int data;
struct LNode *next;
}LNode, *LinkList;
//按位查找
LNode* GetElemlink ( LinkList L, int i ){
if( i<0 )//i<0位置不合法
return NULL;
LNode*p = L;//定义和头指针指向一样结点的指针
int j = 0;
while( p->next != NULL && j<i ){
p = p->next;
j++;
}
return p;
}
4.2按值查找
//按值查找
LNode* LocateElemlink ( LinkList L, int e ){//返回值是指向结点的指针
LNode* p = L->next;//定义指向第一个结点的指针,头结点指的那个结点
while( p != NULL && p->data != e )链表非空且未找到给定值
p = p->next;
return p;返回p
}
4.3求链表长度
#include<stdio.h>
typedef struct LNode{
int data;
struct LNode* next;
}LNode, *LinkList;
int lenthlink (LinkList L){
int len = 0;
LNode*p = L;//定义指针
while( p->next != NULL ){//不为空就加一
p = p->next;
len++;
}
return len;
}
5.单链表的建立
5.1尾插法
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode*next;
}LNode,* LinkList;
//尾插法建立链表
LinkList List_Tailinsert( LinkList &L ){//注意返回值
int x;//局部变量存输入
L = (LinkList)malloc( sizeof(LNode) );//头指针申请头结点
// LNode*s, *r = L;此处写法有误,指针s未初始化
LNode*s = L, *r = L;//这样写才对
scanf("%d",&x);
while( x != 9999 ){
s = (LNode*)malloc(sizeof(LNode) );//给存入数据申请空间
s->data = x;
r->next = s;
r = s;//尾指针保持指向最后一位
scanf("%d",&x);
}
r->next = NULL;//最后结点指向NULL
return L;
}
5.2头插法
对头结点的后插操作
应用:对链表的逆置(1.原地逆置 2.新建链表)
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode*next;
}LNode, *LinkList;
//头插法建立链表
LinkList List_headinsert ( LinkList &L ){//传入,传出都是指针
LNode*s;
int x;
L = (LinkList)malloc(sizeof(LNode) );//创建头结点
L = NULL;//初始化头指针
scanf("%d",&x);
while( x != 9999 ){
s = (LNode*)malloc(sizeof(LNode) );//创建新结点
s->data = x;
s->next = L->next;
L->next = s;//将新结点插入表中,L为头指针
scanf("%d",&x);
}
return L;
}