4链表
数组可以当顺序表使用,这个不难。
此处讲解下链表。。。。
复习下
1.是线性表的一种存储形式
2.每个表元素对应链表的一个结点(含值域和链域)
3.值域(value field)用来存储表元素值
4.链域(link field)用来存储相邻结点的地址
5.表尾结点的链域值为空(NULL,即常数0)
6.用首指针(如,变量head)指向第一个结点
7.链表就是表头指针和一串相继链接的结点的总称
结点和指针的类型定义:
typedef int element_type; //值域类型
typedef struct linkednode //结点类型
{ element_type data; //值域
struct linkednode *next; //链域
} snode, *ptr; //结点类型名snode和指针类型名ptr
ptr head,p,q; // 定义指针类型变量
类型struct linkednode * 与类型ptr等价
都是指向snode的指针类型
注意:每一个结点都是一个结构,结点中保存数值、下一结点的地址。头指针千万不可以修改,否则整个链表都将找不到。
构建链表的通用算法:
步骤1)构造“空链表”
步骤2)读入第一个元素值
步骤3)当读入的元素值不是“输入结束标记”时
循环执行步骤4~7
步骤4)申请一个新结点
步骤5)将读入的元素值存入新结点的值域
步骤6)将新结点“插在”链表中
步骤7)读入“下一个”元素值,转步骤3
步骤8)构造完毕,返回首指针
遍历链表的通用算法
步骤1)使访问指针p指向第一个结点
步骤2)当链表没遍历完时,循环执行步骤3和4
步骤3)访问p->
步骤4)p=p->next; //p滑向下一个结点
步骤5)遍历完毕,返回
链表的创建
每一个结点都是动态分配存储:
p=(ptr)malloc(sizeof(snode));
含义:
产生一个结点——动态分配的变量
将结点的地址值转换成ptr类型,赋给指针变量p
若分配失败,返回NULL
NULL是值为0的指针常量,无效地址
p->表示p所指向的结点
p->就是结点名(变量名)
p->data:结点的值域 等价于 (*p).data
p->next:结点的链域 等价于 (*p).next
c++:
一般格式 new 结点类型名;
语句 :
p=new snode;
等价于 p=newsnode();
也等价于 p=(ptr)malloc(sizeof(snode));
链表的插入
链表的删除
链表的遍历
q=head
while(q->next)
{
q=q->next;
}
q为遍历指针,只要q的指针域存在,说明q中有数值,否则q=q->next,q指向下一个结点。
链表的种类:
分类方式:
(1)按结点产生方式
静态
动态
(2)按结点链域个数
单向链表(singly linked lists)
双向链表(doubly linked lists)
(3)按是否带附加结点
纯链表——不带附加结点
加头链表——带附加表头结点
加尾链表——带附加表尾结点
加头尾链表——既带头又带尾
注意:附加结点往往用作监督元结点(存储特殊值)
(4)按是否循环
循环链表(circularly linked lists)
非循环链表
图
链表算法
向前插入法构造简单链表的算法
ptr creatlinkedA( )
{ ptr head, p; element_type x ;
head=NULL; //将表头指针置空
scanf("%d", &x); //读入第一个元素
while (x!=End_elm) //当读的不是结束标记时循环
{ p=new snode; //申请一个存储结点
p->data=x; //置结点的值域
p->next=head; //插在表头处
head=p; //表头指针指向新结点
scanf("%d", &x); //读入下一个元素
}
return(head); //返回表头指针
}
构建1 2 3 0 的链表
head=NULL;
scanf("%d", &x);
while (x!=End_elm)
{ p=new snode;
p->data=x;
p->next=head;
head=p;
scanf("%d", &x);
}
return(head);
向后插入法构造加头链表的算法
ptr creatlinkedB( )
{ ptr head, last,p; element_type x ;
head=last=new snode; //构造空链表
scanf("%d", &x);
while (x!=End_elm)
{ p=new snode;
p->data=x;
last->next=p; //插在表尾
last=p; //修改尾指针
scanf("%d", &x); //读入下一个元素
}
last->next=NULL;
return(head);
}
单向简单链表的输出算法
void outlinkA(ptr p) //p是起始指针
{
printf("链表中的结点序列为:\n");
while(p!=NULL)
{ printf("%5d", p->data);
p=p->next;
}
printf("\n");
}
单向简单链表的查找算法
ptr searchA(ptr p,element_type x)
{ while(p!=NULL)
{ if(p->data==x)return p;//找到x,返回p
p=p->next; //暂时没找到,则继续向后找
}
return NULL; //查找不成功,返回空指针
}
单向加尾链表的查找算法
ptr searchB(ptr p,ptr last,element_type x)
{ last->data=x; //设置监督元
while(p->data!=x )p=p->next;//没找到,继续
if(p!=last)return p; //查找成功
return NULL; //查找不成功
}
源代码:
// List.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define DATA 5
//节点数据类型
typedef struct Node
{
int data;
struct Node* next;
}Node;
//链表类型
typedef struct List
{
Node* head;
}List;
//创建新节点
Node *CreaceNode(int data)
{
Node *PtrNew=(Node*)malloc(sizeof(Node));
PtrNew->data=data;
PtrNew->next=NULL;
return PtrNew;
};
//向头节点插入新节点
void PushHead(List *list,int data)
{
Node* PtrNew1=CreaceNode(data);
PtrNew1->next=list->head;
list->head=PtrNew1;
};
//遍历链表
Node* Travel(List *list)
{
Node *Ptr=list->head;
if(Ptr!=NULL)
while(Ptr)
{
Ptr=Ptr->next;
};
return Ptr;
};
//计算链表的长度
int Length(List *list)
{
int iCount=0;
Node *Ptr=list->head;
if(Ptr!=NULL)
while(Ptr)
{
iCount++;
Ptr=Ptr->next;
};
return iCount;
};
//输入链表的节点数据
void Show(List *list)
{
printf("链表中的数据为:");
int count=0;
Node *findLength=list->head;
if(findLength!=NULL)
while(findLength)
{
printf("%d ",findLength->data);
findLength=findLength->next;
count++;
};
printf("\n");
printf("数据个数为:%d\n",count);
};
//查询链表中某一个数
Node* Find(List *list,int iPos)//传入要查找的位置
{
Node* tempTtr=list->head;
int iCurPos=0;//标记
while(tempTtr->next!=NULL&&iCurPos<iPos)
{
tempTtr=tempTtr->next;
iCurPos++;
};
if(tempTtr!=NULL&&iPos==iCurPos)
{
//printf("你所查找位置的数据为:%d\n",*tempTtr);
return tempTtr;
}
else
{
printf("你要查找的位置超过了范围!\n");
return NULL ;
};
};
//删除某一个节点
int Delete(List *list,int ptr)
{
if(ptr<1||ptr>Length(list))
{
printf("error\n");
return 0;
};
Node *tempPtr;
if(ptr>1)
{
tempPtr=Find(list,ptr-1);//获取要删除的节点的上一节点
Node* nextPtr=tempPtr->next;//获取要删除节点的下一节点
tempPtr->next=nextPtr->next;//使删除节点的上一节点与下下节点相连接
delete nextPtr;//删除节点
}
else
{
tempPtr=list->head;
list->head=tempPtr->next;
delete tempPtr;
};
return 0;
};
//在某一节点前插入一个节点
int AddNode(List *list,int pos)
{
Node* tempPtr=NULL;
Node* temp=NULL;
if(pos<=0||pos>Length(list)+1)
{
printf("error");
return 0;
}
else
{
if(pos>1)
{
tempPtr=Find(list,pos-1);//获取某一位置的前一节点
temp=tempPtr->next;//暂时存放新加节点的后一个节点
Node* newPtr=CreaceNode(5);//创建新节点
tempPtr->next=newPtr;//使上一节点与新节点相连接
newPtr->next=temp;//使新节点与后一节点相连接
}
else
{
Node* newPtr=CreaceNode(5);//创建新节点
temp=list->head->next;
newPtr->next=list->head;
list->head=temp;
};
};
};
int main()
{
List list;
list.head=NULL;
for(int i=1;i<=3;++i)
{
PushHead(&list,i);
Show(&list);
};
Find(&list,3);
Delete(&list,3);
printf("\n");
AddNode(&list,1);
printf("\n");
for(int i=1;i<=3;++i)
{
PushHead(&list,i);
Show(&list);
};
getchar();
return 0;
};