数据结构之链表
一、定义--离散存储【链表】
n个节点离散分配;彼此通过指针相连;每个节点只有一个前驱节点,
每个节点只有一个后续节点;首节点没有前驱节点,尾节点没有后续节点。
二、专业术语:
首节点:第一个有效节点
尾节点:最后一个有效节点
头节点:第一个有效节点前面的那个节点;头节点不存放有效数据;
加上头节点是为了方便对链表的操作
头指针:指向头节点的指针变量
尾指针:指向尾节点的指针变量
三、分类:单链表;双链表;循环链表;非循环链表
四、代码
#include<stdio.h> #include<malloc.h> #include<stdlib.h> typedef struct node{ int data; //数据域 struct node * pNext; //指针域 }NODE,* PNODE; //NODE等价于struct node;PNODE等价于 struct node * PNODE init_link(void); void traverse_link(PNODE pHead); bool is_empty(PNODE pHead); int length_link(PNODE pHead); bool insert_link(PNODE pHead,int pos,int val); bool del_link(PNODE pHead,int pos,int * val); bool sort_link(PNODE pHead); int main(void) { //首先创建头节点 PNODE pHead = NULL; //一个指针只需一个参数,即头节点即可确定下来。 int val; int * pVal = &val; //用来接收删除的节点数据 pHead = init_link(); if(is_empty(pHead)) { printf("数组为空。。。\n"); }else{ printf("数组不为空。。。\n"); } printf("数组长度为:%d\n",length_link(pHead)); traverse_link(pHead); insert_link(pHead,3,333); traverse_link(pHead); if(del_link(pHead,4,pVal)) { printf("链表节点删除成功,你删除的节点数据是:%d 。\n",*pVal); }else{ printf("链表节点删除失败!"); } sort_link(pHead); traverse_link(pHead); return 0; } PNODE init_link(void) { int i; int len; //链表有效长度 int val; //临时存放用户数据 printf("请输入链表有效长度:len= "); scanf("%d",&len); PNODE pHead = (PNODE)malloc(sizeof(NODE)); if(pHead == NULL) { printf("内存分配失败,程序终止\n"); exit(-1); } PNODE pTail = pHead; //设置一个尾指针,永远指向尾节点,方便新节点pNew挂在后面 pTail->pNext = NULL; for(i=0;i<len;i++) { printf("请输入第 %d 个节点的值:",i+1); scanf("%d",&val); PNODE pNew = (PNODE)malloc(sizeof(NODE)); if(pNew == NULL) { printf("内存分配失败,程序终止\n"); exit(-1); } pNew->data = val; pTail->pNext = pNew; pNew->pNext = NULL; pTail = pNew; } return pHead; } void traverse_link(PNODE pHead) { PNODE p = pHead->pNext; //第一个有效节点 while(p!=NULL) { printf("%d ",p->data); p = p->pNext; } printf("\n"); } bool is_empty(PNODE pHead) { PNODE p = pHead->pNext; if(p==NULL) return true; else return false; } int length_link(PNODE pHead) { int cnt=0; PNODE p = pHead->pNext; while(p!=NULL) { cnt++; p = p->pNext; } return cnt; } bool insert_link(PNODE pHead,int pos,int val) { int i=0; PNODE p = pHead; while(p!=NULL && i<pos-1) { p = p->pNext; i++; } if(p==NULL || i>pos-1) return false; PNODE pNew = (PNODE)malloc(sizeof(NODE)); if(pNew==NULL) { printf("动态内存分配失败!\n"); exit(-1); } pNew->data = val; PNODE q = p->pNext; p->pNext = pNew; pNew->pNext = q; return true; } bool del_link(PNODE pHead,int pos,int * pVal) { int i=0; PNODE p = pHead; while(p->pNext!=NULL && i<pos-1) { p = p->pNext; i++; } //经过while循环,p此时指向pos位置前面那个节点 if(p->pNext==NULL || i>pos-1) return false; PNODE q = p->pNext; //q即为pos位置处的节点 *pVal = q->data; //删除pos位置的节点 p->pNext = p->pNext->pNext; free(q); //释放内存,防止内存泄漏。 q = NULL; return true; } /* 何为算法: 狭义的算法是与数据的存储方式密切相关的; 广义的算法是与数据的存储方式无关的; 泛型: 利用某种技术达到的效果就是:针对不同的存储方式,执行的操作是一样的 */ bool sort_link(PNODE pHead) { int i,j,temp; //数组中定义的参量 PNODE p,q; //链表中定义的参量 for(i=0,p = pHead->pNext;i<length_link(pHead)-1;i++,p=p->pNext) for(j=i+1,q=p->pNext;j<length_link(pHead);j++,q=q->pNext) if(p->data<q->data) //等价于a[i]<a[j] { temp = q->data; //等价于a[i] = a[j]; q->data = p->data; //a[j] = a[i]; p->data = temp; //a[i] = temp; } }
运行结果:
五、数组与链表优缺点对比
数组(元素类型相同,大小相等):
优点:存取速度很快;
缺点:插入删除速度很慢;空间通常有限制;事先需要知道数组长度;需要大块内存块
链表:
优点;空间没有限制;插入删除元素很快
缺点:存取速度慢