定义
n个节点离散分配
彼此通过指针相连
每个节点只有一个前驱节点,每个节点只有一个后继节点
首节点没有前驱节点,尾节点没有后续节点
专业术语
链表中每个节点的数据类型是一样的
首节点:链表第一个有效的节点
尾节点:最后一个有效的节点
头节点:第一个有效节点之前的节点,头节点并不存放有效数据
头指针:指向头节点的指针变量
尾指针:指向尾节点的指针变量
确定一个链表只需要一个参数,
只需要头指针,就可以推算列表的其它所有信息
用程序表示每一个节点的数据类型
#include <stdio.h>
typedef struct Node{
int data;//data
struct Node* pNode;//point,指向的每个节点的数据类型一样
}Node,*PNode; //在*和前面是一个整体,Node相当于struc Node,PNode相当于 struct Node *
int main(void){
return 0;
}
链表的分类
单链表
双链表:每个链表有两个指针域
循环列表:能通过任意节点找到其它节点
非循环链表
链表是否为空的判断
思路:判断头节点的指针域是不是为空 p->pNext
求链表的长度
思路:遍历列表,直到找到最后一个指针域为NULL的节点,累计遍历的次数
对链表排序
思路:参考冒泡排序的思路,利用反射技术,可以使链表的排序和数组的排序一样,即
i=0(第一个有效节点的位置)等价于pHead->pNext;i<length-1;i++相当于p->pNext
链表的插入
问题:在a节点(指针为p)后面插入一个节点b(指针为q)的伪算法
思路:要在a后面插入,那么a就指向b,由原来的a指向c变为b指向c。q->pNext(b的指针域)存放p->pNext的值,p->pNext(a的指针域)指向存放q的值。
q->pNext=p->pNext
p-pNext=q
链表的删除
问题:把a节点(指针为p)后的b节点删除
思路:即把b节点存放的c的地址给a节点,即 p->pNext=p->pNext->pNext.在java中,这样写是可以的,但是c语言中,内存无法自己释放,此时p->pNext 的值已经改变,找不到b节点的位置了,这种算法会导致内存泄漏。我们可以定义一个r指针来临时存放解决这个问题
伪代码:
p->pNext=p->pNext->pNext(内存泄漏)
r=p->pNext;//(先存放b的地址)
p->pNext=p->pNext->pNext;
free r;//释放内存
链表的创建和链表的遍历算法
生成
生成所有节点(用一个pNew指针指向所有节点,每次循环指向一个节点)
生成一个头节点,把头节点的指针赋给pTail
把新生成的节点做为尾节点,挂在头节点后面,让pTail永远指向pNew(新节点的指针)
遍历
把头节点的指针赋给p,p指向下一个节点,当下一个节点不为空,则继续往下指,当节点为空时,代表走到了尾部。
#include <stdio.h>
#include <malloc.h>
typedef struct Node{
int data;//数据域
struct Node * pNext;//指针域
}NODE ,*PNODE; //NODE 等价于 struct Node PNODE 等价于 struct Node *
//函数声明
PNODE creat_list(void); //创建链表
bool isNull(PNODE pHead);//判断链表是否为空
void traverse_list(PNODE pHead);//遍历输出链表
int length(PNODE pHead);//求链表长度
void sort(PNODE,int ,int);//对链表排序:冒泡排序
int main(void){
int i;
PNODE pHead = NULL; //等价于 struct Node * PHean = null;
pHead = creat_list();//creat_list():创建一个非循环的单链表,并把头节点的地址赋pHead. //动态内存可以通过在别的函数中分配好在引用
if( isNull(pHead)){
printf("链表不为空\n");
}else {
printf("链表为空\n");
}
traverse_list(pHead);
i = length(pHead);
printf("链表的长度是%d\n",i);
return 0;
}
PNODE creat_list(void){
int len;//节点个数
int i;
int val;//节点值
//为头节点分配内存
PNODE pHead=(PNODE)malloc(sizeof(NODE));
if(NULL==pHead){
printf("分配内存失败,程序终止!");
}
//定义一个指向头指针
PNODE pTail=pHead;
pTail->pNext=NULL;
printf("请输入需要生成的链表节点的个数,len=");
scanf("%d",&len);
for( i=0;i<len;i++){
printf("请输入第%d个节点的值:",i+1);
scanf("%d",&val);
//为每个节点分配内存
PNODE pNew = (PNODE)malloc(sizeof(NODE));
if(NULL==pHead){
printf("分配内存失败,程序终止!");
}
pNew->data=val;//用一个指针指向所有的节点。注意:每次pNew都指向不同的节点
pTail->pNext=pNew;//pNew挂到pTail后面
pNew->pNext = NULL;//把新节点设为尾部节点
pTail=pNew;//pTail永远指向尾节点
}
return pHead;
}
void traverse_list(PNODE pHead){
PNODE p=pHead->pNext;//指向头节点的下一个有效节点
while(NULL!=p){
printf("%d ",p->data);
p=p->pNext;
}
printf("\n");
}
bool isNull(PNODE pHead){
if(NULL==pHead->pNext){
return false;
}
return true;
}
int length(PNODE pHead){
int i = 0;
PNODE P=pHead->pNext;
while(NULL!=P->pNext){
i++;
P=P->pNext;
}
return i;
}
void sort(PNODE pHead){
int i,j,t;
PNODE q,r;
}
冒泡算法:对一个数组排序(升序)。把第一个元素和第二个元素比较,小的放前面,大的放后面;然后第一个和第三个比较,直到第一个和最后一个比较。以此循环。
代码为:
int i,j,t,length;
for(i=0;i<length-1;i++){//每个元素都需要单独取出来,与后面的元素比较。最后一个不需要取出来比较,故i<length-1
for(j=i+1;j<length;j++){//第i个元素依次和后面的元素比较
if(a[i]>a[j]){
t=a[j];
a[j]=a[i];//交换位置,把大的放后面去
a[i]=t;
}
}
}
算法
遍历
查找
清空
销毁
求长度
排序
删除节点
新增节点
广义的算法和数据的存储方式无关
侠义的算法与数据存储方式密切相关
泛型:利用某种技术达到效果就是:不同的存数方式,执行的操作是一样的