排序算法终结总结<Java实现>

/**
 * 排序算法学习之希尔排序
 * 实现方法:
 * 希尔排序是特殊的插入排序
 * 插入排序按照处理的子数组长度递增分为多趟插入操作
 * 而每一趟插入操作处理的子数组元素索引间隔都是1(即步长)
 * 希尔排序每趟处理的子数组元素索引间隔是动态的。
 */
package 排序算法.shellSort;

public class ShellSort {
	/**
	 * 对输入数组进行希尔排序
	 * @param a 待排序数组,索引有效范围从0开始
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void shellSort(Comparable[] a) {
		int incr = a.length / 2;//初始步长
		while (incr >= 1) {
			for (int i = incr; i < a.length; i++) {
				Comparable insertElement = a[i];
				int j;
				for (j = i - incr; j >= 0 &&      
                                     insertElement.compareTo(a[j]) < 0; j -= incr)
					a[j + incr] = a[j];
				a[j + incr] = insertElement;
			}
			if (incr == 2)
				incr = 1; 
			else
				incr = (int) (incr / 2.2);
		}
	}
}


 

/**
 * 排序算法学习之选择排序
 * 实现方法:
 * 每次选择子数组中最大的元素依次排列在子数组末尾,
 * 子数组的长度依次递减。
 */
package 排序算法.selectionSort;

public class SelectionSort {
	@SuppressWarnings({ "rawtypes", "unchecked" })
	/**
	 * 查找指定长度的数组中最大元素的索引
	 * @param a 指定数组
	 * @param n 数组长度
	 * @return 最大元素的索引
	 */
	public static int max(Comparable[] a, int n) {
		if (n < 0)
			throw new IllegalArgumentException("数组为空");
		int positionOfCurrentMax = 0;
		for (int i = 1; i <= n; i++)
			if (a[positionOfCurrentMax].compareTo(a[i]) < 0)
				positionOfCurrentMax = i;
		return positionOfCurrentMax;
	}

	/**
	 * 交换指定数组中指定索引的元素
	 * @param a 指定数组
	 * @param i 第一个索引
	 * @param j 第二个索引
	 */
	public static void swap(Object[] a, int i, int j) {
		Object temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	/**
	 * 对输入数组执行一般选择排序
	 * @param a 输入数组
	 */
	@SuppressWarnings("rawtypes")
	public void selectionSort(Comparable[] a) {
		//按照子数组长度递减的顺序进行每趟的选择操作
		for (int size = a.length; size > 1; size--) {
			int j = max(a, size - 1);
			swap(a, j, size - 1);
		}
	}

	/**
	 * 对输入数组执行早结束版本的选择排序
	 * @param a 输入数组,数组索引有效范围从0开始
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public  void selectionSort2(Comparable[] a) {
		boolean sorted = false;//当前子数组是否有序的标志
		for (int size = a.length; !sorted && (size > 1); size--) {
			int pos = 0;
			sorted = true;
			for (int i = 1; i < size; i++)
				if (a[pos].compareTo(a[i]) <= 0)
					pos = i;
				else
					sorted = false;
			swap(a, pos, size - 1);
		}
	}

}


 

/**
 * 秩排序实现2
 * @author Sking
 */
package 排序算法.rankSort;

public class RankSort2 {
	/**
	 * 对指定数组执行秩排序
	 * @param a 待排序数组
	 */
	@SuppressWarnings("rawtypes")
	private  void rankSort2(Comparable[] a) {
		int[] r = new int[a.length];
		rank(a, r);//求数组元素的秩
		rearrange(a, r);//移动元素到索引为其秩的位置
	}
	/**
	 * 交换指定数组中的两个元素
	 * @param a 指定数组
	 * @param i 第一个元素的索引值
	 * @param j 第二个元素的索引值
	 */
	  @SuppressWarnings("rawtypes")
	private static void swap(Comparable[] a, int i, int j)
	   {
		  Comparable temp = a[i];
	      a[i] = a[j];
	      a[j] = temp;
	   }
	  
		/**
		 * 交换秩数组中的两个元素
		 * @param a 指定的秩数组
		 * @param i 第一个元素的索引值
		 * @param j 第二个元素的索引值
		 */
	  private static void swap(int[] a, int i, int j)//重载交换方法
	   {
	      int temp = a[i];
	      a[i] = a[j];
	      a[j] = temp;
	   }
	  
	 /**
	  * 根据秩数组对待排序数组进行排序
	  * @param a 待排序数组
	  * @param r 待排序数组的秩数组
	  */
	@SuppressWarnings("rawtypes")
	private static void rearrange(Comparable[] a, int[] r) {
		for (int i = 0; i < a.length; i++)
			//依次检查位置i,如果有i=r[i]则表示元素i位置正确
			//否则交换位置i和位置r[i]上的元素(r[i]指出索引i位置
			//上的元素在排序数组中药位于r[i]的位置。
			while (r[i] != i) {
				int t = r[i];
				swap(a, i, t);
				swap(r, i, t);
			}
	}
	/**
	 * 求指定数组元素的秩,存放在给定数组中
	 * @param a 待排序数组
	 * @param r 给定的存放元素秩的数组
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void rank(Comparable[] a, int[] r) {
		if (r.length < a.length)
			throw new IllegalArgumentException("秩数组长度异常!");
		for (int i = 0; i < a.length; i++)
			r[i] = 0;
		for (int i = 1; i < a.length; i++)
			for (int j = 0; j < i; j++)
				//当左边的元素小于等于右边的元素时,右边元素的秩加1
				if (a[j].compareTo(a[i]) <= 0)
					r[i]++;
				else
				//当左边的元素不小于右边的元素时,左边的元素的秩加1
					r[j]++;
	}
	
}


 

/**
 * 排序算法学习之秩排序
 *@author Sking
 秩的定义: 一个序列中元素的秩被定义为序列中小于该元素的的元素
  个数加上出现在其左边的相等元素的个数。则可知一个元素在排序序列
  中的位置索引就是它们的秩。
  
 实现方法:
 1.计算待排序数组元素的秩
 2.将数组元素移动到索引值为他们的秩的位置  
 */

package 排序算法.rankSort;

public class RankSort1 {
	/**
	 * 对指定数组执行秩排序
	 * @param a 待排序的数组
	 */
	@SuppressWarnings("rawtypes")
	public  void rankSort(Comparable[] a) {
		int[] r = new int[a.length];
		rank(a, r);//求待排序数组元素的秩
		rearrange(a, r);//移动元素到索引为他们秩的位置,实现排序
	}
	
	/**
	 * 使用数组元素的秩数组对数组进行排序
	 * @param a 待排序数组
	 * @param r 待排序数组元素的秩数组
	 */
	@SuppressWarnings("rawtypes")
	private static void rearrange(Comparable[] a, int[] r) {
		Comparable[] u = new Comparable[a.length];
		for (int i = 0; i < a.length; i++)
			//移动元素到索引为他们秩的位置,实现排序
			u[r[i]] = a[i];
		for (int i = 0; i < a.length; i++)
			a[i] = u[i];
	}
	
	/**
	 * 求指定数组元素的秩,存放在给定数组中
	 * @param a 待排序数组
	 * @param r 给定的存放元素秩的数组
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void rank(Comparable[] a, int[] r) {
		if (r.length < a.length)
			throw new IllegalArgumentException("秩数组长度异常!");
		for (int i = 0; i < a.length; i++)
			r[i] = 0;
		for (int i = 1; i < a.length; i++)
			for (int j = 0; j < i; j++)
				//当左边的元素小于等于右边的元素时,右边元素的秩加1
				if (a[j].compareTo(a[i]) <= 0)
					r[i]++;
				else
			  //当左边的元素不小于右边的元素时,左边的元素的秩加1
					r[j]++;
	}
	

}


 

/**
 * 排序算法学习之快速排序的非递归实现,使用辅助栈
 * @author Sking
 */
package 排序算法.quickSort;

import 栈.ArrayStack;
public class QuickSort2 {
	/**
	 * 使用子数组的首个元素作为枢纽,划分子数组 划分后,
	 * 枢纽左边的元素均小于枢纽,右边的元素均大于枢纽 
	 * 并返回划分的位置索引,是快速排序的核心方法
	 * 
	 * @param a 待排序数组
	 * @param p 子数组的开始索引
	 * @param r 子数组的结束索引
	 * @return 划分的索引位置
	 */
	@SuppressWarnings({ })
	private int partition(int[] a, int p, int r) {
		int i = p, j = r + 1;
		int x = a[p];// 使用子数组的首个元素作为枢纽
		while (true) {
			// 从左边开始找到大于枢纽的元素索引
			while (a[++i] < x && i < r);
			// 同时从右边开始找到小于枢纽的元素索引
			while (a[--j]> x);
			if (i >= j)
				break;
			// 交换大于枢纽的元素到右边,小于枢纽的元素导左边
			swap(a, i, j);
		}// a[i]>=枢纽,a[j]<=枢纽,i>=j的时候表示已经划分完毕
		a[p] = a[j];// 交换枢纽索引位置所在元素和枢纽
		a[j] = x;
		return j;// j为枢纽索引
	}

	/**
	 * 交换指定数组中的两个元素
	 * @param a 指定数组
	 * @param i  第一个元素的索引
	 * @param j  第二个元素的索引
	 */
	public static void swap(int[] a, int i, int j) {
		int temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

	/**
	 * 快速排序算法的非递归实现,使用辅助栈
	 * @param a 待排序的数组段
	 * @param p  数组段的左端索引
	 * @param r 数组段的右端索引
	 */
	@SuppressWarnings({ "unused" })
	private void qSort(int[] a, int p, int r) {
		ArrayStack stack = new ArrayStack();// 栈
		if (p < r) {
			int mid = partition(a, p, r);
			if (p < mid - 1) {
				stack.push(p);
				stack.push(mid - 1);
			}
			if (mid + 1 < r) {
				stack.push(mid + 1);
				stack.push(r);
			}
			while (!stack.empty()) {
				int m = (int) stack.pop();
				int n = (int) stack.pop();
				int l = partition(a, n, m);
				if (n < l - 1) {
					stack.push(n);
					stack.push(l - 1);
				}
				if (l + 1 < m) {
					stack.push(l + 1);
					stack.push(m);
				}
			}
		}
	}

}


 

/**
 * 排序算法学习之快速排序
 * @author Sking
 实现方法:
通过把一个数组递归的划分为两个子数组。 
递归的基本步骤:
1. 把数组划分成以一个元素为枢纽的左右两个子数组。 
2. 调用自身的左边和右边以步骤1递归。 

性能障碍:
对枢纽数据的选择是影响排序的效率。
 
 性能:
 最坏时间复杂度:O(n^2)
 平均时间复杂度:O(n*log(n))
 辅助空间:O(n)或O(log(n))
 稳定性:不稳定
 时间复杂度是O(n*log(n))
 */
package 排序算法.quickSort;

public class QuickSort {
	@SuppressWarnings("rawtypes")
	/**
	 * 递归划分子数组a[p....r]
	 * @param a 指定数组,索引有效范围从0开始
	 * @param p 子数组的开始索引
	 * @param r 子数组的结束索引
	 */
	private void qSort(Comparable[] a,int p, int r) {
		if (p < r) {
			int q = partition(a,p, r);//划分的位置索引
			qSort(a,p, q - 1);//递归划分
			qSort(a,q + 1, r);
		}
	}

	/**
	 * 使用子数组的首个元素作为枢纽,划分子数组
	 * 划分后,枢纽左边的元素均小于枢纽,右边的元素均大于枢纽
	 * 并返回划分的位置索引,是快速排序的核心方法
	 * @param a 待排序数组
	 * @param p 子数组的开始索引
	 * @param r 子数组的结束索引
	 * @return 划分的索引位置
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private int partition(Comparable[] a,int p, int r) {
		int i = p, j = r + 1;
		Comparable x = a[p];//使用子数组的首个元素作为枢纽
		while (true) {
			//从左边开始找到大于枢纽的元素索引
			while (a[++i].compareTo(x) < 0 && i < r);
			//同时从右边开始找到小于枢纽的元素索引
			while (a[--j].compareTo(x) > 0);
			if (i >= j)
				break;
			//交换大于枢纽的元素到右边,小于枢纽的元素导左边
			swap(a,i, j);
		}//a[i]>=枢纽,a[j]<=枢纽,i>=j的时候表示已经划分完毕
		a[p] = a[j];//交换枢纽索引位置所在元素和枢纽
		a[j] = x;
		return j;//j为枢纽索引
	}

	/**
	 * 交换指定数组中的两个元素
	 * @param a 指定数组
	 * @param i 第一个元素的索引
	 * @param j 第二个元素的索引
	 */
	@SuppressWarnings("rawtypes")
	public static void swap(Comparable[] a,int i, int j) {
		Comparable temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}

}


 

/**
 * 排序算法学习之一般合并排序
 * @author Sking

实现方法:
将待排序数组分为大小大致相等的2个子数组
分别对两个子数组进行排序,如此递归划分排序
最后将排序号的子数组再递归合并为更大的已排序数组
直到整个数组已排序为止。
 */
package 排序算法.mergeSort;

public class MergeSort2 {

	/**
	 * 对指定数组的指定范围执行一般合并排序
	 * 
	 * @param a
	 *            指定数组
	 * @param left
	 *            指定范围的左边索引
	 * @param right
	 *            指定范围的右边索引
	 */
	@SuppressWarnings("rawtypes")
	public void mergeSort2(Comparable[] a, int left, int right) {
		Comparable[] b = new Comparable[a.length];
		if (left < right) {
			int i = (left + right) / 2;
			mergeSort2(a, left, i);//左子段递归排序
			mergeSort2(a, i + 1, right);//右子段递归排序
			merge(a, b, left, i, right);//合并子段到新数组中
			copy(a, b, left, right);//复制排序后的元素到原数组
		}

	}

	/**
	 * 合并已排序子数组c[l...m]和c[m+1,r]到新数组中,新数组保持有序
	 * 
	 * @param c存放两个已排序数组的数组
	 * @param d
	 *            新数组,用于存放合并后的数组
	 * @param l
	 *            左边子数组的起始索引
	 * @param m
	 *            左边子数组的结束索引
	 * @param r
	 *            右边子数组的结束索引
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void merge(Comparable[] c, Comparable[] d, int l, int m,
			int r) {
		int i = l;
		int j = m + 1;
		int k = l;
		while ((i <= m) && (j <= r))
			if (c[i].compareTo(c[j]) <= 0)
				d[k++] = c[i++];
			else
				d[k++] = c[j++];
		if (i > m)
			for (int q = j; q <= r; q++)
				d[k++] = c[q];
		else
			for (int q = i; q <= m; q++)
				d[k++] = c[q];
	}

	/**
	 * 复制源数组中指定索引范围内的元素到目标数组
	 * 
	 * @param a
	 *            源数组
	 * @param b
	 *            目标数组
	 * @param left
	 *            指定范围的左边索引
	 * @param right
	 *            指定范围的右边索引
	 */
	@SuppressWarnings("rawtypes")
	private static void copy(Comparable[] a, Comparable[] b, int left, int 
                                          right) {
		int i = left;
		int j = left;
		while (i <= right)
			a[i++] = b[j++];
	}

}


 

/**
 * 排序算法学习之合并排序
 * @author Sking
 
 实现方法:
将待排序数组中相邻元素两两配对作为子数组,排序各个子数组,
 构成n/2组长度为2的排序好的子数组;然后将长度为2的子排序
 子数组再两两配对,并排序,构成长度为4的已排序子数组。如此递归
 直到整个数组是已排序为止。
 
  最坏时间复杂度:O(n*log(n))
  平均时间复杂度:O(n*log(n))
  辅助空间:O(n)
  稳定性:稳定
 */
package 排序算法.mergeSort;

public class MergeSort {
	@SuppressWarnings("rawtypes")
	/**
	 * 对输入数组执行合并排序
	 * @param a 指定数组,索引有效位置从0开始
	 */
	public void mergeSort(Comparable[] a) {
		Comparable[] b = new Comparable[a.length];// 辅助空间
		int s = 1;// 初始子数组长度设置为1
		while (s < a.length) {
			mergePass(a, b, s);
			s += s;
			mergePass(b, a, s);
			s += s;
		}
	}

	/**
	 * 合并相邻的已排序子数组为更大的已排序子数组
	 * 
	 * @param x
	 *            包含了已排序子数组的数组
	 * @param y
	 *            包含更大的已排序子数组的数组
	 * @param s
	 *            已排序子数组的长度
	 */
	@SuppressWarnings("rawtypes")
	public static void mergePass(Comparable[] x, Comparable[] y, int s) {
		int i = 0;
		while (i <= x.length - 2 * s) {// 合并两相邻的长度为s的已排序子数组
			merge(x, y, i, i + s - 1, i + 2 * s - 1);
			i = i + 2 * s;
		}// 当i>x.length-2*s的时候退出while循环
			// 处理剩下的部分,可以是s长度的已排序数组+“零片”
			// 也可能只是“零片“,此时不需要合并。
		if (i + s < x.length) {
			// 合并相邻的长度s的已排序子数组和长度小于s的“零片”
			merge(x, y, i, i + s - 1, x.length - 1);
		} else
			// 处理”零片“
			for (int j = i; j < x.length; j++)
				y[j] = x[j];
	}

	/**
	 * 合并已排序子数组c[l...m]和c[m+1,r]到新数组中,新数组保持有序
	 * 
	 * @param c存放两个已排序数组的数组
	 * @param d
	 *            新数组,用于存放合并后的数组
	 * @param l
	 *            左边子数组的起始索引
	 * @param m
	 *            左边子数组的结束索引
	 * @param r
	 *            右边子数组的结束索引
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	static void merge(Comparable[] c, Comparable[] d, int l, int m, int r) {
		int i = l;// 第一个子数组的索引指针
		int j = m + 1;// 第二个子数组的索引指针
		int k = l;// 新数组的索引指针
		while ((i <= m) && (j <= r))
			if (c[i].compareTo(c[j]) <= 0)
				d[k++] = c[i++];
			else
				d[k++] = c[j++];
		if (i > m)// 将右边子数组剩下的元素添加到新数组中
			for (int q = j; q <= r; q++)
				d[k++] = c[q];
		else
			// 将左边子数组剩下的元素添加到新数组中
			for (int q = i; q <= m; q++)
				d[k++] = c[q];
	}

}


 

/**
 * 排序算法学习之插入排序
 * @author Sking
 */
package 排序算法.insertionSort;

public class InsertionSort {
	@SuppressWarnings({ "rawtypes", "unchecked" })
	/**
	 * 一次元素插入的实现,在n长度的子数组中插入元素x到合适位置
	 * @param a 带排序数组,索引有效范围从0开始
	 * @param n 子数组元素个数
	 * @param x 待插入的元素
	 */
	public static void insert(Comparable[] a, int n, Comparable x) {
		if (a.length < n + 1)//数组已满,不可插入
			throw new IllegalArgumentException("数组不够大");
		int i;//当前被比较元素索引
		for (i = n - 1; i >= 0 && x.compareTo(a[i]) < 0; i--)
			a[i + 1] = a[i];//比x大的元素后移,寻找x插入的位置
		a[i + 1] = x;//插入x
	}

	/**
	 * 对输入数组执行插入排序
	 * @param a 待排序数组,索引有效位置从0开始
	 */
	@SuppressWarnings("rawtypes")
	public static void insertionSort(Comparable[] a) {
		//i表示一次元素插入步骤所考虑的子数组长度,大小递增
		for (int i = 1; i < a.length; i++)
			insert(a, i, a[i]);
	}
}


 

/**
 * 排序算法学习之冒泡排序
 * 使用时,将Comparable类型替换为指定类型,必要时,要定义比较方法
 * @author Sking
 */
package 排序算法.bubbleSort;

public class BubbleSort {
	/**
	 * 交换数组元素方法
	 * @param a 指定数组
	 * @param i 第一个索引
	 * @param j 第二个索引
	 */
	@SuppressWarnings("rawtypes")
	public static void swap(Comparable[] a, int i, int j) {
		Comparable t = a[i];
		a[i] = a[j];
		a[j] = t;
	}

	/**
	 * 一次冒泡迭代,分别比较相邻元素选择单趟的最大元素
	 * @param a 指定数组
	 * @param n 冒泡子序列的长度
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void bubble(Comparable[] a, int n) {
		for (int i = 0; i < n - 1; i++)
			if (a[i].compareTo(a[i + 1]) > 0)
				swap(a, i, i + 1);
	}
	/**
	 * 一般冒泡排序
	 * @param a 指定数组
	 */
	@SuppressWarnings("rawtypes")
	public static void bubbleSort(Comparable[] a) {
		for (int i = a.length; i > 1; i--)
			bubble(a, i);
	}
	
	/**
	 * 早结束版本的冒泡排序方法的一次迭代
	 * @param a 指定数组
	 * @param n 冒泡子序列的长度
	 * @return 如果该次迭代中进行了元素交换位置,则返回true,否则返回false
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static boolean haveBubble(Comparable[] a,int n){
		boolean swapped=false;//标志一次冒泡是否进行交换
		for(int i=0;i<n-1;i++)
			if(a[i].compareTo(a[i+1])>0){
				swap(a,i,i+1);
				swapped=true;
			}
		return swapped;
	}
	
	/**
	 * 早结束版本的冒泡排序
	 * @param a 指定排序的数组
	 */
	@SuppressWarnings("rawtypes")
	public static void bubbleSort2(Comparable[] a){
		for(int i=a.length;i>1&&haveBubble(a,i);i--);
	}
}


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ACM/ICPC比赛成绩会按照一定的规则计算各位参赛者的名次并实时显示排行榜,计算规则主要参考解题的数量及罚时,解题数量越多,罚时越少,则排名越高。 解题数量很容易计算,只需考察比赛中标记为“Accepted”的题数即可。罚时计算则相对复杂,对于提交到竞赛系统中的每道题目,系统会给出一个罚时,为从比赛开始到该题提交的代码第一次被“Accepted”的时间。请注意,只是第一次“Accepted”。对于“Accepted”之前的每次提交,都有20分钟的罚时,但如果该题目最终未解出,则不计罚时。 先在有一个比赛的题目通过情况记录,请生成该比赛的排行榜。 示例输入: 2008-04-25 18:00:00 2008-04-25 23:30:00 1000 1001 1002 1003 1004 38 602203621 1002 Accepted 756K 30MS C++ 2008-04-25 18:04:59 37 liheyuan 1002 Wrong_Answer 768K 10MS C++ 2008-04-25 18:28:05 36 ftest 1000 Accepted 888K 10MS C++ 2008-04-25 21:30:32 35 ftest 1000 Accepted 904K 10MS C++ 2008-04-25 21:30:55 34 gaojianwei 1000 Accepted 768K 10MS C 2008-04-25 22:15:58 33 gaojianwei 1001 Wrong_Answer 904K 10MS C 2008-04-25 22:18:01 32 gaojianwei 1004 Accepted 768K 10MS C 2008-04-25 22:24:23 31 lzz 1000 Accepted 904K 10MS C++ 2008-04-25 23:29:27 30 lzz 1001 Wrong_Answer 904K 10MS C++ 2008-04-25 23:30:17 示例输出: Rank Name Solved 1000 1001 1002 1003 1004 Penalty 1 gaojianwei 2 4:15:58 -1 0 0 4:24:23 8:40:21 2 602203621 1 0 0 0:04:59 0 0 0:04:59 3 ftest 1 3:30:32 0 0 0 0 3:30:32 4 lzz 1 5:29:27 0 0 0 0 5:29:27 5 liheyuan 0 0 0 -1 0 0 0:00:00

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值