Q : 何为主元素:
设T[0:n-1]是n个元素的数组,对任意一个元素x,设S(x) = { i | T[i] = x }。当| S(x) | > n/2 时,称x为T的主元素。
算法实现:
1、快排 + 判断中位数
2、分治思想 (分解、递归实现)
3、线性算法 (主元素个数大于n/2)
方法一:针对有序数组,若存在主元素,则主元素肯定是中位数。
思路:先对数组进行快速排序,然后求解有序数组的中位数,若中位数个数>n/2 (或者判断中位数与第一个、最后一个元素的关系),则中位数为主元素,否则不存在主元素。
分析:时间复杂度为O(nlogn)
1 #include <stdio.h>
2
3 #include <windows.h>
4
5
6
7 //利用快速排序的方法求中位数
8
9 void swap(int *a, int *b)
10
11 {
12
13 int temp = 0;
14
15 temp = *a;
16
17 *a = *b;
18
19 *b = temp;
20
21 }
22
23
24
25 int partition(int *num, int start, int end)
26
27 {
28
29 int x = num[end];
30
31 int i = start-1;
32
33 int j;
34
35 for (j = start; j < end; j++) {
36
37 if (num[j] <= x) {
38
39 i = i + 1;
40
41 swap(&num[i], &num[j]);
42
43 }
44
45 }
46
47 swap(&num[i+1], &num[end]);
48
49 return i+1;
50
51 }
52
53
54
55 void quicksort(int *num, int start, int end)
56
57 {
58
59 if( start < end) {
60
61 int mid = partition(num, start, end);
62
63 quicksort(num, start, mid-1);
64
65 quicksort(num, mid+1, end);
66
67 }
68
69 }
70
71
72
73 int main()
74
75 {
76
77 int i,n;
78
79 int num[10];
80
81 int index;
82
83 printf("please input the number of a[]:");
84
85 scanf("%d",&n);
86
87 printf("please input a[]:\n");
88
89 for(i=0;i<n;i++)
90
91 scanf("%d",&num[i]);
92
93 quicksort(num, 0, n-1);
94
95 for (i = 0; i < n; i++) {
96
97 printf("%d\n", num[i]);
98
99 }
100
101 if(n%2 == 0)
102
103 index=n/2-1;
104
105 else
106
107 index = n/2; //奇数n/2偶数n/2-1
108
109 //中位数与第一个或者最后一个数相同,则为主元素
110
111 if (num[0] == num[index] || num[n-1] == num[index]) {
112
113 printf("main element exits: index = %d element = %d\n", index, num[index]);
114
115 }
116
117 else {
118
119 printf("main element not exits\n");
120
121 }
122
123 Sleep(10000000);
124
125 }
代码实现
方法二:分治法
思路:若T 中存在主元素,则将T 分为两部分后,T 的主元素也必为两部分中至少一部分的主元素,因此可用分治法。
将元素划分为两部分,递归地检查两部分有无主元素。具体算法如下:
a. 若T 只含一个元素,则此元素就是主元素,返回此数。
b. 将T 分为两部分T1 和T2(二者元素个数相等或只差一个),分别递归调用此方法 求其主元素m1 和m2。
c. 若m1 和m2 都存在且相等,则这个数就是T 的主元素,返回此数。
d. 若m1 和m2 都存在且不等,则分别检查这两个数是否为T 的主元素,若有则返回
e. 若m1 和m2 只有一个存在,则检查这个数是否为T 的主元素,若是则返回此数,
f. 若m1 和m2 都不存在,则 T 无主元素,返回空值。
1 #include <stdio.h>
2
3 #include <stdlib.h>
4
5 #include <malloc.h>
6
7 #include <windows.h>
8
9
10
11 typedef struct snode{
12
13 int data;
14
15 int count;
16
17 }*node;
18
19
20
21 int checkNum(int *num, int p, int q, int data)
22
23 {
24
25 int count = 0;
26
27 int i;
28
29 for (i = p-1; i < q; i++) {
30
31 if (num[i] == data) {
32
33 count++;
34
35 }
36
37 }
38
39 return count;
40
41 }
42
43
44
45 node checkAnotherPart(int *num, int len, int p, int q, node nodec)
46
47 {
48
49 nodec->count = checkNum(num, p, q, nodec->data) + nodec->count; //统计左右两部分元素出现个数
50
51 if (nodec->count > len/2) { //如若大于n/2,则符合要求返回,否则返回空
52
53 return nodec;
54
55 }
56
57 else {
58
59 return NULL;
60
61 }
62
63 }
64
65
66
67 node checkMaster(int *num, int p, int q)
68
69 {
70
71 node nodetmp = (node)malloc(sizeof(node));
72
73 node nodea = (node)malloc(sizeof(node));
74
75 node nodeb = (node)malloc(sizeof(node));
76
77 //递归结束条件
78
79 if (p == q) {
80
81 nodetmp->data = num[p-1];
82
83 nodetmp->count = 1;
84
85 return nodetmp;
86
87 }
88
89 int len = q - p + 1; //待检查数组长度(未必是从头开始:-p)
90
91 int mid = p + len / 2; //找数组中间位置(未必是从头开始:+p)
92
93 nodea = checkMaster(num, p, mid-1); //左半部分递归求解主元素
94
95 nodeb = checkMaster(num, mid, q); //右半部分递归求解主元素
96
97 if (nodea == NULL && nodeb == NULL) { //两部分都不存在主元素,则返回空
98
99 return NULL;
100
101 }
102
103 if (nodea == NULL && nodeb != NULL) { //左半部分存在,右半部分不存在时,检查左半部分主元素是否合格
104
105 return checkAnotherPart(num, len, p, mid-1, nodeb);
106
107 }
108
109 if (nodea != NULL && nodeb == NULL) { //左半部分不存在,右半部分存在时,检查右半部分主元素是否合格
110
111 return checkAnotherPart(num, len, mid, q, nodea);
112
113 }
114
115 if (nodea != NULL && nodeb != NULL) { //左右两部分都存在主元素
116
117 if (nodea->data == nodeb->data) { //左右两部分的主元素相同,直接返回
118
119 nodea->count = nodea->count + nodeb->count;
120
121 return nodea;
122
123 }
124
125 else { //左右两部分的主元素不同,分别检查其是否为原数组的主元素
126
127 node nodec = checkAnotherPart(num, len, p, mid-1, nodeb);
128
129 if (nodec != NULL) {
130
131 return nodec;
132
133 }
134
135 else {
136
137 return checkAnotherPart(num, len, mid, q, nodea);
138
139 }
140
141 }
142
143 }
144
145 }
146
147
148
149 int main()
150
151 {
152
153 int i,n,num[50];
154
155 printf("please input the number of num[]:");
156
157 scanf("%d",&n);
158
159 printf("please input num[]:\n");
160
161 for(i=0;i<n;i++)
162
163 scanf("%d",&num[i]);
164
165 node masterNode = checkMaster(num, 1, n);
166
167 if(masterNode == NULL)
168
169 printf("the main elemer not exist! \n");
170
171 else
172
173 printf("num = %d count = %d\n", masterNode->data, masterNode->count);
174
175 Sleep(10000000);
176
177 }
代码实现
方法三:主元素个数 > n/2 ,所以主元素的个数减去其它元素的个数仍然大于0。
思路:假定a[0]为主元素mainE,主元素与其它元素的差值为dif,初值为1;然后进行比较,如果下一个元素与mainE相同,则++dif,否则--dif,若为0,则令后继元素为mainE,且dif置1。
分析:时间复杂度为:O(n) 线性
1 #include <stdio.h>
2
3 #include <stdlib.h>
4
5 #include <windows.h>
6
7
8
9 int mainElement(int a[], int n)
10
11 {
12
13 int mainE = a[0];
14
15 int dif = 1;
16
17 int i =1;
18
19 int count;
20
21 while(i < n)
22
23 {
24
25 if(a[i] == mainE)
26
27 {
28
29 ++dif;
30
31 }
32
33 else
34
35 {
36
37 --dif;
38
39 if(!dif)
40
41 {
42
43 mainE = a[i+1];
44
45 ++i;
46
47 dif = 1;
48
49 }
50
51 }
52
53 ++i;
54
55 }
56
57
58
59 //统计mainE的个数,判断mainE是否是主元素
60
61 count = 0;
62
63 for (i = 0; i < n; i++) {
64
65 if (a[i] == mainE) {
66
67 count++;
68
69 }
70
71 }
72
73 if (count > n/2) {
74
75 return mainE;
76
77 }
78
79 return 0;
80
81 }
82
83
84
85 void main()
86
87 {
88
89 int a[10];
90
91 int i,n,mainE;
92
93 printf("please input the number of a[]:");
94
95 scanf("%d",&n);
96
97 printf("please input a[]:\n");
98
99 for(i=0;i<n;i++)
100
101 scanf("%d",&a[i]);
102
103 mainE=mainElement(a,n);
104
105 if (mainE != 0)
106
107 printf("main element is %d\n", mainE);
108
109 else
110
111 printf("main element not exits\n");
112
113 Sleep(100000);
114
115 }
116
117
代码实现