数组及链表的归并排序(C++实现)

本文只是对数组和链表的归并排序的代码记录,并不对算法原理进行过多的说明。并只对关键代码进行注释。


1.数组归并排序的递归实现(C++)

#include<iostream>

using namespace std;

template <typename T> 
void Merge(T *a,int low, int mid , int high)
{
    T *temp =  new T[high-low+1]; //申请临时缓存 
    int i = low , j = mid + 1 , k = 0;
    while( i<=mid&&j<=high)    
    {
        if( a[i] <= a[j] )       
        {
            temp[k++] = a[i++];    
        }
        else
        {
            temp[k++] = a[j++];
        }
    }
    
    while(i<=mid)    
    {
        temp[k++] = a[i++];
    }
    while(j<=high)    
    {
        temp[k++] = a[j++];
    }
    
    memcpy( a+low,temp,(high-low+1)*sizeof(T) );
    delete temp;
}

template <typename T>
void MergeSort(T *a,int low, int high)
{
    if( low<high )
    {
        int mid = ( ( high - low ) >> 1 ) + low;//定位中点 
        MergeSort(a,low,mid);  //递归实现 
        MergeSort(a,mid+1,high) ;
        Merge(a,low,mid,high);
    }
}
 
template <typename T>
void print(T *a , int len) 
{
    for(int i=0;i<len;i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;     
}

int main()
{
	int r[] = {10,3,5,1,9,34,54,565};
	int len = sizeof(r)/sizeof(r[0]);
	
	char rr[] = {'c','a','d','h','i','b','f','g'};
	MergeSort(r,0,len-1);
	MergeSort(rr,0,len-1);
	
	print(r,len) ;
	print(rr,len);

    system("pause");
    return 0;
}

2.数组归并排序的非递归实现

#include<iostream>

using namespace std;

template <typename T> 
void Merge(T *a,int low,int mid,int high)
{
    int i = low , j = mid + 1 , k = 0 ;
    T *temp = new T[high-low+1];
    while( i<=mid&&j<=high)
    {
        a[i]<a[j] ? ( temp[k++] = a[i++] ):(temp[k++]=a[j++]);
    }
    
    while(i<=mid)
    {
        temp[k++] = a[i++];             
    }
    while(j<=high)
    {
        temp[k++] = a[j++];              
    }
    memcpy( a+low,temp,(high-low+1)*sizeof(T) );
    free(temp);
}

template <typename T>
void MergeSort(T *a,int len)
{
    int step; //定义步长 
    for( step=1;step<len;step*=2 )//注意两个循环中的循环的控制条件 
    {
        int i;
        for( i=0;i+2*step<len;i+=2*step )     
        {
            Merge( a,i,i+step-1,i+2*step-1 );    
        }
        
        //剩下没能处理完的数再和前面的整体归并 
        if( i+step<=len-1 )
        {
            Merge(a,i,i+step-1,len-1);
        }
    }
}

template <typename T>
void print(T *a , int len) 
{
    for(int i=0;i<len;i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;     
}

int main()
{
	int r[] = {10,3,5,1,9,34,54,565,7};
	int len = sizeof(r)/sizeof(r[0]);
	
	char rr[] = {'c','a','d','h','i','b','f','g','e'};
	MergeSort(r,len);
	MergeSort(rr,len);

    print(r,len) ;
	print(rr,len);

    system("pause");
    return 0;
}

3.链表的插入排序

这里我用leetcode上面AC的代码来进行说明。

https://oj.leetcode.com/problems/insertion-sort-list/

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *insertionSortList(ListNode *head) 
    {
       	if( head == NULL || head->next==NULL)
	{
		return head;
	}

        ListNode *myhead = new ListNode(0);//创建头结点 
        myhead->next = head;
	ListNode *p  = myhead->next;
	ListNode *q;
	ListNode *t1;
	while(p->next!=NULL)
	{
		if( p->next->val >= p->val ) //找到前个节点大于后个节点的指针 
		{
			p = p->next;
			continue;
		}
		q = p->next;
		p->next = p->next->next;

		t1 = myhead;
		while( t1->next->val < q->val ) //从表头开始,找到可以插入的位置 
		{
			t1 = t1->next;
		}
		q->next = t1->next; //插入节点 
		t1->next = q;
	}
	return myhead->next;

    }
};

4.归并两个有序链表

https://oj.leetcode.com/problems/merge-two-sorted-lists/

非递归代码:

#include<iostream>

using namespace std;

struct ListNode 
{
    int val;
    struct ListNode *next;
    ListNode(int x):val(x),next(NULL) {}
};

void CreateList(ListNode *&head , int *arr,int len)
{
    head = new ListNode(arr[0])     ;
    ListNode *p = head;
    for(int i=1;i<len;i++)
    {
        ListNode *s  = new ListNode(arr[i]);
        p->next = s;
        p = p->next;
    }
}

void print(ListNode *p)
{
    if(p == NULL)      return ;
    
    while(p!=NULL)
    {
        cout<<p->val<<" ";              
        p = p->next;
    }
    cout<<endl;
}

//归并两个有序链表 
ListNode * Merge(ListNode *l1,ListNode *l2)
{
    ListNode *head = new ListNode(0);//关键是要创建一个头结点 
    ListNode *cur = head;
    while(l1!=NULL && l2!=NULL)//把归并的过程想清楚了,就没有问题了,代码一气呵成             
    {
        if( l1->val<l2->val )               
        {
            cur->next = l1;
            cur = l1;
            l1 = l1->next;   
        }
        else
        {
            cur->next = l2;
            cur = l2;
            l2 = l2->next;    
        }
    }
    if(l1!=NULL)  cur->next = l1;
    if(l2!=NULL)  cur->next = l2;
        
    return head->next;
}

int main()
{
    int a[] = {1,3,5,7,10}    ;
    int b[] = {-1,4,9,20};
    
    ListNode *l1 , *l2;
    
    CreateList(l1,a,sizeof(a)/sizeof(a[0]));
    CreateList(l2,b,sizeof(b)/sizeof(b[0])); 
    
    print(l1);
    print(l2);
    
    ListNode *head = Merge(l1,l2);
    
    print(head);
    
    system("pause") ;
    return 0;
    
} 

貌似函数里面忘记两个链表头指针判空了,但是还是过了。


递归代码:

#include<iostream>

using namespace std;

template <class T>
class tNode
{
public:
    T val;
    struct tNode *next;
    tNode(T x):val(x),next(NULL) {}
};

template <typename T>
void createList(T *a,int len,tNode<T> *&head)
{
    head = new tNode<T>(a[0])     ;
    tNode<T> *p = head;
    for(int i=1;i<len;i++)
    {
        tNode<T> *tmp = new tNode<T>(a[i]);
        p->next = tmp;
        p = tmp;
    }
}

template<typename T>
void print(tNode<T> *&head)
{
    tNode<T> *p = head;
    while(p!=NULL)
    {
        cout<<p->val<<" ";
        p = p->next;                     
    }
    cout<<endl;
}

template<typename T>
tNode<T> * merge_recursive(tNode<T> *p1,tNode<T> *p2)
{
    if( p1==NULL )    return p2;
    if( p2==NULL )    return p1;
    
    if( p1->val<p2->val )
    {
        tNode<T> *tmp = merge_recursive(p1->next,p2);
        p1->next = tmp;
        return p1;
    }
    else
    {
        tNode<T> *tmp = merge_recursive(p1,p2->next);
        p2->next = tmp; 
        return p2;
    }
}

int main()
{
    tNode<int> *head1,*head2,*newhead;
    //int a[] = {1,3,5,7,9};
    //int b[] = {2,6,8,12,14} ;
    int a[] = {5};
    int b[] = {1,2,4};
    createList( a,sizeof(a)/sizeof(a[0]),head1 );
    createList( b,sizeof(b)/sizeof(b[0]),head2 );
    print(head1);
    print(head2);
    bool flag = true;
    newhead = merge_recursive(head1,head2);
    print(newhead);
    
    system("pause");
    return 0;
} 

5.链表归并排序的递归实现

其实对于链表来说,最高效的应该就是归并排序了,时间复杂度为O(nlogn),空间复杂度为O(1)。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:

    ListNode *merge(ListNode *first,ListNode *second)
    {
    	ListNode *tmp = new ListNode(0);
    	ListNode *curr = tmp;
    
    	while(first!=NULL && second!=NULL)
    	{
    		if(first->val <= second->val)
    		{
    			curr->next = first;
    			first = first->next;
    		}	
    		else
    		{
    			curr->next = second;
    			second = second->next;
    		}
    		curr = curr->next;
    	}
    
    	if(first==NULL)
    	{
    		curr->next = second;
    	}
    	else if(second == NULL)
    	{
    		curr->next = first;
    	}
    
    	return tmp->next;

     }

    ListNode *sortList(ListNode *head) 
    {
        if(head == NULL)
    	{
    		return head;
    	}

    	ListNode *first = head;
    	ListNode *second = head;
    
    	//divide the list into two equal length list
    	while(second->next!=NULL && second->next->next!=NULL)
    	{
    		first = first->next;
    		second = second->next->next;
    	}
    
    	if(first->next!=NULL)
    	{
    		second = first->next;
    		first->next = NULL;
    		first = head;
    	}
    
    	if(first==second)
    	{
    		return first;
    	}
    	
    	return merge( sortList(first),sortList(second)  );
     }
};






C++ STL中的list容器提供了sort()函数,可以对链表进行排序。但是,由于链表的特殊性质,它不能像数组那样直接进行随机访问,因此在排序时需要使用归并排序算法。 具体实现方法如下: 1. 定义一个merge()函数,用于将两个有序链表合并成一个有序链表。 2. 定义一个mergeSort()函数,用于对链表进行归并排序。在该函数中,先将链表分成两个子链表,然后递归地对子链表进行排序,最后将两个有序子链表合并成一个有序链表。 3. 调用mergeSort()函数对整个链表进行排序。 以下是代码示例: ```c++ #include <iostream> #include <list> using namespace std; // 将两个有序链表合并成一个有序链表 void merge(list<int>& l1, list<int>& l2, list<int>& result) { auto it1 = l1.begin(); auto it2 = l2.begin(); while (it1 != l1.end() && it2 != l2.end()) { if (*it1 < *it2) { result.push_back(*it1); ++it1; } else { result.push_back(*it2); ++it2; } } while (it1 != l1.end()) { result.push_back(*it1); ++it1; } while (it2 != l2.end()) { result.push_back(*it2); ++it2; } } // 对链表进行归并排序 void mergeSort(list<int>& l) { if (l.size() <= 1) { return; } list<int> l1, l2; auto it = l.begin(); for (int i = 0; i < l.size() / 2; ++i) { l1.push_back(*it); ++it; } for (; it != l.end(); ++it) { l2.push_back(*it); } mergeSort(l1); mergeSort(l2); l.clear(); merge(l1, l2, l); } int main() { list<int> l = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; mergeSort(l); for (auto x : l) { cout << x << " "; } cout << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值