三、链表,栈,队列,二叉树
(一)链表
(1)链表:由设计为大小合适的小的容器组成,这些容器可以根据需要链接在一起。
由头指针管理的结点
数组的缺陷
动态数组的缺陷
数组是在编译时分配内存的,所以数组的大小是不可改变的,可是链表是动态的,所以
可以在需要的时候增加和减小链表的长度。
(要加长要减短很容易。 链表来源于生活,如火车、 钻石用底座镶嵌连接起来--节点)
节点中放数据和指向下一个节点的指针:
-------- ----------- ----------- -----------
| head |-->|数据|指针|-->|数据|指针|-->|数据|NULL|
-------- ----------- ----------- -----------
头指针 头节点 内部节点 尾节点
struct Node{
T data; //数据
Node* next; //指向下一个节点,而不是数据
};
若改造成类:
class Node{
public: //加public 或者 设置友元 来提供访问权
T data;
Node* next;
};
链表家庭组成:
头节点: 其工作是管理链表的头。 第一个节点
尾节点: 最后一个 next==NULL 初始时,头节点的Next指针指向尾节点(既是头,也是尾)。
内部节点:存放数据类型。
头指针:指向头一个节点的指针,只有4byte
(2)链表的特点
a.非常重要的数据结构 (应用非常广泛)
b.灵活 数组必须连续存放,而链表不要求连续,只要零碎空间;
c.比数组节省空间 因为数组可能会浪费原来申请的空间,而链表要多少申请多少;
数组必须连续存放,而链表不要求连续,只要零碎空间;
d.访问比较慢 后续数据必需从头遍历数据才可访问到;
e.操作比较复杂 通过封装一些函数来解决。
(3)链表的操作
通常把头指针封装成一个链表类 Node* head;
插入
a.插入第一个节点:
1).准备节点
申请空间 Node* p = new Node;
设置data p->data = ...;
设置next=NULL p->next = NULL;
2).head指向新节点 head = p;
b.插入第二个节点:(前插法---新节点总是成为头节点)
1).准备节点
2).让新节点的next成员指向旧节点 p->next = head;
3).让head指向新节点 head = p;
插入第一个节点也可用以上三个步骤(一般复杂步骤兼容简单步骤)
头插法优点:只需要与head打交道,效率最高;
缺点:顺序与插入颠倒了 (应用于栈 再好不过)
c.插入第二个节点:(后插法)
1).准备节点
2).找到尾节点的next成员
写一个函数来找 返回类型Node*& (注意:返回的是Node*的引用,才可以修改它)
3).让它指向新节点
d.在任意位置插入新节点: (涵盖了前插、后插的通用算法):
1).准备新节点
2).找到链表中要插入位置的指针pn
3).让新节点的next成员指向要指入的位置 p->next = pn;
4).让找到的指针指向新节点 pn = p;
对于第2步举个例子,发现规律:
-------- ------------ ----------- ------------ ------------
| head |-->|数据0|指针|-->|数据1|指针|-->|数据2|指针|-->|数据3|NULL|
-------- ------------ ----------- ------------ ------------
0 pt = head;
1 pt->next;
2 pt=pt->next; pt->next
3 pt=pt->next; pt->next
两次
...
n号 pt=pt->next; pt->next //得出结论
n-1次
提醒:链表中只有两种的指针:head 和 next
pt = pt->next 使pt指向pt的下一个节点(前提要有下一个,否则段错误)
建议:一定要多画图!多画图自己就会有思路
---------------------------------------------------------
查找功能分析步骤:
1.定义一个指向第一个节点的指针
2.反复:2.1如果指针为空,找不到数据;
2.2如果非空,看节点中的数据是否是要找的数据
2.2.1 是,找到了
2.2.2 不是,让指针指向下一个节点
函数代码如下:
int find( T d )
{
Node* pt = head;
int pos = 0; //记录找到节点编号
while( pt!=NULL )
{
if( pt->data==d )
return pos; //找到返回节点编号
pt = pt->next;
++pos;
}
return -1; //找不到返回无效值
}
---------------------------------------------------------
更新功能的步骤分析:
1.查找数据,取得在链表中的位置
2.根据位置取得指向节点的指针
3.通过指针修改节点中的数据
函数代码如下:
bool update( T d1, T d2 )
{
int pos = find(d1);
if( pos==-1 )
return false;
Node* pt = getp(pos);
pt->data = d2;
return true;
}
---------------------------------------------------------
删除功能的步骤分析:
1.找到要删的数据所在的位置 pos
2.取得指向要删节点位置的指针 pn
3.把指针保存一份 pt=pn;
4.让pn指向下一个节点 pn = pn->next;
5.释放空间 delete pt;
函数代码如下:
bool erase( T d )
{
int pos = find(d);
if( pos==-1 )
return false;
Node*& pn = getp(pos);
Node* pt = pn;
pn = pn->next;
delete pt;
--len;
return true;
}
---------------------------------------------------------
取链表头:
T getHead()
{
if( empty())
return T();
return head->data;
}
取链表尾:
T getTail()
{
if( empty())
return T();
return getp(len-1)->data;
}
---------------------------------------------------------
(4)双向链表 (了解)
多维护了一个指针,可以前后遍历
struct Node{
int v;
Node *prev;
Node *next;
};
以空间换取时间
(二)栈
(1)LIFO(只要实现这一特征就是栈)
(2)常用方法:push(),pop(),isempty(),count(),clear(),reset()等
( 3 ) 栈的实现: 用数组实现,用链表实现
(三)队列
(1)FIFO;
(2)常用方法:insert(),pop()等;
(四)二叉树
(1)每个节点最多只有两个分支的树,它有一个根指针,要指向这棵树的根节点(最顶端的节点). 左子树上的值小于其父节点的值,右子树上的值都大于其父节点上的值。 --- 排序二叉树
(2)周游(遍历) :
先序 --- 中左右
中序 --- 左中右
后序 --- 左右中
(3)二叉查找树的常见操作:增,删,查,改,遍历;
主要的思想是迭代;
(4)非常方便查找
四、常用算法
(一)算法
有穷性 --- 在保证执行有限步骤之后确定能够结束
确切性 --- 每条语句具体干什么
输入输出 --- 所有的算法都有输出,打印屏幕,写文件,写DB
(二)常用的重要的方法(必须掌握下列排序的思想)
排序
(1)冒泡排序:用得是多轮排序,只比较相邻的数据对。只要发生过交换就要继续,如果没有发生交换排序完成。
规律:每一轮下来都会把最大的一个排好序。
适用于:只有少数是乱序的时候
void sort(){
bool bSwap;//不可以在do里面定义,不然在while()中就不能使用了
do{
bSwap=false;//是否交换过?
for(int i=0;i<n-1;i++){
if(a[i]>a[i+1]){
int t=a[i];
a[i]=a[i+1];
a[i+1]=t;
bSwap=true;//交换过
}
}
n--;//优化,因为每一次最大的都会排好序,所以可以少比一个数。
}while(bSwap); //只要发生过交换就再来一次
}
时间7秒10240个数据
int main(){
const int N=1024;
int a[n];
for(int i=0;i<N;i++)
a[i] = N-i;//保存的是1
long t1=time(NULL);
sort(a,N);
long t2=time(NULL);
cout<<"time:"<< t2-t1 <<endl;
for(int i=0;i<10;i++)
cout<<a[i]<<' ';
cout<<endl;
}
(2)选择排序:每次都找最大(最小)的元素放在应该放的位置
1反复i=0 i--n-1
1.1在未排序的数据中找到最小的元素。
1.1.1反复(j=i-n-1),以前做过递归选择排序
1.2把最小元素,跟下标为i的元素交换。
写void sort(int *a,n);对数组中N个元素排序。用选择排序法。
void sort(int *a , int n){
for(int i=0;i<n-1;i++){
int pos=i;
for(int j=i;j<i-n-1;j++){
if(a[j]<a[pos]){
pos=j;
}
}
int p=a[pos];
a[pos]=a[i];
a[i]=p;
}
}
#include<ctime>
int main(){
const num=10240;
int a[num];
for(int i=0;i<num;i++){
a[i]=num-i;
}
long t1=time(NULL);
sort(a,num);
long t2=time(NULL);
for(int i=0;i<8;i++){
cout<<a[i]<<' ';
cout<<endl;
cout<<"time:"<<t2-t1<<endl;
}
return 0;
}
时间2秒10240个数据
(3)插入排序:将头两个元素排序.把接下来的数据依次将每一个元素排到正确的位置.直到所有的元素都排完.前面一个数据不比要插入的数据大了,就是要插入的位置.凡是比它大的数据都要向后移动.
void sort(int *a,int n){
for(int i=1;i<n;i++){
int cur=a[i];
int j;
for(j=i;j>0&&a[j-1]>a[j];j--){
a[j]=a[j-1];//大量的数据移动,所以速度慢点.
}
a[j]=cur;
}
}
时间3秒10240个数据
(4)快速排序:效率最高的排序算法.
找一个分界值,把数据分成两组,对每一组在分成两组,知道只有最后一组数据只有一个数据为止.把大于分界值得放在一边,把不小于分界值得放在另一边.对这两小组在继续.
数组 {503,87,512,61,908,170,897,275,653,462}
1) [462 87 275 61 170] 503 [897 908 653 512]
2) [170 87 275 61] 462 503 [897 908 653 512]
3) [61 87] 170 [275] 462 503 [897 908 653 512]
4) 61 [87] 170 [275] 462 503 [897 908 653 512]
5) 61 87 170 [275] 462 503 [897 908 653 512]
6) 61 87 170 275 462 503 [897 908 653 512]
7) 61 87 170 275 462 503 [512 653] 897 [908]
8) 61 87 170 275 462 503 512 [653] 897 [908]
9) 61 87 170 275 462 503 512 653 897 [908]
10) 61 87 170 275 462 503 512 653 897 908
void swap(int& x,int & y){
int t=x;
x=y;
y=t;
}
void sort(int *a,int n){
if(n<=1){return ;}
int pivot=a[n>>1];//a[0],a[n-1],a[n/2]找谁居中作为分界值.这里简单处理选a[n/2];
swap(a,a[n>>1]);
int *p=new int[n];
int* lp=p;
int* rp=p+(n-1);
int pivot=*a;
int *pt=a;//为了效率
for(int i=1;i<n-1;i++){
if(pivot>*pt){
*lp++=*pt;
}else{
*rp--=*pt;
}
}
*lp=pivot;
pt=a;
lp=p;
for(int i=0;i<n;i++){
*pt++=*lp++;
}
delete[] p;
int left=rp-p;
sort(a,left);
sort(a+left+1,n-left-1);
}
分享到:
相关推荐
数据结构与算法开发教程&基础篇&数组与链表&栈与队列&树图结构&哈希表&排序搜索算法&Trie树&并查集
c语言版本的数据结构的快速排序算法,适用于新手学习
数据结构冒泡排序算法 数据结构冒泡排序算法
在IT领域,数据结构与算法是核心组成部分,而排序问题是数据结构中不可或缺的一部分。本主题主要聚焦于数据结构试验中的排序问题,通过C语言来实现内部排序算法。下面将详细介绍这些概念及其相关知识。 首先,数据...
数据结构拓扑排序
二叉排序树,又称二叉查找树或二叉搜索树,是一种特殊的数据结构,它具有以下特性:对于树中的任意节点,其左子树中的所有节点的值都小于该节点的值,而右子树中所有节点的值都大于该节点的值。这种特性使得在二叉...
在计算机科学领域,数据结构和排序算法是至关重要的基础,它们直接影响到程序的效率和性能。本资源包“数据结构-各种排序完整示例程序”提供了C语言实现的各种经典排序算法,帮助学习者深入理解并掌握这些算法的实际...
### 数据结构排序实验报告知识点解析 #### 实验背景与目的 - **实验背景**:本实验报告来源于南昌大学科学技术学院信息学科部计算机系的一次专业课程实验。《数据结构》作为一门重要的计算机基础课程,其目的在于...
数据结构与排序是计算机科学中的核心概念,它们在编程和算法设计中扮演着至关重要的角色。数据结构是指在计算机中组织和存储数据的方式,而排序则是对这些数据进行有效处理的关键技术。 首先,我们来深入了解一下...
根据给定的信息,我们可以分析出该段代码主要实现了二叉排序树的...二叉排序树是一种非常实用的数据结构,在实际应用中广泛用于快速查找、排序等领域。理解其原理和实现方法对于学习更高级的数据结构和算法非常重要。
4. **数据结构基础**:排序算法往往与特定的数据结构如数组、链表、栈、队列等紧密相关。理解这些基本数据结构的特性和操作,能帮助设计更高效的排序算法。 5. **团队合作**:四人合作意味着需要明确任务分工,如一...
数据结构学习笔记排序算法:基数排序数据结构学习笔记排序算法:基数排序数据结构学习笔记排序算法:基数排序数据结构学习笔记排序算法:基数排序数据结构学习笔记排序算法:基数排序数据结构学习笔记排序算法:基数...
总结来说,这个实验项目涵盖了数据结构的基础——排序算法,包括直接排序(如插入排序、选择排序和冒泡排序)和高级排序算法(快速排序)。通过实践,你可以深化对这些概念的理解,提升编程技能,并为未来在算法和...
本资源“算法:C语言实现第1-4部分基础知识、数据结构、排序及搜索”涵盖了C语言编程的基础知识,以及在计算科学中至关重要的数据结构、排序和搜索算法。 首先,基础知识部分主要涉及C语言的语法、变量、控制结构...
数据结构排序一章的希尔结构排序,显示结果的
数据结构是计算机科学中的核心课程之一,而内部排序则是数据结构中的重要组成部分,它涉及到如何高效地对大量数据进行排序。严蔚敏教授的《数据结构》是一本经典的教材,其中第十章专门讲解了内部排序算法。内部排序...
内部排序则是数据结构中的一个重要部分,它指的是在计算机内存中对数据进行排序的方法。本实验报告将深入探讨四种经典的内部排序算法:冒泡排序、基数排序、快速排序和希尔排序,以及它们在C++和C语言中的实现。 1....
数据结构--快速排序C++源代码,自己编写调试,代码简单易懂,不长
在计算机科学领域,数据结构与算法是至关重要的基础,而排序则是其中不可或缺的一部分。排序算法是用于重新组织数据序列,使其按照特定标准(如升序或降序)排列的算法。这里我们将深入探讨标题和描述中提及的一些...