经典数据结构题目解析

链表

1.删除单链表的重复节点

遍历法

class Solution {
public:
    ListNode* removeDuplicateNodes(ListNode* head) {
        //先检查头节点是否为空,快速判断
        if (head == NULL) {
            return NULL;
        }  
        ListNode *current = head;
        //循环遍历检查每一个元素,如果有相同元素则去掉
        while (current) {
            ListNode *p = current;
            while (p->next) {
                if (p->next->val == current->val) {
                    ListNode *toDelete = p->next;
                    p->next = p->next->next;
                    delete toDelete; // 释放内存
                } else {
                    p = p->next;
                }
            }
            current = current->next;
        }
        return head;
    }
};

数组法:用一个数组指示,数组初始为0,一次遍历元素的值,出现就将数组对应值置1

2. 如何找出链表的倒数第K个元素

快慢指针法:快指针比慢指针快K个元素,当快指针指向末尾NULL时,此时慢指针指向倒数第K个元素。

class Solution {
public:
    //快慢指针:空间换时间
    ListNode* trainingPlan(ListNode* head, int cnt) {
        ListNode* fast=head;
        ListNode* slow=head;
        while(cnt--)
        {
            fast=fast->next;
        }
        while (fast)
        {
            fast=fast->next;
            slow=slow->next;
        }
        return slow;
    }
};

 3. 如何找出链表的中间节点

双指针:快指针走两步,满指针走一步

class Solution {
public:
    //双指针法
    ListNode* middleNode(ListNode* head) {
        ListNode* fast=head;
        ListNode* slow=head;
        while((fast!=NULL)&&(fast->next!=NULL))
        {
            fast=fast->next->next;
            slow=slow->next;
        }
        return slow;
    }
};

4. 反转链表

反转是逐个反转,例如反转1,2,3,4,5

先变成2,1,3,4,5

再3,2,1,4,5

依次直至最终反转

class Solution {
public:
    //递归实现反转链表
    ListNode* trainningPlan(ListNode* head) {
        if(head==NULL || head->next==NULL){
            return head;
        }
        else
        {
            struct ListNode* mid=head;
            struct ListNode* lateer=mid->next;
            head =trainningPlan(lateer);
            lateer->next=mid;
            mid->next=NULL;
            return head;
        }
    }
};

5.环形链表  

快慢指针:总会相遇,一个两部一个一步

class Solution {
public:
    //快慢指针,追到就是了
    bool hasCycle(ListNode *head) {
        ListNode *fast=head;
        ListNode *slow=head;
        while((fast!=NULL)&&(fast->next!=NULL))
        {
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow)
                return true;
        }
        return false;
    }
};

6. 单链表相交,如何求交点

移动相同的距离即是交点

class Solution {
public:
    //这不是判断是否相交,比较简单,判断交点则AD+BD+DC
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p=headA;
        ListNode *q=headB;
        while(p!=q)
        {
            if(p!=NULL)
                p=p->next;
            else
                p=headB;

            if(q!=NULL)
                q=q->next;
            else
                q=headA;   
        }
        return q;
    }
};

7. 回文链表

找链表中间位置。将后半链表反转,依次和链表前一部分比较,看是否一致。

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (head == NULL) return true;
        
        // 找到链表的中间节点
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != NULL && fast->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
        }
        
        // 反转链表的后半部分
        ListNode* mid = slow;
        ListNode* prev = NULL;
        while (mid != NULL) {
            ListNode* nextTemp = mid->next;
            mid->next = prev;
            prev = mid;
            mid = nextTemp;
        }
        
        // 将slow指向反转后链表的头节点
        slow = prev;
        
        // 比较前半部分和反转后的后半部分是否相同
        fast = head;
        while (slow != NULL) {
            if (fast->val != slow->val) {
                return false;
            }
            fast = fast->next;
            slow = slow->next;
        }
        return true;
    }
};

8. 算法实现两个有序链表的合并

递归实现,返回两个链表最小值,

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if(list1==NULL)
            return list2;
        if(list2==NULL)
            return list1;
        if(list1->val<list2->val)
        {
            list1->next= mergeTwoLists(list1->next,list2);
            return list1;
        }
        else
        {
            list2->next=mergeTwoLists(list1,list2->next);
            return list2;
        }
    }
};

树代码的核心操作在于递归

1.求二叉树的深度

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int calculateDepth(TreeNode* root) {
        if(root ==NULL)
        {
            return 0;
        }
        int Lenleft=calculateDepth(root->left);
        int lenright=calculateDepth(root->right);
        return Lenleft>lenright?Lenleft+1:lenright+1;
    }
};

2.如何判断二叉树是否相等

class Solution {
public:
    //用某种遍历方法,存储成数组,遍历一棵树后,看数组是否相等
    void preOrder(struct TreeNode *root,int *arr,int *i)
    {
        //用指针变量指示数组值的位置
        (*i)++;
        if(root==NULL)
        {
            *(arr+*i)=0;
            return;
        }
        *(arr+*i)=root->val; 
        preOrder(root->left,arr,i);
        preOrder(root->right,arr,i);
    }
    //前序遍历得到数组,再判断数组是否相等
    bool isSameTree(TreeNode* p, TreeNode* q) {
        int i,j;
        int arr1[1000],arr2[1000];
        memset(arr1,0,1000*sizeof(int));
        memset(arr2,0,1000*sizeof(int));
        if((p==NULL)&&(q==NULL))
            return 1;
        if((p==NULL)||(q==NULL))
            return 0;
        j=i=0;
        preOrder(p,arr1,&i);
        preOrder(q,arr2,&j);
        for(i=0;i<1000;i++)
        {
            if(arr1[i]!=arr2[i])
            {
                return 0;
            }
        }
        return 1;
    }
};

3. 判断二叉树是否是平衡二叉树

挨个判断每个节点是否平衡,核心就是递归;

class Solution 
{
public:
    int deptmax(TreeNode* root)
    {
        if(root==NULL)
        {
            return 0;
        }
        int leftdept=deptmax(root->left);
        int rightdept=deptmax(root->right);
        return leftdept>rightdept?leftdept+1:rightdept+1;
    }
    
    //判断每一个节点的左右子树的深度,如何减少复杂度,实则判断meiyih
    bool isBalanced(TreeNode* root) {
        if(root==NULL)
        {
            return true;
        }
        int leftdept=deptmax(root->left);
        int rightdept=deptmax(root->right);
        if(abs(leftdept-rightdept)<2==false)
        {
            return false;
        }
        return abs(leftdept-rightdept)<2&&isBalanced(root->left)&&isBalanced(root->right);
    }
};

 数组

最大子序和

动态规划小问题,值得一看

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
       int pre=0,maxans=nums[0];
       for(const auto &x:nums)
       {
        pre =max(pre+x,x);
        maxans=max(maxans,pre);
       } 
       return maxans;
    }
};

挨个判断将新元素加入子序列的影响。 

丢失的数字

哈希数组,异或,数学方法

题目可以有取巧的方法

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        // 1. 计算从 0 到 n 的理论总和
        int sum1 = (nums.size()+1) * (0 + nums.size()) / 2;
        
        // 2. 计算当前数组的实际总和
        int sum2 = 0;
        for(int num : nums)
            sum2 += num;
        
        // 3. 返回差值,即为缺失的数字
        return sum1 - sum2;
    }
};

按奇偶排序数组  

双指针法,交换元素

class Solution {
public:
    //双指针法,快指针遍历元素,慢指针移动位置
    vector<int> sortArrayByParity(vector<int>& nums) {
        int fast=0;
        int slow=0;
        int cur=0;
        for( fast=0;fast<nums.size();fast++)
        {
            if(nums[fast]%2==0)
            {
                cur=nums[slow];
                nums[slow]=nums[fast];
                nums[fast]=cur;
                slow++;
            }
        }
        return nums;
    }
};

数组是是否存在重复元素 

利用集合或者结构体哈希 

class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        int n = nums.size();
        unordered_map<int, bool> set;
        for(int i = 0; i < n; ++i){
            if(i > k) 
            set[nums[i - k - 1]] = false;
            if(set[nums[i]]) 
            return true;
            set[nums[i]] = true;
        }
        return false;
    }
};

有序数组出现次数超过25%的元素 

class Solution {
public:
    //哈希法,数学方法,有序数组。满足条件仍然是原数字
    int findSpecialInteger(vector<int>& arr) {  
        int n = arr.size();  
        for (int i = 0; i + n / 4 < n; ++i) {  
            if (arr[i] == arr[i + n / 4]) {  
                return arr[i];  
            }  
        }  
        return -1; // 如果没有找到符合条件的元素,返回-1  
    }  
};

 山脉数组

class Solution {
public:
    //山脉数组,满足先增后减的数组;
    //暴力法
    bool validMountainArray(vector<int>& arr) {
        int i=0;
        if(arr.size()<=2)
            return false;
        for(i=1;i<arr.size();i++)
        {
            if(arr[i]-arr[i-1]<=0)
                break;
            if(i==arr.size()-1)
            return false;
        }

        for(;i<arr.size();i++)
        {
             if(i==1)
            return false;
            if(arr[i]-arr[i-1]>=0)
                return false;
        }
        return true;
    }
};

 最长连续递增序列

class Solution {
public:
    //滑动窗口;特殊情况返回结果,不然就遍历一遍寻找最长的
    int findLengthOfLCIS(vector<int>& nums) {
        int numsSize=nums.size();
        if(numsSize == 0)
            return 0;
        if(numsSize == 1)
            return 1;
        int length = 1;
        int max = 1;
        for(int i = 0; i < numsSize - 1; i++){
            if(nums[i] < nums[i+1])
                length++;
            else
            length = 1;
            if(length > max)
        max = length;
        }
        return max;    
    }
};

字符串

有效的括号

 利用栈先进后出的思路来写

class Solution {
public:
    // 括号匹配函数
    bool isValid(const std::string& s) {
        std::stack<char> stack;
        
        for (char c : s) {
            // 如果是左括号,将其入栈
            if (c == '(' || c == '{' || c == '[') {
                stack.push(c);
            } else {
                // 出现右括号时检查栈是否为空
                if (stack.empty()) {
                    return false;
                }
                // 根据右括号类型检查栈顶是否匹配
                if ((c == ')' && stack.top() != '(') ||
                    (c == '}' && stack.top() != '{') ||
                    (c == ']' && stack.top() != '[')) {
                    return false;
                }
                stack.pop(); // 匹配则出栈
            }
        }
        // 栈为空则说明所有括号匹配
        return stack.empty();
    }
};

字符串相加

模拟成竖式相加,转换成整数类型来写

class Solution {
public:
    string addStrings(string num1, string num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        string ans = "";
        while (i >= 0 || j >= 0 || add != 0) {
            //强制转换成数字
            int x = i >= 0 ? num1[i] - '0' : 0;
            int y = j >= 0 ? num2[j] - '0' : 0;
            int result = x + y + add;
            ans.push_back('0' + result % 10);
            add = result / 10;
            i -= 1;
            j -= 1;
        }
        // 计算完以后的答案需要翻转过来
        reverse(ans.begin(), ans.end());
        return ans;
    }
};

二进制求和

 

和上一题一样的思路

class Solution {
public:
    string addBinary(string num1, string num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        string ans = "";
        while (i >= 0 || j >= 0 || add != 0) {
            //强制转换成数字
            int x = i >= 0 ? num1[i] - '0' : 0;
            int y = j >= 0 ? num2[j] - '0' : 0;
            int result = x + y + add;
            ans.push_back('0' + result % 2);
            add = result / 2;
            i -= 1;
            j -= 1;
        }
        // 计算完以后的答案需要翻转过来
        reverse(ans.begin(), ans.end());
        return ans;
    }
};

反转字符串

主要是掌握swap函数的用法,双指针法

class Solution {
    //字符串向量,难点在于使用O(1)的额外空间解决这一问题;不然直接逆序push_back就好了;vector向量没有赋值的操作
    //利用swap函数
public:
    void reverseString(vector<char>& s) {
        int left=0;
        int right=s.size()-1;
        while(left<right)
        {
            swap(s[left],s[right]);
            left++;
            right--;
        }
    }
};

反转字符串中的单词 

思路和上一题差不多,最主要就是分别逆转单词的条件

class Solution {
public:
    void reverseString(string& s,int left,int right) {
        
        while(left<right)
        {
            swap(s[left],s[right]);
            left++;
            right--;
        }
    }
    //仿照上题思路,主要在于找到每个单词的界限
    string reverseWords(string s) {
        int a=0;
        for(int i=0;i<=s.size();i++)
        {
            if(s[i]==' '|| (i==s.size()))
            {
                reverseString(s,a,i-1);
                 a=i+1;
            }  
        }
        return s;
    }
};

 验证回文串

主要是掌握isanum(ch):用于验证ch是否是字母或数字,是则返回trtol

tolower库函数将大小字符转换成小写

class Solution {
public:
    //先是处理字符串,然后再验证字符串。
    //边处理边比较,更能节省时间复杂度。
    bool isPalindrome(string s) {
        string sgood;
        for (char ch: s) {
            if (isalnum(ch)) {
                sgood += tolower(ch);
            }
        }
        int n = sgood.size();
        int left = 0, right = n - 1;
        while (left < right) {
           if (sgood[left] != sgood[right]) {
                return false;
            }
            ++left;
            --right;
        }
        return true;
    }
};

验证回文串2

using namespace std;
class Solution {
public:
    bool isPalindrome(const string& s, int left, int right) {
        while (left < right) {
            if (s[left] != s[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    
    bool validPalindrome(string s) {
        int left = 0;
        int right = s.size() - 1;

        while (left < right) {
            if (s[left] != s[right]) {
             // 如果发现字符不匹配,检查删除左侧字符或右侧字符后的子字符串是
             //否是回文
                return isPalindrome(s, left + 1, right)
                || isPalindrome(s, left, right - 1);
            }
            left++;
            right--;
        }
        
        return true;
    }
};

 根据字符出现频率排序

难点1在于了解unordered_map<char,int>类似字典的数据类型

难点2在于了解sort这种排序的算法

class Solution {
public:
    string frequencySort(string s) {
        unordered_map<char, int> mp;
        for(auto ch:s) mp[ch]++;
        sort(s.begin(),s.end(),[&](const char &a, const char &b){
            return mp[a]==mp[b] ? a>b : mp[a]>mp[b];
        });
        return s;
    }
};

前K个高频单词 

1. 对于字符串可以利用unordered_map< , >数据类型

2. 取出所有键值对,将键值存储到变量当中

3.sort(数组起始,数组结束,[&]排序规则)

[&]字符串1,字符串2

{

排序规则(字符串对应的键值)
}

class Solution {
public:
    vector<string> topKFrequent(vector<string>& words, int k) {
        unordered_map<string, int> mp;
        for (auto& str : words) {
            mp[str]++;
        }

        vector<string> keys;
        for (const auto& pair : mp) {
            keys.push_back(pair.first);
        }

        sort(keys.begin(), keys.end(), 
        [&](const string& a, const string& b) 
        {
            if (mp[a] == mp[b]) {
                return a < b;  
            }
            return mp[a] > mp[b];  
        });
        
        return vector<string>(keys.begin(), keys.begin() + k);
    }
};

 计数二进制子串

代码思路不难考察的是数学思路;

根据题目判断符合子序列要求。

class Solution {
public:
    int countBinarySubstrings(string s) {
        int n=0,pre=0,cur=1,len=s.size()-1;
        for(int i=0;i<len;i++)
        {
            if(s[i]==s[i+1])
            {
                ++cur;
            }
            else
            {
                pre=cur;
                cur=1;
            }
            if(pre>=cur)
            ++n;
        }
        return n;
    }
};

实现字符串的库函数

atoi(将字符串转换成整数)

itoa:将整数转成字符串

排序算法及其改进方法

快速排序

中间轴加递归

交换函数,中枢轴的确定,交换排序,递归调用

#include <iostream>
#include <cstdlib>  // 包含随机数生成的库

// 交换两个元素的值
void Swap(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}

// 快速排序函数
void QuickSort(int arr[], int left, int right) {
	// 如果数组只有一个元素或无元素,直接返回
	if (left >= right) {
		return; 
	}

	// 随机选择枢轴,或固定选择左轴
	int pivotIndex = left;// +rand() % (right - left + 1);
	int pivot = arr[pivotIndex];  
	
	// i 指向小于枢轴的区域的末尾
	int i = left;  
	// j 指向当前待检查的元素
	int j = left + 1; 

	// 通过遍历将小于枢轴的元素移到左边,大于枢轴的元素移到右边
	while (j <= right) {
		//大于不交换,小于的时候把大于指向的元素进行交换
		if (arr[j] < pivot) {
			i++;
			// 将小于枢轴的元素交换到左边
			Swap(arr[i], arr[j]);  
		}
		j++;
	}

	// 将枢轴放到正确的位置,交换
	Swap(arr[left], arr[i]);

	// 递归排序枢轴左侧和右侧的元素
	QuickSort(arr, left, i - 1);   // 排序左侧
	QuickSort(arr, i + 1, right);  // 排序右侧
}

// 打印数组
void PrintArray(int arr[], int size) {
	for (int i = 0; i < size; i++) {
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;
}

int main() {
	// 初始化一个数组
	int arr[] = { 50, 20, 60, 40, 10, 30 };
	int size = sizeof(arr) / sizeof(arr[0]);

	std::cout << "排序前的数组: ";
	PrintArray(arr, size);

	// 执行快速排序
	QuickSort(arr, 0, size - 1);

	std::cout << "排序后的数组: ";
	PrintArray(arr, size);

	return 0;
}

冒泡排序

遍历+逐个比较

#include <iostream>

// 带跳出条件的冒泡排序函数
void bubbleSort(int* arr, int n) {
	for (int i = 0; i < n - 1; i++) {
		bool swapped = false; // 标记是否发生交换

		// 每次遍历,逐步将最大元素移到最后
		for (int j = 0; j < n - 1 - i; j++) {
			if (arr[j] > arr[j + 1]) {
				// 交换相邻元素
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
				swapped = true; // 发生了交换
			}
		}

		// 如果没有发生任何交换,说明数组已经有序,提前跳出
		if (!swapped) {
			break;
		}
	}
}

// 打印数组
void printArray(int* arr, int n) {
	for (int i = 0; i < n; i++) {
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;
}

int main() {
	int arr[] = { 64, 34, 25, 12, 22, 11, 90 };
	int n = sizeof(arr) / sizeof(arr[0]);

	std::cout << "排序前的数组: ";
	printArray(arr, n);

	// 执行带跳出条件的冒泡排序
	bubbleSort(arr, n);

	std::cout << "排序后的数组: ";
	printArray(arr, n);

	return 0;
}

堆排序

原理:

插入排序

将元素插入到顺序表中,适用于链表,数组插入复杂度有点高,可以采用二分查找法

#include <iostream>

typedef int Mytype;  // 定义类型Mytype为int,你也可以根据需要更改为其他类型

void InsertSort(Mytype a[], int n) {
	// 注意从第二个元素开始
	for (int i = 1; i < n; i++) {
		// 如果a[i-1]本来就是小于a[i]的,就不需要做任何操作
		if (a[i] < a[i - 1]) {
			int j = i - 1;
			int x = a[i];  // 暂存a[i]的值
			// 从第j个元素开始,找一个比x小的位置
			while (j >= 0 && x < a[j]) {
				// 顺序查找同时将数组元素后移
				a[j + 1] = a[j];
				j--;
			}
			// 插入到正确的位置
			a[j + 1] = x;
		}
	}
}

int main() {
	Mytype arr[] = { 34, 8, 64, 51, 32, 21 };
	int n = sizeof(arr) / sizeof(arr[0]);

	std::cout << "Array before sorting: ";
	for (int i = 0; i < n; i++) {
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;

	InsertSort(arr, n);

	std::cout << "Array after sorting: ";
	for (int i = 0; i < n; i++) {
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;

	return 0;
}

选择排序

 逐个遍历选择出未排序序列的极值进行排序

#include <iostream>

typedef int Mytype;  // 定义类型 Mytype 为 int,可以根据需求更改

/**
* @Description: 从 i 的位置开始,寻找最大值的位置
* @Param: int arr[] 数组名, int i 查找最大值开始的位置, int n 数组长度
* @Return: 最大值的位置
* @Author: Carlos
*/
int FindMaxPos1(Mytype arr[], int i, int n) {
	// 假设第 i 的位置为最大值
	int max = i;
	// 从 i+1 开始比较
	while (i + 1 < n) {
		if (arr[max] < arr[i + 1]) {
			max = i + 1;
		}
		i++;
	}
	return max;
}

/**
* @Description: 从 i 的位置开始,寻找最小值的位置
* @Param: int arr[] 数组名, int i 查找最小值开始的位置, int n 数组长度
* @Return: 最小值的位置
* @Author: Carlos
*/
int FindMinPos1(Mytype arr[], int i, int n) {
	// 假设第 i 的位置为最小值
	int min = i;
	// 从 i+1 开始比较
	while (i + 1 < n) {
		if (arr[min] > arr[i + 1]) {
			min = i + 1;
		}
		i++;
	}
	return min;
}

int main() {
	Mytype arr[] = { 34, 8, 64, 51, 32, 21 };
	int n = sizeof(arr) / sizeof(arr[0]);

	int maxPos = FindMaxPos1(arr, 0, n);
	int minPos = FindMinPos1(arr, 0, n);

	std::cout << "Maximum value is at position: " << maxPos << " with value: " << arr[maxPos] << std::endl;
	std::cout << "Minimum value is at position: " << minPos << " with value: " << arr[minPos] << std::endl;

	return 0;
}

归并排序

归并排序就是拆成多个子序列,然后递归调用归并进行排序,归并是归并已经排序好的,一开始是一个元素后面是半个子序列

#include <iostream>
#define MAXSIZE 10
using namespace std;

// 实现归并,并把最后的结果存放到list1里
void merging(int *list1, int list1_size, int *list2, int list2_size) {
    int i, j, k, m;
    int temp[MAXSIZE];
    i = j = k = 0;

    // 合并两个有序数组
    while (i < list1_size && j < list2_size) {
        if (list1[i] < list2[j]) {
            temp[k++] = list1[i++];
        } else {
            temp[k++] = list2[j++];
        }
    }

    // 复制剩余的元素
    while (i < list1_size) {
        temp[k++] = list1[i++];
    }
    while (j < list2_size) {
        temp[k++] = list2[j++];
    }

    // 将合并的结果复制回list1
    for (m = 0; m < (list1_size + list2_size); m++) {
        list1[m] = temp[m];
    }
}

// 递归实现的归并排序
void MergeSort(int k[], int n) {
    if (n > 1) {
        int *list1 = k;
        int list1_size = n / 2;
        int *list2 = k + n / 2;
        int list2_size = n - list1_size;

        // 对两个子数组分别进行归并排序
        MergeSort(list1, list1_size);
        MergeSort(list2, list2_size);

        // 合并两个排序后的子数组
        merging(list1, list1_size, list2, list2_size);
    }
}

int main() {
    int i, a[MAXSIZE] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
    
    cout << "排序前的数组是:";
    for (i = 0; i < MAXSIZE; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    // 调用递归版本的归并排序
    MergeSort(a, MAXSIZE);

    cout << "排序后的数组是:";
    for (i = 0; i < MAXSIZE; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    return 0;
}

希尔排序

  • 通过设置 gap 使得待排序的数组被分成若干个子序列,每个子序列独立排序。
  • 随着 gap 不断减小,最后的排序是对整个数组进行的插入排序。
  • 这种排序方式比单纯的插入排序更快,尤其在数组接近有序的情况下。
#include <iostream>
using namespace std;

/**
 * @Description: 希尔排序算法(升序排序)
 * @Param: int arr[] 数组名, int len 数组长度
 * @Return: void
 */
void shell_sort(int arr[], int len) {
	int gap, i, j;
	int temp;

	// 初始化 gap(间隔),每次将 gap 减小一半
	for (gap = len / 2; gap > 0; gap /= 2) {
		// 从 gap 开始,对每个元素进行插入排序
		for (i = gap; i < len; i++) {
			temp = arr[i];  // 暂存当前元素
			// 通过 gap 进行插入排序
			for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
				arr[j] = arr[j - gap];  // 向右移动元素
			}
			arr[j] = temp;  // 插入到正确位置
		}
	}
}

int main() {
	int arr[] = { 12, 34, 54, 2, 3 };
	int len = sizeof(arr) / sizeof(arr[0]);

	cout << "排序前的数组是:";
	for (int i = 0; i < len; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;

	// 调用希尔排序算法
	shell_sort(arr, len);

	cout << "排序后的数组是:";
	for (int i = 0; i < len; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值