对链表的相关操作及数据结构的再理解
2013-07-19 00:43
387 查看
结点的操作
由于链表是n个离散结点彼此通过指针相连,所以对链表的相关操作主要通过头指针(存放了头结点的地址)对结点进行操作来实现。
1.如何将q所指向的结点插入到p所指向结点的后面?
有两个方法
第一种: 采用临时变量
r=p->pNext;//用r保存p所指向结点的下一个结点地址
p->pNext=q;//此时p的指针域指向q所指的结点的地址
q->pNext=r;
第二种:不采用临时变量
q-pNext=p->pNext;//让p和q所指向结点的指针域指向后面的同一个结点
p-pNext=q;//再让p的指针域指向q结点
2.如何删除一个节点(思路:用一个临时变量r来保存要删除的结点,再删除p后面的那个结点)
r=p->pNext;
p->pNext=p->pNext->pNext;
free(r);
r=NULL;
3.如何判断链表是否为空(思路:空链表只有一个头结点,所以只需让头结点的指针域为NULL即可)
对链表的相关操作
实例说明:
注意:
1.在vc++中,c编译器不支持bool函数,但c++编译器支持,所以这里我用的是c++编译器。
2.c编译过程中常见错误:illegal use of this type as an expression 是由于c语言不允许临时定义变量,所有定义的变量都必须放在函数开头,这也是c和c++的重要区别
数据结构的再理解
狭义上的理解:数据结构是专门研究数据存储(包括个体的存储和个体关系的存储)问题。
广义上的理解:数据结构既包含数据的存储也包含数据的操作。算法是对存储数据的操作。
算法:
狭义上的理解:算法和数据的存储方式密切相关
广义上的理解:算法和数据的存储方式无关(这就是泛型的思想)
泛型:利用某种技术达到的效果就是不同的存储方式,执行的操作是一样的。泛型主要通过模板,运算符的重载,指针来实现,在c++中经常用到。
补充
线性结构:
连续存储【数组】
优点:存取速度快
缺点:插入删除元素很慢,空间通常是有限制的,事先必须知道数组的长度,而且需要大块连续内存块
离散存储【链表】
优点:插入删除元素很快,空间没有限制的;
缺点: 存取速度很慢
结束语
链表相关操作中,个人感觉较难的是链表的创建,对结点的插入,删除和排序。今天就写到这,明天开始学习线性结构中的两种应用之一 --栈
由于链表是n个离散结点彼此通过指针相连,所以对链表的相关操作主要通过头指针(存放了头结点的地址)对结点进行操作来实现。
1.如何将q所指向的结点插入到p所指向结点的后面?
有两个方法
第一种: 采用临时变量
r=p->pNext;//用r保存p所指向结点的下一个结点地址
p->pNext=q;//此时p的指针域指向q所指的结点的地址
q->pNext=r;
第二种:不采用临时变量
q-pNext=p->pNext;//让p和q所指向结点的指针域指向后面的同一个结点
p-pNext=q;//再让p的指针域指向q结点
2.如何删除一个节点(思路:用一个临时变量r来保存要删除的结点,再删除p后面的那个结点)
r=p->pNext;
p->pNext=p->pNext->pNext;
free(r);
r=NULL;
3.如何判断链表是否为空(思路:空链表只有一个头结点,所以只需让头结点的指针域为NULL即可)
对链表的相关操作
实例说明:
#include<stdio.h> #include<malloc.h> #include<stdlib.h> typedef struct Node { int data;//数据域 struct Node *pNext;//指针域 }NODE,*PNODE; PNODE CreateList();//创建链表 void TraverseList(PNODE);//遍历链表 bool IsEmpty(PNODE);//判断链表是否为空 int Length(PNODE);//求链表长度 bool InsertNode(PNODE,int,int);//插入结点 bool DeleteNode(PNODE,int,int *);//删除结点 bool QueryNode(PNODE,int);//查找结点 bool ModifyNode(PNODE,int,int);//修改结点 void SortList(PNODE);//遍历排序 int main() { PNODE pHead=NULL; pHead=CreateList();//将创建链表的头指针的地址赋给pHead if(0==Length(pHead)) { printf("链表无有效节点,退出程序!\n"); exit(-1); } TraverseList(pHead); if(InsertNode(pHead,2,100)) { printf("插入后"); TraverseList(pHead); } else { printf("插入操作失败!\n"); } SortList(pHead); printf("排序后"); TraverseList(pHead); return 0; } PNODE CreateList() { int len;//用来保存需要创建链表的结点个数 int i; int val;//用来临时存放新节点的值 PNODE pHead=(PNODE)malloc(sizeof(NODE));//动态分配一块内存,该内存保存头结点的地址,并将其赋给pHead PNODE pTail=pHead; PNODE pNew; pTail->pNext=NULL;//将尾结点的指针域赋为NULL if(NULL==pHead) { printf("分配失败,程序终止运行!\n"); exit(-1); } printf("请输入你要创建链表的结点个数:len="); scanf("%d",&len); for(i=0;i<len;i++) { printf("请输入第%d个结点的值:",i+1); scanf("%d",&val); pNew=(PNODE)malloc(sizeof(NODE));//创建新临时结点 if(NULL==pNew) { printf("分配失败,程序终止运行!\n"); exit(-1); } pNew->data=val; pTail->pNext=pNew;//将新结点挂到原尾结点的后面 pNew->pNext=NULL;//将新结点的指针域赋为NULL pTail=pNew;//将新结点置为尾结点 } return pHead; } void TraverseList(PNODE pHead) { PNODE p=pHead->pNext;//将头结点的指针域指向首结点(链表的第一个有效结点),并赋给指针变量p,此时p指向首节点的地址 printf("遍历整个链表:"); while(NULL!=p)//当p指向首节点的地址不为NULL(即链表不为空),循环输入个结点的值 { //当p指向尾结点的地址时,可输出尾结点的值 //但此时尾结点指针域为NULL,将跳出while循环 printf("%d ",p->data); p=p->pNext;//将p指向下一个结点的地址赋给p指针 } printf("\n"); } bool IsEmpty(PNODE pHead) { if(NULL==pHead->pNext) return true; else return false; } int Length(PNODE pHead) { PNODE p=pHead->pNext;//此时p指向链表的首结点(第一个有效结点)的地址 int len=0; while(NULL!=p) { ++len; p=p->pNext; } return len; } bool InsertNode(PNODE pHead,int pos,int val) { int i=0; PNODE p=pHead,q; PNODE pNew; while(NULL!=p&&i<pos-1)//目的是为了使p指向要插入位置的前一个结点 { p=p->pNext; ++i;//如链表只有两个有效结点,要插入的位置结点pos=3,i=2时,2<3-1不成立,循环结束, } if(i>pos-1||NULL==p)//p为NULL说明要插入位置结点的前一个结点不存在,i>pos-1是为了防止用户输入pos为像0、-1等非法数据 return false; pNew=(PNODE)malloc(sizeof(NODE));//为新节点分配内存 if(NULL==pNew) { printf("动态内存分配失败,程序终止!\n"); exit(-1); } pNew->data=val; q=p->pNext; p->pNext=pNew; pNew->pNext=q; return true; } bool DeleteNode(PNODE pHead,int pos,int *pVal) { int i=0; PNODE p=pHead,q; while(NULL!=p->pNext&&i<pos-1)//当链表不为空,p指向要删除位置的前一个结点 { p=p->pNext; ++i; } if(i>pos-1||NULL==p->pNext)//当pos值小于或等于0,或指向了尾结点(此时要删除的下一个结点不存在)时; return false; q=p->pNext; *pVal=q->data; p->pNext=p->pNext->pNext; free(q); q=NULL; return true; } void SortList(PNODE pHead) { int i,j,t; int len=Length(pHead);//用len来保存链表的长度 PNODE p,q; for(i=0,p=pHead->pNext;i<len-1;p=p->pNext,i++)//比较趟数 { for(j=i+1,q=p->pNext;j<len;q=q->pNext,j++)//比较对数 { if(p->data>q->data) { t=p->data; p->data=q->data; q->data=t; } } } } bool QueryNode(PNODE pHead,int pos) { int i=0; PNODE p=pHead,q; while(NULL!=p->pNext&&i<pos-1) { p=p->pNext; ++i; } if(i>pos-1||NULL==p) return false; q=p->pNext; printf("第%d号位置上结点的值为:%d\n",pos,q->data); return true; } bool ModifyNode(PNODE pHead,int pos,int val) { int i=0; PNODE p=pHead,q; while(NULL!=p->pNext&&i<pos-1) { p=p->pNext; ++i; } if(i>pos-1||NULL==p) return false; q=p->pNext; q->data=val; printf("修改第%d号位置上结点的值为:%d\n",pos,q->data); return true; }
注意:
1.在vc++中,c编译器不支持bool函数,但c++编译器支持,所以这里我用的是c++编译器。
2.c编译过程中常见错误:illegal use of this type as an expression 是由于c语言不允许临时定义变量,所有定义的变量都必须放在函数开头,这也是c和c++的重要区别
数据结构的再理解
狭义上的理解:数据结构是专门研究数据存储(包括个体的存储和个体关系的存储)问题。
广义上的理解:数据结构既包含数据的存储也包含数据的操作。算法是对存储数据的操作。
算法:
狭义上的理解:算法和数据的存储方式密切相关
广义上的理解:算法和数据的存储方式无关(这就是泛型的思想)
泛型:利用某种技术达到的效果就是不同的存储方式,执行的操作是一样的。泛型主要通过模板,运算符的重载,指针来实现,在c++中经常用到。
补充
线性结构:
连续存储【数组】
优点:存取速度快
缺点:插入删除元素很慢,空间通常是有限制的,事先必须知道数组的长度,而且需要大块连续内存块
离散存储【链表】
优点:插入删除元素很快,空间没有限制的;
缺点: 存取速度很慢
结束语
链表相关操作中,个人感觉较难的是链表的创建,对结点的插入,删除和排序。今天就写到这,明天开始学习线性结构中的两种应用之一 --栈
相关文章推荐
- 对链表的相关操作及数据结构的再理解
- 数据结构_双链表的建立及相关操作
- 数据结构学习1:链表的相关操作
- 第二天 之数据结构、链表的相关概念和操作
- 数据结构-单向链表相关操作算法
- 链表的相关操作查找插入删除(c++ 数据结构)
- 数据结构_带有结点的单链表相关操作_C语言源代码
- 【数据结构】链表及相关操作(C语言实现)
- 11-数据结构_链表相关操作
- c语言实现链表的相关的操作
- (C语言版)链表(一)——实现单向链表创建、插入、删除等简单操作(包含个人理解说明及注释,新手跟着写代码)
- 深入理解链表的各类操作详解
- 数据结构 - 单链表的基本操作 (C语言)
- 数据结构上机测试2-2:单链表操作B
- Linux内核常见数据结构及操作——链表
- 树的相关操作(数据结构)
- 数据结构-顺序表和链表的基本操作
- 链表的相关操作(3)
- C#版的数据结构(对链表的操作)
- 【数据结构】链表操作示例