每日算法之2

每日算法之2

1.之两个非递减的数组合并为一个数组保持依然有序

	//问题描述:两个非递减数组,A,B,A具有足够的内存容纳B,要求将两个数组合并为一个数组,保持数组依然非递减

//算法分析:从B数组中第一个元素开始,依次与数组A的尾部至头部开始扫描比较,如果小于,则后移一位,下标前移一位,继续比较,直到找到非小于的位置,将其插入当前的后一位;遍历完B数组,则循环结束

//算法实现;
void mergeSort(int A[],int B[],int a_length,int b_length){
    if(A==NULL || B==NULL ){
        cout<<"error!"<<endl;
        return;
    }
    if(a_length>b_length){
        int j=a_length-b_length-1;//表示指向A数组的下标
        int i;//表示指向B数组的下标
        int k=a_length-1;
        for(i=b_length-1;i>=0 && j>=0;--i){//表示遍历B数组的元素
            for(j;j>=0;--j){
                if(B[i]>=A[j]){
                    A[k--]=B[i];
                    break;                        
                }                
                else
                    A[k--]=A[j];
            }
        }
        if(i+1>=0){//将B数组剩余元素从头开始依次填入A数组,记得由于上次循环退出时,是自动减了1 
            for(int p=0;p<=i+1;++p){
                A[p]=B[p];
            }
        }              
    }
}


int main(){
	//测试用例
	int a[10]={4,5,6,8,10,34};
	int b[4]={3,5,9,18}; 
	mergeSort(a,b,10,4);
	for(int i=0;i<10;++i)
		cout<<a[i]<<" ";	
} 
//虽然使用了两个循环,但是没执行一次比较,必会干掉一个最大值放在后面,也就是说,从思路上就能判断出基本操作次数最坏情况下为两个序列的长度和,所以时间复杂度为O(n),即线性时间


//其他优秀的算法代码分析:
/**
     * 合并两个有序数组,合并后仍然有序
     * @param a 要合并的数组A
     * @param b 要合并的数组B
     * @param c 合并后的数组C
     */
void merge(int a[] ,int b[],int c[]){
        //1.传入函数的参数必须考虑周全,传入什么参数,有什么作用,考虑是值传递还是引用传递,需不需
        	//要加const常量进行限定
        int lengthA = a.length;
        int lengthB = b.length; 
        //2.首先将此函数需要使用的局部变量定义好,标识符要有实际意义,尽量避免使用i,k,l,否则
        	//阅读你的代码真是一件头疼的事情
        
        int indexA = 0;
        int indexB = 0;
        int indexC = 0;
        
        //3.使用循环必须充分考虑好退出条件,是否存在其他退出循环的情况
        while(indexA < lengthA && indexB < lengthB){
            if(a[indexA] < b[indexB]){
                c[indexC++] = a[indexA++];
            }else{                
                c[indexC++] = b[indexB++];
            }
        }
        //4.当退出循环时,这个遍历指针或者下标是否自动前移?
        	//此外,当循环结束,是否真的完成了?
        while(indexA < lengthA){
            c[indexC++] = a[indexA++];            
        }
        while (indexB < lengthB) {
            c[indexC++] = b[indexB++];            
        }
        //5.使用循环最头疼的就是边界条件,只要记住一点,编号,第几号和个数,第几个不要混用就OK了
    }

2.之链表操作-反向输出链表

链表的特点:是一种动态的数据结构,传入链表时,只需要传入头结点指针即可,不需要指定长度

//问题描述:输入一个链表,将一个带头结点的链表反转输出
	//第一种方法
struct LNode{
    int data;
    struct LNode *next;
};
void reverse_list(LNode *A){
    LNode *curLNode,*nextLNode,*tempLNode;//定义当前指针和下一个指针以及一个临时指针
    
    curLNode=A->next;
    nextLNode=curLNode->next;//进行初始化操作
    
    curLNode->next=NULL;
    while(nextLNode!=NULL){//当下一个节点为空时,退出循环
        tempLNode=curLNode;
        curLNode=nextLNode;
        nextLNode=nextLNode->next;//每次反转之前需要后移一位,并使用临时变量记住上次的节点
        
        curLNode->next=tempLNode;//将当前的节点指针反转指向临时节点
    }
    A->next=curLNode;//最后将头结点指针重新指向反转后的第一个节点
}


void createList(LNode *A,const int data[],int length){
    //1.使用头插法创建一个链表,并将一个数组赋值给链表节点的数据域,由于使用的是头插法,所以数组的数据顺序
	//是逆序的!!
	LNode *firstLNode;//定义一个指向链表第一个节点的指针
    LNode *newLNode;//定义一个需要插入个新节点指针
    
    A=new LNode;//由于传入的只是一个指向节点的指针,所以创建时必须new出一个指针,并指向它!!!
    A->next=NULL;//初始化头结点指针
    
    for(int i=0;i<length;++i){
        newLNode= new LNode;
        newLNode->data=data[i];
        
        firstLNode=A->next;
        newLNode->next=firstLNode;
        A->next=newLNode;//第一次虽然指向空节点,但正好将尾节点初始化为NULL,一举两得!!
    }   
    
    //2.使用尾插法正向插入数组数据
    LNode *lastLNode;
    LNode *newLNode;
    
    A=new LNode;
    A->next=NULL;
    
    lastLNode=A;//初始化尾节点
    for(int i=0;i<length;++i){
		newLNode= new LNode;
        newLNode->data=data[i];
        
        lastLNode->next=newLNode;
        lastLNode=lastLNode->next;
    }
    lastLNode->next=NULL;//插入完毕必须初始化尾节点指针域
}

//打印链表
void printfList( LNode *A){
    LNode *index;
    for(index=A;index->next!=NULL;index=index->next){//由于是带头结点的链表
        cout<<index->next->data<<" ";//index为当前指针节点,但是打印输出时却是下一个节点
    }
    cout<<endl;
}
//测试用例:
int main(){
	
	int a[10]={1,2,3,4,5,6,7,8,9,10};
	LNode *list;
	createList(list,a,10);
	printfList(list);
    
	reverse_list(list);
	printfList(list);
		 
}
		//第二种方法
//第一种方法需要修改链表,如果要求不能修改数据结构,改变策略,由于要求将链表逆序输出,可以先正向遍历
	//将其存入一个栈中,利用栈的后进先出的特点,从而实现逆序
//算法实现:
void reversePrintfList_useListStack(LNode *A){//必须使用一个链表栈实现
    LNode *indexA,*indexS;//链表A和S的指针迭代器
    LNode *stack_t_LNode;//栈的头结点
    LNode *new_s_LNode;//栈的新插入的节点
    LNode *first_s_LNode;//表示栈的第一个节点
    
    stack_t_LNode=new LNode;
    stack_t_LNode->next=NULL;//初始化链表栈,必须使用头插法
    
    for(indexA=A;indexA->next!=NULL;indexA=indexA->next){
        new_s_LNode=new LNode;
        new_s_LNode->data=indexA->next->data;//压入栈
        
        first_s_LNode=stack_t_LNode->next;
        new_s_LNode->next=first_s_LNode;
        stack_t_LNode->next=new_s_LNode;//使用头插法连接到栈中
    }
    
    //将栈遍历输出
    for(indexS=stack_t_LNode;indexS->next!=NULL;indexS=indexS->next){
		cout<<indexS->next->data<<" ";
    }
    cout<<endl;
    delete[] stack_t_LNode;
}

		//第三种方法
//既然使用自定义链表栈实现反向输出,为何不使用一个简单的递归函数,直接两三行代码实现递归栈的反转输出
void reversePrintfList_useRecursion(LNode *A){
    if(A!=NULL){
        if(A->next!=NULL){
            reversePrintfList_useRecursion(A->next);
        }
        cout<<A->data<<" ";
    }
}//该办法有一个缺点,如果将带头结点的链表传入,头结点的data域也会被访问打印,解决办法只能再调用的时候,将头结点过滤掉!!!
//比如:
reversePrintfList_useRecursion(A->next);

3.之二叉树的三种遍历考察[重点]

//掌二叉树的八大遍历实现,构建;;掌握完全二叉树搜索树,最大小堆,红黑树,字典树		

		//使用先序遍历构建二叉树
typedef struct BTNode{
    char data;
    struct BTNode *lchild,*rchild;
}BTNode;

//逻辑存在严重的错误!!
//算法分析:使用先序遍历将字符串数组"ABDG##H###CE##F##"构建成一棵二叉树
void createBTree_usePreorder(BTNode *B,char *data){

    int index_data;
    
    index_data=0;
    
    if(data[index_data]!='\0'){
        if(data[index_data]=='#')
            B=NULL;//表示为叶节点
        else{
            B=new BTNode;
            B->data=data[index_data];
            createBTree_usePreorder(B->lchild,data+1);
            createBTree_usePreorder(B->rchild,data+1);
        }
    }
}



		//二叉树的四种遍历方式:三种深度优先的递归实现和借助栈的非递归实现;
		//一种借助队列实现广度优先的非递归实现
//1.先序遍历的递归实现和非递归实现
//递归实现:
void BTree_preorder(BTNode *B){
    if(B!=NULL){
        cout<<B->data<<" ";
        BTree_preorder(B->lchild);
        BTree_preorder(B->rchild);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章