数据结构 1.关于算法效率 例1:写程序计算给定多项式在定点x处的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 double f (int n,double a[],double x) { int i; double p=a[0 ]; for (i=1 ;i<=n;i++){ p+=(a[i]*pow (x,i)); } return p; } double f (int n,double a[],double x) { int i; double p=a[n]; for (i=n;i>0 ;i--) p=a[i-1 ]+x*p; return p; }
常用的测试程序运行时间的模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <time.h> using namespace std ; clock_t start,stop;double duration;int main () { start=clock(); MyFunction(); stop=clock(); duration=((double )(stop-start))/CLK_TCK; return 0 ; }
具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <iostream> #include <time.h> #include <math.h> using namespace std ; #define MAXN 10 #define MAXK 1e7 double f1 (int n, double a[], double x) { int i; double p = a[0 ]; for (i = 1 ; i <= n; i++) { p += (a[i] * pow (x, i)); } return p; } double f2 (int n, double a[], double x) { int i; double p = a[n]; for (i = n; i > 0 ; i--) p = a[i - 1 ] + x * p; return p; } clock_t start, stop;double duration;int main () { int i; double a[MAXN]; for (i = 0 ; i < MAXN; i++) a[i] = (double )i; start = clock(); for (i=0 ;i<MAXK;i++) f1(MAXN - 1 , a, 1.1 ); stop = clock(); duration = ((double )(stop - start)) /CLK_TCK/MAXK; printf ("duration1=%6.2e\n" , duration); start = clock(); for (i = 0 ; i < MAXK; i++) f2(MAXN - 1 , a, 1.1 ); stop = clock(); duration = ((double )(stop - start)) /CLK_TCK/MAXK; printf ("duration2=%6.2e\n" , duration); return 0 ; }
求N个整型数列的区间和最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int MaxsubseqSum (int A[],int N) { int ThisSum,MaxSum=0 ; int i,j,k; for (i=0 ,i++,i<N){ for (j=i,j++,j<N){ ThisSum=0 ; for (k=i,k++,k<j){ ThisSum+=A[k]; } if (ThisSum>MaxSum) MaxSum=ThisSum; } } return MaxSum; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int MaxsubseqSum (int A[],int N) { int ThisSum,MaxSum=0 ; int i,j; for (i=0 ,i++,i<N){ ThisSum=0 ; for (j=i,j++,j<N){ ThisSum+=A[j]; if (ThisSum>MaxSum) MaxSum=ThisSum; } } return MaxSum; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int MaxsubseqSum (int A[],int N) { int ThisSum,MaxSum=0 ; int i; ThisSum=MaxSum=0 ; for (i=0 ,i++,i<N){ ThisSum+=A[i]; if (ThisSum>MaxSum) MaxSum=ThisSum; else if (ThisSum<0 ) ThisSum=0 ; } return MaxSum; }
一元多项式的表示
运用结构数组,结构中包含指数和系数,按照指数由大到小排列 运用链表存储,链表中每个结点存储多项式中的一个非零项,包括系数和指数两个数据域以及一个指针域
1 2 3 4 5 6 typedef struct PolyNode *Polynomial;struct PolyNode { int coef; int expon; Polynomial link; }
2.线性结构 线性表 抽象数据类型描述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 类型名称:线性表(List) 数据对象集:n个元素构成的有序序列 操作集: List MakeEmpty () :初始化一个空线性表 ElementType FindKth(int K,List L):根据位序K,返回相应元素; int Find (ElementType X,List L) :在线性表L中查找X的第一次出现位置;void Insert (ElementType X,int i,List L) :在位序i前插入一个新元素X;void Delete (int i,List L) :删除指定位序i的元素;int Length (List L) :返回线性表L的长度n;
线性表的顺序存储实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 typedef struct LNode *List;struct LNode { ElementType Data[MAXSIZE]; int Last; }; struct LNode L;List PtrL; List MakeEmpty () { List Ptrl; Ptrl = (List)malloc (sizeof (struct LNode)); Ptrl->Last=-1 ; return Ptrl; } int Find (ElementType X,List L) { int i =0 ; while (i<=Ptrl->Last&&Ptrl->Data[i]!=X) i++; if (i>Ptrl->Last) return -1 ; else return i; } void Insert (ElementType X,int i,List L) { int j; if (Ptrl->==MAXSIZE-1 ){ cout<<"表已满" ; return ; } if (i<1 ||i>Ptrl->Last+2 ){ cout<<"位置不合法" ; return ; } for (j=Ptrl->Last;j>=i-1 ;j--) Ptrl->Data[j+1 ]=Ptrl->Data[j+1 ]; Ptrl->Data[i-1 ]=X; Ptrl->Last++; return ; } void Delete (int i,List L) { if (i<1 ||i>Ptrl->Last+1 ){ cout<<"位置不合法" ; return ; } for (j=i;j<=Ptrl->Last;j++) Ptrl->Data[j-1 ]=Ptrl->Data[j]; Ptrl->Last-; return ; }
线性表的链表存储实现
1 2 3 4 5 6 7 8 typedef struct LNode * List;struct LNode { ElementType Data; List Next; }; struct Lnode L;List PtrL;
操作 求表长
1 2 3 4 5 6 7 8 9 int Length (List Ptrl) { List p = Ptrl; int j = 0 ; while (p){ p = p->Next; j++; } return j; }
查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 List FindKth (int K,List Ptrl) { List p = Ptrl; int i = 1 ; while (p != NULL && i < K ){ p = p->Next; i++; } if (i == K)return p; else return NULL ; } List FindKth (ElementType K,List Ptrl) { List p = Ptrl; while (p != NULL && p->Data != X ){ p = p->Next; } return p; }
插入
思路: (1).先创建一个新的结点,用s指向 (2).再找到链表的第i-1个结点,用p指向; (3)然后修改指针,插入结点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 List Insert (ElementType X,int i,List Ptrl) { List p,s; if (i == 1 ){ s = (List)malloc (sizeof (struct LNode)); s->Data = X; s->Next = Ptrl; return s; } p = FindKth (i-1 ,Ptrl); if (p == NULL ){ cout<<"参数i错误" <<endl; return NULL ; }else { s = (List)malloc (sizeof (struct LNode)); s->Data = X; s->Next = p->Next; p->Next = s; return Ptrl; } }
删除 插入
思路: (1).先找到第i-1个结点,并用p指向 (2).再用指针s指向要被删除的结点(p的下一个结点) (3)修改指针,删除s所指结点 (4)最后释放s指针所指的空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 List Insert (ElementType X,int i,List Ptrl) { List p,s; if (i == 1 ){ s = Ptrl; if (Ptrl != NULL ) Ptrl = Ptrl->Next; else return NULL ; free (s); return Ptrl; } p = FindKth (i-1 ,Ptrl); if (p == NULL ){ cout<<"第" <<i-1 <<"个结点不存在" <<endl; return NULL ; }else if (p->Next == NULL ){ cout<<"第" <<i<<"个结点不存在" <<endl; }else { s = p->Next; p->Next = s->Next; free (s); return Ptrl; } }
多重链表 广义表 广义表表示二元多项式
广义表是线性表的推广 对于线性表而言,n个元素都是基本的单元素 广义表中,这些元素不仅可以是单元素也可以是另一个广义表
1 2 3 4 5 6 7 8 9 typedef struct GNode *GList;struct GNode { int Tag; union { ElementType Data; GList SubList }URegion; GList Next; }
十字链表
用于存储稀疏矩阵 只存储矩阵的非0元素项 结点的数据域:行坐标Row,列坐标,数值Value 每个结点通过两个指针域,把同行,同列串起来 [1].行指针(向右指针)Right [2].列指针(向下指针)Down
堆栈
栈的特点:先进后出,后进先出
后序表达式
a+bc-d/e abc +de/-
堆栈的抽象数据类型描述 堆栈:具有一定操作约束的线性表,只在一段(栈顶/top)做插入、删除
插入数据:入栈 删除数据:出栈 后入先出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 类型名称:堆栈(Stack) 数据对象集:一个有0 个或多个元素的有穷线性表 操作集: 长度为MaxSize的堆栈S,堆栈元素item Stack CreatStack (int MaxSize) :生成空堆栈,其最大长度为MaxSize int IsFull(Stack S,int MaxSize):判断堆栈S是否已满; void Push (Stack S,ElementType item) :将元素item压入堆栈;int IsEmpty (Stack S) :判断堆栈S是否为空;ElementType Pop (Stack S) ;删除并返回栈顶元素
栈的顺序存储实现 1 2 3 4 5 6 #define MaxSize typedef struct SNode *Stack;struct SNode { ElementType Data[Maxsize]; int Top; };
入栈
1 2 3 4 5 6 7 8 9 void Push (Stack PtrS,ElementType item) { if (PtrS->Top == MaxSize-1 ){ cout<<"栈已满" ; return ; }else { PtrS->Data[++(PtrS->Top)] = item; return ; } }
出栈
1 2 3 4 5 6 7 8 ElementType Pop (Stack PtrS) { if (PtrS->Top==-1 ){ cout<<"堆栈空" ; return ERROR; }else { return (PtrS->Data[(PtrS->Top)--]); } }
例子 请用一个数组实现两个堆栈,要求最大地利用数组空间,使数组只要有空间入栈操作就可以成功
方法:使两个栈分别从数组的两头开始向中间生长;当两个栈的栈顶指针相遇时,表示两个栈都满了;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #define MaxSize struct DStack { ElementType Data[Maxsize]; int Top1; int Top2; }S; S.Top1 = -1 ; S.Top2 = MaxSize; void Push (strcut DStack *PtrS,ElementType item,int Tag) { if (PtrS->Top2 - PtrS->Top1 == 1 ){ cout<<"栈已满" ; return ; } if (Tag == 1 ) PtrS->Data[++(PtrS->Top1)] = item; else PtrS->Data[--(PtrS->Top2)] = item } ElementType Pop (struct DStack *PtrS,int Tag){ if (Tag == 1 ){ if (PtrS->Top1 == -1 ){ cout<<"堆栈1空" ; return NULL ; }else return (PtrS->Data[(PtrS->Top1)--]); } else { if (PtrS->Top2 == MAXSIZE){ cout<<"堆栈2空" ; return NULL ; }else return (PtrS->Data[(PtrS->Top2)++]); } }
栈的链式存储实现 栈的链式存储结构实际上就是一个单链表 ,叫做链栈 。插入和删除操作只能在链栈的栈顶进行。Top应该在头节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 typedef struct SNode *Stack;struct SNode { ElementType Data; struct SNode *Next; }; Stack CreateStack () { Stack S; S = (Stack)malloc (sizeof (strcut SNode)); S->Next = NULL ; return S; } int IsEmpty (Stack S) { return (S->Next == Next); } void Push (ElementType item,Stack S) { struct SNode * TmpCell; TmpCell = (struct SNode*)malloc (sizeof (struct SNode)); TmpCell->Element = item; TmpCell->Next = S->Next; S->Next = TmpCell; } ElementType Pop (Stack S) { struct SNode *FirstCell; ElementType TopElem; if (IsEmpty (S)){ cout<<"堆栈空" ; return NULL ; }else { FirstCell = S->Next; S->Next = FirstCell->Next; TopElem = FirstCell->Element; free (FirstCell); return TopElem; } }
实际应用 中缀表达式求值basic strategy :将中缀表达式转化为后缀表达式,然后求值中缀表达式如何转化为后缀表达式
从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理
运算数 :直接输出
左括号 :压入堆栈
右括号 :将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出);
运算符 :
若优先级大于栈顶运算符时,则把它压栈
若优先级小于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈;
若各对象处理完毕,则把堆栈中存留的运算符一并输出。