2021-06-08 总结基础

本文概述了各种关键的计算机科学算法,包括二分查找、直接插入排序、冒泡排序、快速排序、选择排序和堆排序。深入探讨了二叉树的深度优先遍历(前序、中序、后序及层次遍历)、进制转换技术,以及面向二叉树的遍历方法。适合初学者和进阶者理解基础数据结构和算法应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

二分查找

直接插入排序

冒泡排序

快速排序

选择排序

堆排序

二叉树深度优先遍历dfs

前序遍历

中序遍历

后序遍历

二叉树的层次遍历

转换进制


二分查找

public int findnum(vector<int> arr,int target){
    int left,right,mid;
    left = 0;
    right = arr.size()-1;//**size-1
    while(left <= right){//有等于
        mid = left + (right-left)/2;//写在内部
        if(target < arr[mid]){
            right = mid-1;//-1
        }
        else if(target > arr[mid]){
            left = mid+1;//+1
        }
        else if(target==arr[mid]){
            return mid;
        }
    }
    return -1;//-1别忘
}

直接插入排序

稳定

void InsertionSort(int *a, int len)
{
	for (int i=1; i<len; i++)
	{
		int key = a[i];//现在所在元素
		int j = i-1;//之前的元素
		while (j>=0 && a[j]>key)//现在的元素小于之前的元素
		{
			a[j+1] = a[j];//之前的元素往后挪
			j--;
		}
		a[j+1] = key;//放现在的元素
	}
}

冒泡排序

void bubbleSort(int a[], int n)
{
    int i,j;
    for(i = 0; i<n - 1; i++){//**n-1趟冒泡
        for(j = 0; j<n - 1 - i; j++){//**n-1-j,前面的冒泡
            if(a[j] > a[j+1]) {
                swap(a[j], a[j+1]);
            }

        }
    }
}

快速排序

不稳定

public void quick_sort(int left,int right,vector<int> arr){
    //left right开始排序的下标位置
    if(left>=right){//星星
        return;
    }
    int i,j,base;
    i = left;
    j = right;
    base = arr[left];
    while(i < j){
        if(base<=arr[j]&&i<j){
            j--;
        }
        if(base>=arr[i]&&i<j){
            i++;
        }
        swap(arr[i],arr[j]);
    }
    //星星
    arr[left] = arr[i];
    arr[i] = base;
    quick_sort(left,i-1,arr);
    quick_sort(j+1,right,arr);
}

选择排序

不稳定

void select_sort(int a[], int n)
{
    int index;
    int i,j;
    for (i = 0; i < n - 1; i++)
    {
        index = i;
        for (j = i + 1; j < n; j++)
        {
            if (a[index] < a[j])
            {
                index = j;
            }
        }
        swap(a[index], a[i]);
    }
}

堆排序

// 递归方式构建大根堆(len是arr的长度,index是第一个非叶子节点的下标)
void adjust(vector<int> &arr, int len, int index)
{
    int left = 2*index + 1; // index的左子节点
    int right = 2*index + 2;// index的右子节点

    //找子树的最大节点下标
    int maxIdx = index;
    if(left<len && arr[left] > arr[maxIdx])
        maxIdx = left;
    if(right<len && arr[right] > arr[maxIdx])
        maxIdx = right;

    //最大节点不是父节点则交换位置
    if(maxIdx != index)
    {
        swap(arr[maxIdx], arr[index]);
        adjust(arr, len, maxIdx);
    }

}

// 堆排序
void heapSort(vector<int> &arr, int size)
{
    // 构建大根堆(从最后一个非叶子节点向上)
    for(int i=size/2 - 1; i >= 0; i--)
    {
        adjust(arr, size, i);
    }

    // 调整大根堆
    for(int i = size - 1; i >= 1; i--)
    {
        swap(arr[0], arr[i]);           // 将当前最大的放置到数组末尾
        adjust(arr, i, 0);              // 将未完成排序的部分继续进行堆排序
    }
}

二叉树深度优先遍历dfs

前序遍历

//递归实现:根左右
void preOrder1(BinTree *root)
{
    if (root != NULL)
    {
        cout<<root->data<<endl;
        preOrder1(root->lchild);
        preOrder1(root->rchild);
    }
}
//非递归实现
/*注意,如前所述,我们将二叉树的每一个结点都看作根结点。因此,从整个二叉树的根结点root出发,一路向左,遇到的每一个结点都立即访问(它是根,同时也是其父亲的左子树的根,所以这个过程访问了“根和左”)并入栈,直到不能再左,转向右(这个“右”上哪找呢?当然是父亲的右儿子。父亲去哪里找呢?当然是栈里),将这个右儿子当成新的根结点重复上述过程,直到栈为空且当前根结点也为空。*/
void preOrder2(BinTree *root)
{
	stack<BinTree *> s;
	BinTree *p=root;
 	while (p!=NULL || !s.empty())
 	{
  		//一路向左
  		while (p!=NULL)
		{
			cout<<p->data<<endl;	 //访问根结点
			s.push(p);
   			p=p->lchild;
		}

		//当不能再左时,开始向右
  		if (!s.empty())
  		{
   			p=s.top();//从栈里面取出根结点
   			s.pop();
   			p=p->rchild;            //作为新的根结点
  		}
 	}
 }

中序遍历

//递归实现:左根右
void inOrder1(BinTree *root)
{
	if (root != NULL)
	{
  		inOrder1(root->lchild);
  		cout<<root->data<<endl;
  		inOrder1(root->rchild);
 	}
}
//非递归实现
/*与前序遍历类似,但是,根结点进栈时不访问(否则就成了前序遍历),根结点弹栈时才访问(左根右)。*/
void inOrder2(BinTree *root)
{
	stack<BinTree *> s;
	BinTree *p=root;

	while (p!=NULL || !s.empty())
	{
  		//一路向左
 		while (p!=NULL)
 		{
 			s.push(p);
 			p=p->lchild;
 		}

  		//当不能再左时,访问根结点,向右
  		if (!s.empty())
  		{
   			p=s.top();
   			cout<<p->data<<endl;	//在中间访问根结点
   			s.pop();
   			p=p->rchild;
  		}
	}
}

后序遍历

//递归实现:左右根
void postOrder1(BinTree *root)
{
	if (root != NULL)
	{
		postOrder1(root->lchild);
		postOrder1(root->rchild);
		cout<<p->data<<endl;
	}
}
//非递归实现
/*对任一结点p,边一路向左边进栈,直到其左儿子为空,这时,各个根结点在栈里存放。然后依次出栈,但是此时还不能访问(否则就是中序遍历了),出栈之后以当前根节点的右儿子设置为新的根节点,重复前述过程;直到当前根节点第二次出栈(说明它的左右儿子都已被访问),然后访问此根结点(左右根)。*/
typedef struct _poNode
{
	BinTree *btnode;
	bool isFirst;
} poNode;

void postOrder2(BinTree *root)
{
	stack<poNode *> s;
	BinTree *p=root;

	poNode *temp;

	while (p!=NULL || !s.empty())
	{
 		//一路向左直到不能再左
		while (p!=NULL)
		{
			temp = (poNode *)malloc(sizeof(poNode));
			temp->btnode = p;
			temp->isFirst = True;	 //第一次进栈标记
			s.push(temp);

			p=p->lchild;
		}

		if (!s.empty())
		{
			temp = s.top();	 //此时还不能访问,否则就是中序遍历了
			s.pop();

			//如果是第一次进栈,那还需要再进栈一次,之后以它的右儿子为新的根结点
			if (temp->isFirst == true)
			{
				temp->isFirst = false;
				s.push(temp);
				p = temp->btnode->rchild;
 			}
			else
			{
				cout<<temp->btnode->data<<endl;	//后序访问根结点
				p = NULL;	//不要忘了这一句,因为访问过根结点之后应该直接弹栈考察上一个父结点
			}
 		}
 	}
 }

二叉树的层次遍历

public static void treeBFS(TreeNode root) {
    //如果为空直接返回
    if (root == null)
        return;
    //队列
    Queue<TreeNode> queue = new LinkedList<>();
    //首先把根节点加入到队列中
    queue.add(root);
    //如果队列不为空就继续循环
    while (!queue.isEmpty()) {
        //poll方法相当于移除队列头部的元素
        TreeNode node = queue.poll();
        //打印当前节点
        System.out.println(node.val);
        //如果当前节点的左子树不为空,就把左子树
        //节点加入到队列中
        if (node.left != null)
            queue.add(node.left);
        //如果当前节点的右子树不为空,就把右子树
        //节点加入到队列中
        if (node.right != null)
            queue.add(node.right);
    }
}

转换进制

// 将10进制下的数字转为n进制
int toNBase(int num, int base){
	int res=0, factor=1;
	while(num){
		res += factor*(num%base);
		num /= base;
		factor *= 10;
	}
	return res;
}
// 将n进制下的数字转为10进制
int to10Base(int num,int base) {
    int res=0,factor=1;
    while(num) {
        res +=  factor*(num%10);
        num /= 10;
        factor *= base;
    }
    return res;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值