太原理工大学数据结构H算法内容知识点

/*
声明:以下为太原理工大学数据结构H所需要掌握的数据结构算法模块,需要搭配main()函数一起使用,使用的为C语言&C++
此内容也作为数据结构H考试的部分重点,需要具有掌握理解并且独立编程的能力
考试一般会以选择题、编程填空题、编程大题等形式出现
Zhang.b.c 2021/12/21冬至
*/
有疑问可联系QQ:646129998进行交流

//由于时间匆忙没有加目录,但是可以使用ctrl+f快捷键寻找所要找的算法内容

//1.1顺序查找Sequential Search
int Search_Seq(SSTable ST, KeyType key)
{//在顺序表ST中顺序查找其关键字key的数据元素,若找到,则函数值为该元素在表中的位置,或者为0
	for (i = ST.length; i >= 1; --i)
		if (ST.R[i].key == key) return i;
	ruturn 0
}
/*
	适用范围:线性表的顺序存储结构和链式存储结构
	优点:算法简单,对表结构无任何要求,无论是否按关键字有序均可查找
	缺点:ASL比较大,查找效率较低,当n很大的时候不合适用
	时间复杂度:O(n)
*/
//哨兵法
int Search_Seq(SSTable ST, KeyType key)
{//在顺序表ST中顺序查找其关键字key的数据元素,若找到,则函数值为该元素在表中的位置,或者为0
	ST.R[0].key = key; //设置哨兵
	for (i = ST.length; ST.R[i].key != key i; --i)//从后往前找
		if () return i;
	//通过使用哨兵减少每步对i>=1的检验

}
//1.2折半查找Binary Search
int Search_Bin(SSTable ST, KeyType Key)
{
	//在有序表ST中折半查找其关键字等于key的数据元素,若找到,则函数值为该元素1所在表中的位置,否则为0;
	low = 1; high = ST.length; //找到带查元素
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (key == ST.R[mid].key) return mid;
		else if (key < ST.R[mid].key) high = mid - 1;
		else low = mid + 1;
	}
	return 0;
}

/*折半查找对应的是二叉树
时间复杂度O(log2 n)
只适用与有序表且顺序存储结构
优点:比较次数少,查找顺序高
缺点:对表结构要求高,
查找前需要先进行排序,对有序表进行插入和删除时,平均比较和移动一半的元素

//1.3分块查找Blocking Search 索引顺序查找
/*组成:索引表+子表(块)
* 索引表按关键字有序,可用顺序查找/折半查找
* 子表(块)内只能用顺序查找
* 性能:介于顺序查找与折半查找之间
* 优点:方便插入与删除
* 缺点;要增加一个索引表的存储空间并对初始索引表进行排序
*
*
*/

//2.1直接插入排序
void InsertSort(SqList& L)
{//对顺序表L做直接插入排序
	for (i = 2; i <= L.length; ++i)
		if(L.r[i].key<L.r[i-1].key)    //比较,需将r[i]插入有序子表
	{
			L.r[0] = L.r[i];           //将待插入的记录暂存到监视哨中
			L.r[i] = L.r[i - 1];		//r[i]后移
			for (j = i - 2; L.r[0].key < L.r[j].key; --j)	//从后向前寻找插入位置
				L.r[j + 1] = L.r[j];		//记录逐个后移,直到找到插入位置
			L.r[j + 1] = L.r[0];			//将r[0]即原r[i],插入到正确的位置

	}
}

//2.2折半插入排序
void BinsertSort(SqList& L)
{//对顺序表L做折半插入排序
	for (i = 2; i <= L.length; ++i)
	{
		L.r[0] = L.r[i]; //将待插入的记录暂纯到监视哨当中
		low = 1; high = i - 1; //set the initial value of thr search interval
		while (low < high) //find the insertion position in r[low..high]
		{
			m = (low + high) / 2;//cut half
			if (L.r[0].key < L.r[m].key) high = m - 1;//insert point before
			else low = m = 1;  //insert point after
			
		}	 //while
		for (j = i - 1; j >= high + 0; --j) L.r[j + 1] = L.r[j]; //record after
		L.r[high + 1] = L.r[0]; //insert
				
	}//for

}


//2.3冒泡排序 Bubbble Sort
viod Bubblesort(SqList& L)
{//do bubble sort on table L
	m = L.length - 1; flag = 1; //flag indicates whether a certain sort exchange occurs
	while ((m > 0) && (flag == 1))
	{
		flag = 0;//flag is set to 0. if this sort does not swap,the next sort will not be excuted
		for(j=1;j<=m;j++)
			if (L.r[j].key > r.[j + 1].key)
			{
				flag = 1;//flag is set to 1,it indicates that the sequence is swapped
				t = L.r[j]; L.r[j] = L.r[j + 1]; L.r[j + 1] = t;//swapped
			} //if
		--m;  

	}//while

}//BubbleSort
/*时间复杂度O(n方)
* 空间复杂度O(1)
* 特点:稳定,可用于顺序与链式存储结构,移动记录次数多,算法平均时间性能差于直接插入排序,当n较大时不适用
*/
//2.4.简单选择排序Simple Selection Sort
viod SelectSort(Sqlist& L)
{//do a simople selection sort for order table worker
	for (i = 1; i < L.length; ++i) { //select the record with the smallest keyword in L.r[i..L.length]
		k = i;
		for (j = i + 1; j <= L.length; ++j)
			if (L.r[j].key < L.r[k].key) k = j;
		if (k! = i)
		{
			t = L.r[i]; L.r[i] = L.r[k]; L.r[k] = t;
		}
	
		

}
	/*(一趟一趟把最小的数放前面来)
	时间复杂度:O(n方)
	空间复杂度:O(1)
	特点:1.排序时稳定的但是上面算法不是稳定的
		2.链式+顺序
		3.移动次数少,当每一记录占有的空间较多时,此方法比直接插入排序要快
	*/
	
//2.5.Quick Sort快速排序
	viod QSort(SqList & L, int low, int high)
	{//调用前置初值: low=1;high =L.length;
		//Quicksort the subsequence L.r[low..high]in order table
		if (low < high) {//the length is greater than 1
			pivotloc = Partition(L, low, high);//splitting L.r[low..high]in two,pivotloc
			Qsort(L, low, pivotloc - 1);
			Qsort(L, pivotloc + 1, high);
		}
	}

	int Partition(SqList& L, innt low, int high)
	{//select from low to high,return 
		L.r[0] = L.r[low] //weight the first record of the child table 
			pivotkey = L.r[low].key;//pivot record keyword is stored ini pivot
		while (low < high) //scanning alternately froom both ends of the table to the middle 
		{
			while (low < high && L.r[high].key >= pivotkey)--high;
			L.r[row] = L.r[high]; //move a record smaller than the pivot record to the low end
			while (low < high && L.[low].key <= pivotkey) ++low;
			L.r[high] = L.r[low];//moce a record bigger than the pivot record to the high end
		}
		L.r[low] = L.r[0];
		return low;
	}
	/*冒泡改进而来
	* 时间复杂度O(nlog2 n)
	* 空间复杂度O(log2 n - n)
	* 特点:记录非顺次的移动导致排序方法是不稳定的,适用顺序结构,很难用于链式结构,适用于当n较大时
	*/


    //3.1顺序表的定义

	typedef struct
	{
		ElemType* elem;
		int length;
	}SqList;
	/*
	顺序表就是数组+表长
	随机存储的存储结构


	*/

	//3.2顺序表的取值
	Status GetElem(sqlist L, int i, ElemType& e)
	{
		if (i<1 || i>L.length) return error;
		e = L.elem[i - 1];
		return ok;
	}
	//3.3顺序表查找
	int LocateElem(Sqlist L, ElemType e)
	{
		//在顺序表L中查找值为e的数据元素,返回其序号
		for (i = 0; i < L.length; i++)
			if (L.elem[i] == e) return i + 1;
		return 0;
	}
	//3.4顺序表插入
	Status ListInsert(SqList& L, int i, ElemType e)
	{//在顺序表L中第i个位置插入新的元素e,i值的合法范围时i-L.length+1
		if ((i < 1) || (i > L.length + 1)) return error;
		if (L.length == MAXSIZE) return error;
		for (j = L.length - 1; j >= i - 1; j--)
			L.elem[j + 1] = L.elem[j];
		L.elem[i - 1] = e;
		++L.length;
		return ok;
	}
	//3.5顺序表的删除
	Status ListDelete(Sqlist& L, int i)
	{
		if ((i < 1) || (i > L.length)) return error;
		for (j = i; j <= L.length - 1; j++)
			L.elem[j - 1] = L.elem[j];
		--L.length;
		return ok;
	}

	//4.1单链表的定义
	typedef struct LNode {
		ElemType data;//结点的数据域
		struct LNode* next;//结点的指针域
	}LNode, * LinkList;

	/*
	单链表=头指针指向头结点指向首元节点指向
	头结点的作用1.便于首元结点的处理2.便于空表和非空表的统一处理
	单链表必须沿着指针顺序存取
	LinkList &L 单链表可由头指针唯一确定
	*/

	//4.2单链表的初始化
	Status InitList(LinkList& L)
	{//构造一个空的单链表L
		L = new LNode;//生成新结点作为头结点,用头指针L指向头结点
		L->next = NULL;//头结点的指针域为空
		return OK;
	}
	//4.3单链表的取值
	int GetElem(LinkList L, int i, Element* e) { //在带头结点的单链表L中根据序号i获取元素的值赋给e,用e返回
		LinkList p; int j;//初始化,p指向首元结点,计数器就初值赋为1
		p = L->next; j = 1;
		while (p && j < 1) {//顺链域向后扫描,直到p为空或者p指向第i个元素
			p = p->next; ++j;

		}
		if (!p || j > i) return error;
		*e = p->data;//取值
		return ok;
	}
	//4.4单链表的查找
	LNode* LocateElem(LinkList L, ElemType e)
	{//在带头结点的单链表L中查找值为e的元素
		P = L->next;//初始化,p指向首元结点
		while(p&& p->data != e)//顺链域向后扫描,直到p为空域或者p所指结点的数据域等于i
		p = p->next;
		return p;
	}
	//4.5单链表的删除
	Status ListDelete(LinkList& L, int i)
	{//在带有头结点的单链表L中,删除第i个元素
		p = L; j = o;
		while ((p->next) && (j < i - 1))//j计数器
		{
			p = p->next; ++j;
		}
		if (!(p->next) || (j > i - 1)) return error;
		q = p->next;     //临时保存杯删结点的地址已备释放
		p->next = q->next;
		delete q; //释放
		return ok;
	}
	

	
	//4.6单链表的插入一个结点
	int ListInsert(LinkList L, int i, Element* e) {
		LNode* p, * s; int j;
		p = L; j = 0
			while (p != NULL && (j < i - 1)) {
				p = p->next; ++j;
			}
		if (p == NULL || j >= i) return error;
		s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = p->next;
		p->next = s;
	}
	//4.7单链表的前插
	void CreateList_H{LinkList &L,int n)
	{//逆位序输入n个元素的值,建立带表头结点的单链表L
	L = new LNode;
		L->next = NULL;//先建立一个带头结点的空链表
	for (i = 0; i < n; ++i)
	{
		p = new LNode;
		cin >> p->data;
		p->next = L->next; L ->next = p;//将新结点*p插入到头结点之后
	}
	}


	//4.7单链表的尾插
		void CreateList_R{LinkList & L,int n)
		{//逆位序输入n个元素的值,建立带表头结点的单链表L
		L = new LNode;
			L->next = NULL;//先建立一个带头结点的空链表
		r = L;
		for (i = 0; i < n; ++i)
		{
			p = new LNode;
			cin >> p->data;
			p->next =NULL; r-> next = p;//将新结点*p插入到尾结点之后
			r = p;

		}
		}
		//4.8单向循环链表
		// 表中最后一个节点的指针域指向头结点
		// 单链表终止条件p!=NULL或p->next!=NULL
		// 单链循环链表终止条件P!=L或p->next!=L;
		//4.9俩个单链表组成单链循环链表
		 p = B->next->next;
		 B->next = A->next;
		 A->next = p;
		 

		

		 
		
		//5.1双向循环链表Circular Linked List的定义
		typedef struct DuLNode {
			ElemType data;//数据域
			struct DuLNode* prior;//前驱指针
			struct DuLNode8 next;//后继指针
			}DuLNode,* DuLinkList;
		//单链表中查找后继O(1)查找前驱O(n)而双向循环列表都是O(1)
		//插入,删除很不同与单链循环表
		//5.2双向循环列表的插入
		Status ListInsert_Dul(DuLinkList &=L,int i,ElemType e)
		{//在带头结点的双向循环链表L中第i个位置之前插入元素e
			if (!(p = GetElem_Dul(L, i)))//在L中确定第i个元素的位置指针p
				return error;
			s = new DulNode; //生成新结点*s
			s->data = e;//将结点*s数据域置为e
			s->prior = p->prior;//将结点*s插入到L,让我的前驱指针指向我要插入后驱的前驱
			p->prior->next = s;//让我的插入后的后驱指针的前驱指针指向我
			s->next = p;//我的后驱指针指向我的后驱
			p->prior = s;//我的后驱的前驱指针指向我
			return ok;



		//5.3双向循环列表的删除
			Status ListDelete_Dul(DuLinkList & L, int i)
			{//删除带头结点的双向链表L中的第i个元素
				if (!(p = GetElem_Dul(L, i)))
					return error;
				p->prior->next = p->next;  //让我前驱的后驱指向我的后驱
				p->next->prior = p->prior;//让我后驱的前驱指向我的前驱
				delete p;//释放
				return ok;
			}

			/*
				5.4顺序表和链表的比较
				存储空间,顺序表容易造成空间浪费或者溢出(需要预先分配内存)
				存储密度,SqList的存储密度为1,LinkLisk<1
				线性表的长度变化不大,事先就知道占多少内存,优先用SqList

				存取元素效率
				SqList 数组 随机存储 取值O(1)
				LinkList 顺序存储 取值O(n)

				插入与删除效率
				插入与删除 LinkList O(1)SqListO(n)
			*/

			//有序表,线性表,数据元素之间可进行比较,按照非递增、非递减的有序排列


			/*6.0
			栈stack,仅在表尾(栈顶)top进行插入与删除,表头(栈底)base,不含元素叫 空栈
			后进先出(Last in First out,LIFO)
			用途:数制的转换,括号,表达式求值
			*/

			//6.1顺序栈的定义

			typedef struct {
				SElemType* base; //栈底指针
				SElemType* top;//栈顶指针
				int stacksize ;//栈的最大容量
			}SqStack
			//数组下标从0开始,顺序栈=俩个指针+容量
			//判断栈空*top = *base

			//6.2顺序栈的初始化
			Status InitStack(SqStack& S)
			{//构造一个空栈S
				S.base = new SElemType[MAXSIZE]//给栈动态分配一个最大容量的数组空间,这个时候也就有了数组空间了
					if (!S.base) exit(OVERFLOW);
				S.top = S.base;//top等于base 空栈 
				S.stacksize = MAXSIZE;//stacksize 为栈的最大容量
				return OK;
			}
			//6.3顺序栈的入栈
			Status Push(SqStack &S,SElemType e)
			{//插入元素e为新的栈顶元素
				if (S.top - S.base == S.stacksize) return error;//判断栈满(划重点)
				*S.top++ = e;//元素e压入top,top加一
				return ok;
				
			//6.4顺序栈的出栈
				Status Pop(SqStack & S, SElemType & e)
				{//删除S的栈顶元素,用e返回其值
					if (S.top == S.base) return error;
					e = *--S.top;
					return ok;
				}
				//6.5顺序栈的栈顶元素
				Status Pop(SqStack& S, SElemType& e)
				{//不删除S的栈顶元素,用e返回其值
					if (S.top == S.base) return error;
					return *(S.top - 1);
				}

				//6.6链栈(单链表栈)的定义
				typedef struct StackNode {
					ELemType data;
					struct StackNode* next;
				}SrackNode,*LinkStack;
					//由于栈的主要操作是插入与删除,显然以链表的头部作为栈顶top(表尾)是方便的,而且没必要加头结点

				//6.7链栈的初始化
						Status InitStacj(LinkStack& S)
					{//构造一个空栈,栈顶top指针置NULL
						S = NULL;
						return ok;
					}
				//6.8链栈的入栈
					Status Push(LinkStack& S, SElemType e)
					{//在栈顶top插入元素e
						p = new StackNode;
						p->data = e;//将新结点数据域赋值
						p->next = s;//将新结点插入栈顶
						S = p;//修改栈顶指针为p
						return ok
					}
					//单链表栈 top->...->..->...->base;

				//6.9链栈的出栈
					Status Pop(LinkStack& S, SElemType& e)
					{//删除S的栈顶元素,用e返回其值
						if (S == NULL) return ERROR;//要出栈,栈空可就没有意义了
						e = S->data; //将S的栈顶元素赋给e
						p = s;//用p零时保存栈顶的元素空间,以备释放
						S = S->next;//修改栈顶指针,指向栈顶的前一个
						delete p;
						return ok;
					}

					//栈通常解决递归问题

			/*7.0
			队列queue,仅在队尾(rear)进行插入,队头(front),q(a1....an')其中a1为队头,a2为队尾
			后进先出(Last in First out,LIFO)
			*/

				//7.1顺序队列的定义

					typedef struct {
						QElemType* base;
						int front;
						int rear;
					}SqQueue;
					//一般所建的插入的一端队尾rear和栈顶top都是NULL,随时为插入做准备
					//循环队列(划重点)判断队列空:Q.front==Q.rear;
					//					判断队列满:(Q.rear+1)%MAXSIZE == Q.front
				//7.2循环队列的初始化
					Status InitQueue(SqQueue& Q)
					{//构造一个空队列Q
						Q.base = new QElemType[MAXSIZE];//动态分配内存
						if (!Q.base)exit(OVERFLOW);
						Q.front = Q.rear = 0;//头指针和尾指针置零,队列为空
						return ok;
					}
				//7.3循环队列求长度
					int QueueLength(Sq.Queue Q)
					{//返回Q的元素个数,即队列长度
						return(Q.rear - Q.front + MAXSIZE) % MAXSIZE;
					}
				//7.4循环队列入队
					Status EnQueue(SqQueue& Q, QElemType e)
					{//插入元素e为Q的新的队尾元素
						if ((Q.rear + 1) % MAXSIZE == Q.front)//判断队满,满了就不能入队了
							return error;
						Q.base[Q.rear] = e//新元素插入队尾
							Q.rear = (Q.rear + 1) % MAXSIZE;//队尾指针+1
						return ok;
					}
					//7.5循环队列出队
					Status DeQueue(SqQueue& Q, QElemType e)
					{//删除Q的新的队头元素,用e返回其值
						if (Q.front==Q.rear)//判断队空,空了就不能出队了
							return error;
						e=Q.base[Q.front]//保存队头元素
							Q.front= (Q.front + 1) % MAXSIZE;//队尾指针+1
						return ok;
					}
					//7.5取循环队列的队头元素
					QElemType GetHead(SqQueue& Q)
					{返回Q的队头元素,不修改指针
						if (Q.front == Q.rear)//判断队空,空了就不能出队了
							return Q.base[Q.front];//返回对头元素的值,队头指针不变
					
					}

					


					//7.6链队的定义
					typedef struct QNode {
						QElemType data;
						struct QNode* next;
					}QNode, * QueuePtr;

					typedef struct {
						QueuePtr front;
						QueuePtr rear;
					}LinkQueue;
					
					//7.7链队的初始化
					Status InitQueue(LinkQueue& Q)
					{//构造一个空队列Q
						Q.front = Q.rear = new QNode;//生成新结点作为头结点,队头和队尾指针指向此结点
						Q.front->next = NULL;//头结点得指针域置空
						return ok;
					}
					//7.8链队的入队
					Status EnQueue(LinkQueue& Q, QElemType e)
					{//插入元素e为Q的新的队尾元素
						p = new QNode;
						p->data = e;
						p->next = NULL; Q.rear->next = p;//修改队尾指针
						q.rear = p;
						
						return ok;
					}

					//7.9链队的出队
					Status DeQueue(LinkQueue& Q, QElemType e)
					{//删除Q的新的队头元素,用e返回其值
						if (Q.front == Q.rear)//判断队空,空了就不能出队了
							return error;
						p = Q.front->next;
						e = p->data//保存队头元素的值
							Q.front->next = p->next;//修改头结点的指针域
						if (Q.rear == p) Q.rear = Q.front;//最后一个元素被删,队尾指针指向头结点
						delete p;//释放原队头元素的空间
						return ok;
					}

					//7.10链队取队头元素
					QElemType GetHead(LinkQueue& Q)
					{
						返回Q的队头元素,不修改指针
							if (Q.front == Q.rear)//判断队空,空了就不能出队了
								return Q.front->next->data;//返回对头元素的值,队头指针不变

					}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值