文档视界 最新最全的文档下载
当前位置:文档视界 › 数据结构算法大全有代码

数据结构算法大全有代码

数据结构算法大全有代码
数据结构算法大全有代码

排序算法有:插入排序,合并排序,冒泡排序,选择排序,希尔排序,堆排序,快速排序,计数排序,基数排序,桶排序(没有实现)。比较一下学习后的心得。

我不是很清楚他们的时间复杂度,也真的不知道他们到底谁快谁慢,因为书上的推导我确实只是小小了解,并没有消化。也没有完全理解他们的精髓,所以又什么错误的还需要高手指点。呵呵。

1.普及一下排序稳定,所谓排序稳定就是指:如果两个数相同,对他们进行的排序结果为他们的相对顺序不变。例如A={1,2,1,2,1}这里排序之后是A = {1,1,1,2,2} 稳定就是排序后第一个1就是排序前的第一个1,第二个1就是排序前第二个1,第三个1就是排序前的第三个1。同理2也是一样。这里用颜色标明了。不稳定呢就是他们的顺序不应和开始顺序一致。也就是可能会是A={1,1,1,2,2}这样的结果。

2.普及一下原地排序:原地排序就是指不申请多余的空间来进行的排序,就是在原来的排序数据中比较和交换的排序。例如快速排序,堆排序等都是原地排序,合并排序,计数排序等不是原地排序。

3.感觉谁最好,在我的印象中快速排序是最好的,时间复杂度:n*log(n),不稳定排序。原地排序。他的名字很棒,快速嘛。当然快了。我觉得他的思想很不错,分治,而且还是原地排序,省去和很多的空间浪费。速度也是很快的,n*log(n)。但是有一个软肋就是如果已经是排好的情况下时间复杂度就是n*n,不过在加入随机的情况下这种情况也得以好转,而且他可以做任意的比较,只要你能给出两个元素的大小关系就可以了。适用范围广,速度快。

4.插入排序:n*n的时间复杂度,稳定排序,原地排序。插入排序是我学的第一个排序,速度还是很快的,特别是在数组已排好了之后,用它的思想来插入一个数据,效率是很高的。因为不用全部排。他的数据交换也很少,只是数据后移,然后放入要插入的数据。(这里不是指调用插入排序,而是用它的思想)。我觉得,在数据大部分都排好了,用插入排序会给你带来很大的方便。数据的移动和交换都很少。

插入排序主要思想是:把要排序的数字插入到已经排好的数据中。(我自己理

解的哈)。例如12356是已经排好的序,我们将4插入到他们中,时插入之后也是排好序的。这里显而易见是插入到3的后面。变为123456.

实现思路:插入排序就是先是一个有序的数据,然后把要插入的数据插到指定的位置,而排序首先给的就是无序的,我们怎么确定先得到一个有序的数据呢?答案就是:如果只有一个,当然是有序的咯。我们先拿一个出来,他是有序的,然后把数据一个一个插入到其中,那么插入之后是有序的,所以直到最后都是有序的。。哈哈。结果就出来了!

当然在写的时候还是有一个技巧的,不需要开额外的数组,下标从第二个元素开始遍历直到最后一个,然后插入到前面已经有序的数据中。这样就不会浪费空间了。插入排序用处还是很多的,特别是链表中,因为链表是指针存放的,没有数组那么好准确的用下标表示,插入是简单有效的方法。嘻嘻。。废话少说,

源代码奉上:

1 #include

2 #include

3

4 //插入排序从小到大,nData为要排序的数据,nNum为数据的个数,该排序是稳定的排序

5 bool InsertionSort(int nData[], int nNum)

6 {

7 for (int i = 1; i < nNum; ++i) //遍历数组,进行插入排序

8 {

9 int nTemp = nData[i];

10 for (int j = 0; j < i; ++j) //对该数,寻找他要插入的位置

11 {

12 if (nData[j] > nTemp) //找到位置,然后插入该位置,之后的数据后移

13 {

14 for (int k = i; k > j; --k) //数据后移

15 {

16 nData[k] = nData[k -1];

17 }

18 nData[j] = nTemp; //将数据插入到指定位置

19 break;

20 }

21 }

22 }

23

24 return true;

25 }

26

27 int main()

28 {

29 int nData[10] = {4,10,9,8,7,6,5,4,3,2}; //创建10个数据,测试

30 InsertionSort(nData, 10); //调用插入排序

31

32 for (int i = 0; i < 10; ++i)

33 {

34 printf("%d ", nData[i]);

35 }

36

37 printf("\n");

38 system("puase");

39 return 0;

40 }

5.冒泡排序,n*n的时间复杂度,稳定排序,原地排序。冒泡排序的思想很不错,一个一个比较,把小的上移,依次确定当前最小元素。因为他简单,稳定排序,而且好实现,所以用处也是比较多的。还有一点就是加上哨兵之后他可以提前退出。

冒泡排序的主要思路:我们把要排序的数组A = {3,4,2,1} 看成一组水泡,就像冒泡一样,轻的在上面,重的在下面,换成数据,就是小的在上面,大的在下面。我们先把最轻的冒出到顶端,然后冒出第二轻的在最轻的下面,接着冒出第三轻的。依次内推。直到所有都冒出来了为止。

我们怎么做到把最轻的放在顶端呢?我们从最底下的数据开始冒,如果比他上面的数据小,就交换(冒上去),然后再用第二第下的数据比较(此时他已经是较轻的一个),如果他比他上面的小,则交换,把小的冒上去。直到比到第一位置,得到的就是最轻的数据咯,这个过程就像是冒泡一样,下面的和上面的比较,小的冒上去。大的沉下来。呵呵。

画个图先:

开始:1 和2 比,1比2小,浮上,然后1跟4比,再1跟3比,这样结构就变为1,3,4,2。最小的位置确定了,然后我们确定第二小的,同理2 vs 4, 2 vs 3 得到2,再确定第3小数据,3 vs 4得到3,最后就是4为最大的数据,我们冒泡就排好了。

注:这里红色的1,2是前一次比较1 vs 2交换的结构。后面也一样。

大概思路就这样了,奉上源代码:

#include

#include

//冒泡排序, pnData要排序的数据, nLen数据的个数

int BubbleSort(int* pnData, int nLen)

{

bool isOk = false; //设置排序是否结束的哨兵

//i从[0,nLen-1)开始冒泡,确定第i个元素

for (int i = 0; i < nLen - 1 && !isOk; ++i)

{

isOk = true; //假定排序成功

//从[nLen - 1, i)检查是否比上面一个小,把小的冒泡浮上去

for (int j = nLen- 1; j > i; --j)

{

if (pnData[j] < pnData[j - 1]) //如果下面的比上面小,交换

{

int nTemp = pnData[j];

pnData[j] = pnData[j - 1];

pnData[j - 1] = nTemp;

isOk = false;

}

}

}

return 1;

}

int main()

{

int nData[10] = {4,10,9,8,7,6,5,4,3,2}; //创建10个数据,测试

BubbleSort(nData, 10); //调用冒泡排序

for (int i = 0; i < 10; ++i)

{

printf("%d ", nData[i]);

}

printf("\n");

system("pause");

return 0;

}

我这里用了一个哨兵做标记,就是如果在已经是排好序的情况下我们能检测出来并退出。随便说一下,冒泡排序是稳定的排序。

6.选择排序,n*n的时间复杂度,稳定排序,原地排序。选择排序就是冒泡的基本思想,从小的定位,一个一个选择,直到选择结束。他和插入排序是一个相反的过程,插入是确定一个元素的位置,而选择是确定这个位置的元素。他的好处就是每次只选择确定的元素,不会对很多数据进行交换。所以在数据交换量上应该比冒泡小。

选择排序和冒泡排序思路上有一点相似,都是先确定最小元素,再确定第二笑元素,最后确定最大元素。他的主要流程如下:

1.加入一个数组A = {5,3,6,2,4,7},我们对他进行排序

2.确定最小的元素放在A[0]位置,我们怎么确定呢,首先默认最小元素为5,他的索引为0,然后用它跟3比较,比他打,则认为最小元素为3,他的索引为1,然后用3跟6比,发现比他小,最小元素还是3,然后跟2比,最小元素变成了2,索引为3,然后跟4比,跟7比。当比较结束之后,最小元素也尘埃落定了。就是2,索引为3,然后我们把他放在A[0]处。为了使A[0]原有数据部丢失,我们使A[0](要放的位置) 与A[3](最小数据的位置)交换。这样就不可以了吗?

3.然后我们在来找第二小元素,放在A[1],第三小元素,放在A[2]。。当寻找完毕,我们排序也就结束了。

4.不过,在找的时候要注意其实位置,不能在找A[2]的时候,还用A[2]的数据跟已经排好的A[0],A[1]比,一定要跟还没有确定位置的元素比。还有一个技巧就是我们不能每次都存元素值和索引,我们只存索引就可以了,通过索引就能找到元素了。呵呵。

5.他和冒泡的相似和区别,冒泡和他最大的区别是他发现比他小就交换,把小的放上面,而选择是选择到最小的在直接放在确定的位置。选择也是稳定的排序。

基本思路就这样了,奉上源代码:

#include

#include

//选择排序, pnData要排序的数据, nLen数据的个数

int SelectSort(int* pnData, int nLen)

{

//i从[0,nLen-1)开始选择,确定第i个元素

for (int i = 0; i < nLen - 1; ++i)

{

int nIndex = i;

//遍历剩余数据,选择出当前最小的数据

for (int j = i + 1; j < nLen; ++j)

{

if (pnData[j] < pnData[nIndex])

{

nIndex = j;

}

}

//如果当前最小数据索引不是i,也就是说排在i位置的数据在nIndex处

if (nIndex != i)

{

//交换数据,确定i位置的数据。

int nTemp = pnData[i];

pnData[i] = pnData[nIndex];

pnData[nIndex] = nTemp;

}

}

return 1;

}

int main()

{

int nData[10] = {4,10,9,8,7,6,5,4,3,2}; //创建10个数据,测试

SelectSort(nData, 10); //调用选择排序

for (int i = 0; i < 10; ++i)

{

printf("%d ", nData[i]);

}

printf("\n");

system("pause");

return 0;

}

7.插入排序,选择排序,冒泡排序的比较,他们的时间复杂度都是n*n。我觉得他们的效率也是差不多的,我个人喜欢冒泡一些,因为要用它的时候数据多半不多,而且可以提前的返回已经排序好的数组。而其他两个排序就算已经排好了,他也要做全部的扫描。在数据的交换上,冒泡的确比他们都多。呵呵。举例说明插入一个数据在末尾后排序,冒泡只要一次就能搞定,而选择和插入都必须要n*n的复杂度才能搞定。就看你怎么看待咯。

8.合并排序:n*log(n)的时间复杂度,稳定排序,非原地排序。他的思想是分治,先分成小

的部分,排好部分之后合并,因为我们另外申请的空间,在合并的时候效率是0(n)的。速度很快。貌似他的上限是n*log(n),所以如果说是比较的次数的话,他比快速排序要少一些。对任意的数组都能有效地在n*log(n)排好序。但是因为他是非原地排序,所以虽然他很快,但是貌似他的人气没有快速排序高。

合并排序的主要思想是:把两个已经排序好的序列进行合并,成为一个排序好的序列。例如:13579 2468这两个序列,各自都是排好序的,然后我们进行合并,成为123456789这样一个排好序的序列。貌似这个跟排序关系不大,因为排序给的是一个乱的序列,而合并是合并的两个已经排序好的序列。且慢,我们可以把需要排序的数据分解成N个子序列,当分解的子序列所包含数据个数为1的时候,那么这个序列不就是有序了吗?然后再合并。这个就是有名的”分治“了。。(哈哈。没有想到这么好的思想能在这里学到。)。例如321分成3,2,1三个序列,1这个序列是有序的啦。(只有一个数据当然是有序的啦。当我傻的啊。哈哈)。同理2,3都是有序的。然后我们逐一的合并他们。3,2合并为23,然后在23与1合并为123。哈哈,排序成功。合并排序主要思路就是这样了。但是,问题又出来了,怎么合并两个有序列呢?我相信我应该理解了数组的存储方式,所以直接用数组说事啦。。我们先把下标定位到各有序子序列的开始,也把合并之后数组的下标定位到最初。那么下标对应的位置就是他们当前的最小值了。然后拿他们来比较,把更小的那个放到合并之后数组的下标位置。这样,合并后数组的第一个元素就是他们的最小值了。接着,控制合并后数组的下标后移一个,把比较时小数字所在序列对应的下标后移一个。这样。下次比较的时候,他得到就是他的第二小,(第一下已经合并了)就是当前最小值了,在于另一个序列的当前最小值比较,用小的一个放到合并后数组的相应位置。依次类推。接着当数据都合并玩了结束,合并完成。(这样说忒空泛了,云里雾里的,BS一下以前的我。)

1357 2468 来做例子:

(1回合) 1357 2468 00000(合并后数据空)

(2) 357 2468 100000(0表示空) 因为1 < 2所以把1放到合并后位置中了(这里1并不是丢掉了,而是下标变为指向3了,1是没有写而已。呵呵。理解为数组的下标指向了3)

(3) 357 468 120000 因为3 > 2,所以把2放进去

(4) 57 468 123000 同理3 < 4

(5) 57 68 1234000 同理5 > 4

(6) 7 68 1234500 同理5 > 6

(7) 7 8 1234560 同理7 > 6

(8) 0(空了) 8 12345670 同理7 < 8

(9) 0 0 12345678 弄最后一个

PS:这是用记事本写的哈,没有钱买office而且也不是很会用。哈哈。我想以后的我也不见怪的哈。。关键还有书嘛,这里看不懂还有教科书。。

当然,这些只是思路。并不是一定一成不变的这样。合并OK,那么我们就可以用合并排序了哦!哈哈。。不过注意,那个321全部弄成一个单个数字,然后一个一个合并这样来合并似乎不是很好,貌似还有更好的解决方案。哈哈,对了,就是我先分一半来合并。如果这一半是排好序的,那么合并不久简单了吗?但是我怎么让一般排好序呢。呵呵简单,我一半在分一半合并排序,在分一半合并排序,直到分到两个都是1个了,就合并,ok!

例如,81726354:

(1)分成9172 6354

(2)把8172 分成81 和72 把6354分成63和54

(3)81分成8和1,哦能合并了哦。合并为18, 同理72,63,54,也可以分解成单个合并为27,36,45

(4) 现在变为了18, 27, 36, 45了,这个时侯,18 和27能合并了,合并为1278 同理36,合并为45 3456

(5) 好了最好吧,1278和3456合并为12345678.ok排序成功。哈哈。

这样把一个问题分解为两个或多个小问题,然后在分解,最后解决小小问题,已达到解决打问题的目的。

哈哈。分治很强大。哈哈。如果看不懂,我也没有办法啦。。看教科书吧。呵呵

思路主要就是这样了哦:

程序实现上也有点技巧。这个就不说了,直接奉上源代码:

1 #include

2 #include

3

4 //合并排序的合并程序他合并数组nData中位置为[nP,nM) 和[nM,nR).这个是更接近标准的思路

5 bool MergeStandard(int nData[], int nP, int nM, int nR)

6 {

7 int n1 = nM - nP; //第一个合并数据的长度

8 int n2 = nR - nM; //第二个合并数据的长度

9

10 int *pnD1 = new int[n1 + 1]; //申请一个保存第一个数据的空间

11 int *pnD2 = new int[n2 + 1]; //申请二个保存第一个数据的空间

12

13 for (int i = 0; i < n1; ++i) //复制第一个数据到临时空间里面

14 {

15 pnD1[i] = nData[nP + i];

16 }

17 pnD1[n1] = INT_MAX; //将最后一个数据设置为最大值(哨兵)

18

19 for (int i = 0; i < n2; ++i) //复制第二个数据到临时空间里面

20 {

21 pnD2[i] = nData[nM + i];

22 }

23 pnD2[n2] = INT_MAX; //将最后一个数据设置为最大值(哨兵)

24

25 n1 = n2 = 0;

26

27 while(nP < nR)

28 {

29 nData[nP++] = pnD1[n1] < pnD2[n2] ? pnD1[n1++] : pnD2[n2++]; //取出当前最小值到指定位置

30 }

31

32 delete pnD1;

33 delete pnD2;

34 return true;

35 }

36

37 //合并排序的合并程序他合并数组nData中位置为[nP,nM) 和[nM,nR).

38 bool Merge(int nData[], int nP, int nM, int nR)

39 {

40 //这里面有几个注释语句是因为当时想少写几行而至。看似短了,其实运行时间是一样的,而且不易阅读。

41

42 int nLen1 = nM - nP; //第一个合并数据的长度

43 int nLen2 = nR - nM; //第二个合并数据的长度

44 int* pnD1 = new int[nLen1]; //申请一个保存第一个数据的空间

45 int* pnD2 = new int[nLen2]; //申请一个保存第一个数据的空间

46

47 int i = 0;

48 for ( i = 0; i < nLen1; ++i) //复制第一个数据到临时空间里面

49 {

50 pnD1[i] = nData[nP + i];

51 }

52

53 int j = 0;

54 for (j = 0; j < nLen2; ++j) //复制第二个数据到临时空间里面

55 {

56 pnD2[j] = nData[nM + j];

57 }

58

59 i = j = 0;

60 while (i < nLen1 && j < nLen2)

61 {

62 //nData[nP++] = pnD1[i] < pnD2[j] ? pnD1[i++] : pnD2[j++]; //取出当前最小值添加到数据中

63

64 if (pnD1[i] < pnD2[j]) //取出最小值,并添加到指定位置中,如果pnD1[i] < pnD2[j]

65 {

66 nData[nP] = pnD1[i]; //取出pnD1的值,然后i++,定位到下一个个最小值。

67 ++i;

68 }

69 else //这里同上

70 {

71 nData[nP] = pnD2[j];

72 ++j;

73 }

74 ++nP; //最后np++,到确定下一个数据

75 }

76

77 if (i < nLen1) //如果第一个数据没有结束(第二个数据已经结束了)

78 {

79 while (nP < nR) //直接把第一个剩余的数据加到nData的后面即可。

80 {

81 //nData[nP++] = pnD1[i++];

82 nData[nP] = pnD1[i];

83 ++nP;

84 ++i;

85 }

86 }

87 else //否则(第一个结束,第二个没有结束)

88 {

89 while (nP < nR) //直接把第一个剩余的数据加到nData的后面即可。

90 {

91 //nData[nP++] = pnD2[j++];

92 nData[nP] = pnD2[j];

93 ++nP;

94 ++j;

95 }

96 }

97

98 delete pnD1; //释放申请的内存空间

99 delete pnD2;

100

101 return true;

102 }

103

104 //合并的递归调用,排序[nBegin, nEnd)区间的内容

105 bool MergeRecursion(int nData[], int nBegin, int nEnd)

106 {

107 if (nBegin >= nEnd - 1) //已经到最小颗粒了,直接返回

108 {

109 return false;

110 }

111

112 int nMid = (nBegin + nEnd) / 2; //计算出他们的中间位置,便于分治

113 MergeRecursion(nData, nBegin, nMid); //递归调用,合并排序好左边一半

114 MergeRecursion(nData, nMid, nEnd); //递归调用,合并排序好右边一半

115 //Merge(nData, nBegin, nMid, nEnd); //将已经合并排序好的左右数据合并,时整个数据排序完成

116 MergeStandard(nData, nBegin, nMid, nEnd);//(用更接近标准的方法合并)

117

118 return true;

119 }

120

121 //合并排序

122 bool MergeSort(int nData[], int nNum)

123 {

124 return MergeRecursion(nData, 0, nNum); //调用递归,完成合并排序

125 }

126

127 int main()

128 {

129 int nData[10] = {4,10,3,8,5,6,7,4,9,2}; //创建10个数据,测试

130

131 MergeSort(nData, 10);

132 for (int i = 0; i < 10; ++i)

133 {

134 printf("%d ", nData[i]);

135 }

136

137 printf("\n");

138 system("pause");

139 return 0;

140 }

141

9.堆排序:n*log(n)的时间复杂度,非稳定排序,原地排序。他的思想是利用的堆这种数据结构,堆可以看成一个完全二叉树,所以在排序中比较的次数可以做到很少。加上他也是原地排序,不需要申请额外的空间,效率也不错。可是他的思想感觉比快速难掌握一些。还有就是在已经排好序的基础上添加一个数据再排序,他的交换次数和比较次数一点都不会减少。虽然堆排序在使用的中没有快速排序广泛,但是他的数据结构和思想真的很不错,而且用它来实现优先队列,效率没得说。堆,还是要好好学习掌握的。

#include

#include

//交换两个整数。注意一定要if判断是否两个相等,如果

//不相等才交换,如果相等也交换会出错的。a^a = 0

inline void Swap(int& a, int& b)

{

if (a != b)

{

a^= b;

b^= a;

a^= b;

}

}

//维持一个最大堆

int Heapify(int* npData, int nPos, int nLen)

{

int nMax = -1; //暂存最大值

int nChild = nPos * 2; //他的左孩子位置

while(nChild <= nLen) //判断他是否有孩子

{

nMax = npData[nPos]; //是当前最大值为他

if (nMax < npData[nChild]) //与左孩子比较

{

nMax = npData[nChild]; //如果比左孩子小,就时最大值为左孩子

}

//同理与右孩子比较,这里要注意,必须要保证有右孩子。

if (nChild + 1 <= nLen && nMax < npData[nChild + 1])

{

++nChild; //赋值最大值的时候把孩子变为右孩子,方便最后的数据交换 nMax = npData[nChild];

}

if (nMax != npData[nPos]) //判断是否该节点比孩子都打,如果不大

{

Swap(npData[nPos], npData[nChild]); //与最大孩子交换数据

nPos = nChild; //该节点位置变为交换孩子的位置

nChild *= 2; //因为只有交换后才使不满足堆得性质。

}

else //都最大了,满足堆得性质了。退出循环

{

break;

}

}

return 1; //维持结束。

}

//建立一个堆

int BuildHeap(int* npData, int nLen)

{

//从nLen / 2最后一个有叶子的数据开始,逐一的插入堆,并维持堆得平衡。

//因为堆是一个完全二叉树,所以nlen/2+1- nLen之间肯定都是叶子。

//叶子还判断什么呢。只有一个数据,肯定满足堆得性质咯。

for (int i = nLen / 2; i >= 1; --i)

{

Heapify(npData, i, nLen);

}

return 1;

}

//堆排序

int HeapSort(int* npData, int nLen)

{

BuildHeap(npData, nLen); //建立一个堆。

while(nLen >= 1) //逐一交和第一个元素交换数据到最后

{ //完成排序

Swap(npData[nLen], npData[1]);

--nLen;

Heapify(npData, 1, nLen);//交换之后一定要维持一下堆得性质。

} //不然小的成第一个元素,就不是堆了。

return 1;

}

//main函数,

int main()

{

int nData[11] = {0,9,8,7,6,5,4,3,2,1,0}; //测试数据,下标从1开始哦。

HeapSort(nData, 10); //堆排序

for (int i = 1; i <= 10; ++i) //输出排序结果。

{

printf("%d ", nData[i]);

}

printf("\n");

system("pause");

return 0;

}

10.希尔排序:n*log(n)的时间复杂度(这里是错误的,应该是n^lamda(1 < lamda < 2), lamda 和每次步长选择有关。),非稳定排序,原地排序。主要思想是分治,不过他的分治和合并排序的分治不一样,他是按步长来分组的,而不是想合并那样左一半右一半。开始步长为整个的长度的一半。分成nLen/2个组,然后每组排序。接个步长减为原来的一半在分组排序,直到步长为1,排序之后希尔排序就完成了。这个思路很好,据说是插入排序的升级版,所

以在实现每组排序的时候我故意用了插入排序。我觉得他是一个特别好的排序方法了。他的缺点就是两个数可能比较多次,因为两个数据会多次分不过他们不会出现数据的交换。效率也是很高的。

主要思想借用了合并排序的思想。不过他不是左边一半右边一半,而是按照步长来分,随着步长减少,分成的组也越少。然后进行各组的插入排序。

11.快速排序,堆排序,合并排序,希尔排序的比较,他们的时间复杂的都是n*log(n),我认为在使用上快速排序最广泛,他原地排序,虽然不稳定,可是很多情况下排序根本就不在意他是否稳定。他的比较次数是比较小的,因为他把数据分成了大和小的两部分。每次都确定了一个数的位置,所以理论上说不会出现两个数比较两次的情况,也是在最后在交换数据,说以数据交换上也很少。合并排序和堆排序也有这些优点,但是合并排序要申请额外的空间。堆排序堆已经排好的数据交换上比快速多。所以目前快速排序用的要广泛的多。还有他很容易掌握和实现。

快速排序的速度是很快的,平均复杂度是nlogn,我也不知道是怎么算出来的,反正T(n) = 2T(n/2) + o(n) 这样怎么怎么推到就成了nLogn了,呵呵,有空去学习一下。希望会的人可以教我,我数学太烂了。废话少说,记录一下快速排序的思路:

1.分治的思想,把数组分成两份,两份分成4分,这样分到足够小,就能很好排序咯,然后把他们合起来,排序完成。

2.该分治思想和合并排序思想一样,但是处理上更搞一筹,他是把小的和大的分成两份,这样在最后合并的时候,就不会像合并排序那样还要检查,因为本来就是左边比右边小,所以可以做到原地排序(就是不用申请多余的空间)。

3.如何做好把小和大的分开时关键,我们做的就是以一个数位基准,然后找到这个数的位置。把比他小的放在他的左边,比他大的放在他的右边,这样不就分开了嘛。

4.具体怎么分时一个最关键的地方,本来想用图说明一下,但是自己不会画:作罢,试着语言整理一下,呵呵:

例如,开始把最后一个作为标准,用一个循环j = nBegin j < nEnd一一比较,这样就能判断到底谁比他大,谁比他小咯。

注意:为了能清楚知道区域,所以要用一个变量i来保存它的标志,i的左边是比他小的,i 的右边是比他大的。有了这个标志我们就好处理了。比较就好处理咯。

遇到小的,要把他方在i的左边,所以我们把他和i+1的元素交换,因为i+1得元素是大于x 的,交换之后i+1就小于x了,这样我们把i也加1,不就有保证了i的左边都比x小,右边都比x大了嘛。呵呵。

遇到大的,不用管他。I也不用变。

比较完了,这时情况就是i的左边都比x小,i的右边都比x大,x在最后面。怎么处理呢?还不简单,有重复一下i + 1与 x交换,这样处理之后,i + 1就是保存的x值,i + 1的右边都比x 大,i+1的左边都比x小,哈哈,i+1就是分割点咯。搞定。。

找出分割点后还不分而治之。。分而治之的时候发现分割点是排好的,只需排序nBegin - 分割点-1,分割点+1 - nEnd 就可以咯。

最后还是截张《算法导论》书中的图:

呵呵,我就是学的这本书。还不错啦。附上下载地址分享一下:

https://www.docsj.com/doc/c918671967.html,/source/1199909

奉上自己的源代码:

#include

#include

//化分区间,找到最后元素的排序位置。并返回分隔的点(即最后一数据排序的位置)。

//划分的区间是[nBegin, nEnd). pData是保存数据的指针

int Partition(int* pData, int nBeging, int nEnd)

{

int i = nBeging - 1; //分隔符号,最后nD保存在这里

--nEnd;

int nD = pData[nEnd]; //比较的数据。

int nTemp; // 交换用的临时数据

//遍历数据比较,找到nD的位置,这里注意,比较结果是,

//如果i的左边是小于等于nD的,i的右边是大于nD的

for (int j = nBeging; j < nEnd; ++j)

{

if (pData[j] <= nD) //如果数据比要比较的小,则在该数据的左边,与i+1交换

{

++i; //小于nD的数据多一个,所以要加1,i的左边数据都比nD小

nTemp = pData[i]; //交换数据

pData[i] = pData[j];

pData[j] = nTemp;

}

}

//最后不要忘了吧nD和i+1交换,因为这里就是nD的位置咯。

++i;

pData[nEnd] = pData[i];

pData[i] = nD;

return i; //返回nD的位置,就是分割的位置。

}

//排序的递归调用。

int QuickSortRecursion(int* pData, int nBeging, int nEnd)

{

if (nBeging >= nEnd -1) //如果区域不存在或只有一个数据则不递归排序

{

return 1;

}

//这里因为分割的时候,分割点处的数据就是排序中他的位置。

//也就是说他的左边的数据都小于等于他,他右边的数据都大于他。

//所以他不在递归调用的数据中。

int i = Partition(pData, nBeging, nEnd); //找到分割点

QuickSortRecursion(pData, nBeging, i); //递归左边的排序

QuickSortRecursion(pData, i + 1, nEnd); //递归右边的排序

return 1;

}

//快速排序

int QuickSort(int* pData, int nLen)

{

//递归调用,快速排序。

QuickSortRecursion(pData, 0, nLen);

return 1;

}

int main()

{

int nData[10] = {5,9,3,2,1,6,20,45,88,75}; //测试数据

QuickSort(nData, 10); //调用快速排序

for (int i = 0; i < 10; ++i) //输出结果

{

printf("%d ", nData[i]);

}

printf("\n");

system("pause");

return 0;

}

12.计数排序:n的时间复杂度,稳定排序,非原地排序。他的思想比较新颖,就是先约定数据的范围不是很大,而且数据都是整数(或能定位到整数)的情况,然后直接申请一个空间。把要排序的数组A的元素值与申请空间B的下标对应,然后B中存放该下标元素值的个数,从而直接定位A中每个元素的位置。这样效率只为n。因为比较很特殊,虽然很快,但是用的地方并不多。

13.基数排序:n的时间复杂度,稳定排序,非原地排序。他的思想是数据比较集中在一个范围,例如都是4位数,都是5位数,或数据有多个关键字,我们先从各位开始排,然后排十位,依次排到最高位,因为我们可以用一个n的方法排一位,所以总的方法为d*n的复杂度。关键字也一样,我们先排第3个关键字,在排第3个关键字,最后排第一个关键字。只有能保证每个关键字在n的时间复杂度完成,那么整个排序就是一个d*n的时间复杂度。所以总的速度是很快的。不过有一点就是要确保关键字能在n的时间复杂度完成。

14.桶排序:n的时间复杂度,稳定排序,非原地排序。主要思路和基数排序一样,也是假设都在一个范围例如概率都在0-1,而且分布还挺均匀,那么我们也是和基数排序一样对一个数把他划分在他指定的区域。然后在连接这些区域就可以了。书上对每个区域使用链表的存储,我认为在寸小区域的时候也会有时间在里面。所以只是理论上的n时间复杂度。这种思路是不错的。呵呵。

15.计数排序,基数排序,桶排序的比较,我觉得他们都很有思想,不过都是在特定情况下才能发挥最大的效果。虽然效率很高,但是用的不会很广泛。他们之间我更喜欢计数排序,来个映射的方式就直接找到了自己的位置,很高明。和基数排序和同排序只是理论上的n 时间复杂度,基数排序要确定一个关键字的排序是n复杂度的,桶排序要确定每个区域的排序是n复杂度的。

16.排序算法的最后感悟:黑格尔说过:存在即合理。所以这些排序的算法都是很好的,他确实给了我们思想上的帮助。感谢前人把精华留给了我们。我得到的收获很大,总结一下各自排序的收获:

冒泡:好实现,速度不慢,使用于轻量级的数据排序。

插入排序:也使用于小数据的排序,但是我从他的思想中学到怎么插入一个数据。呵呵,这样就知道在排好的数据里面,不用再排序了,而是直接调用一下插入就可以了。

选择排序:我学会了怎么去获得最大值,最小值等方法。只要选择一下,不就可以了。

合并排序:我学会分而治之的方法,而且在合并两个数组的时候很适用。

堆排序:可以用它来实现优先队列,而且他的思想应该给我加了很多内力。

快速排序:本来就用的最多的排序,对我的帮助大的都不知道怎么说好。

希尔排序:也是分治,让我看到了分治的不同,原来还有这种思想的存在。

计数排序,基数排序,桶排序:特殊情况特殊处理。

/*排序头文件部分,文件名为sort.h*/

#include "stdlib.h"

#include

#define MAXSIZE 20

typedef int KeyType;

typedef struct

{KeyType key;

char other;

}RedType;

typedef struct

{RedType r[MAXSIZE+1];

int length;

}SqList;

/*输入排序元素的初始序列*/

void create(SqList *L)

{int i;

randomize();

L->length=random(MAXSIZE);

for(i=1;i<=L->length;i++)

{ L->r[i].key=random(100);

L->r[i].other=random(26)+65;}

}

/*输出元素*/

void visit(SqList L)

{int i,k;

printf("\n");

for(i=1;i<=L.length;i++)

printf("%4d%2c",L.r[i].key,L.r[i].other);

printf("\n");

}

/*简单选择排序*/

void select_sort(SqList *L)

{

int i,j,k;

RedType t;

for (i=1;ilength;i++)

{j=i;

for (k=i+1;k<=L->length;k++)

if (L->r[j].key>L->r[k].key) j=k;

if (i!=j) {t=L->r[j];L->r[j]=L->r[i];L->r[i]=t;

}

}

}

/*快速排序*/

void QSort(SqList *L,int low,int high)

{int i,j;

if (low

- 30 -

{

i=low;j=high;L->r[0]=L->r[i];

while(i

{

while(ir[j].key>=L->r[0].key) j--;

L->r[i]=L->r[j];

while(ir[i].key<=L->r[0].key) i++;

L->r[j]=L->r[i];

}

L->r[i]=L->r[0];

QSort(L,low,i-1);

QSort(L,i+1,high);

}

}

void QuickSort(SqList *L)

{QSort(L,1,L->length);

}

void pause()

{printf("Pause,continue blankspace pressed\n");

while(getch()!=' ');

}

/*主函数部分,文件名为sort.c*/

main()

{int select;

SqList L;

do

{ clrscr();

printf(" 1 select_sort 2 quick_sort 0 exit\n ");

printf(" Please input number(0-2)\n");

scanf("%d",&select);

switch (select)

{case 0:exit(0);

case 1:create(&L);

visit(L);

select_sort(&L);

visit(L);

break;

case 2:create(&L); 数据结构实验指导与练习题

- 31 -

visit(L);

QuickSort(&L);

visit(L);

break;

default:printf("ERROR!\n"); break;

}

pause();

}while(1);

}

数据结构与算法问题分析及源代码之二叉树

二叉树 1 题目 编写一个程序,实现二叉树的各种运算,并在此基础上设计一个主程序完成如下功能(b 为如图示的一棵二叉树): 输出二叉树b; 输出‘H’节点的左、 右孩子结点值; 输出二叉树b的深度; 输出二叉树b的结点个数; 输出二叉树b的叶子结点个数。 2 目标 熟悉二叉树的定义及其基本操作的实现 3 设计思想 二叉树的每个结点都有指向其左右孩子的指针,对二叉树的表示可以有很多方法,这里采用中序的带括号表示法,以字符串形式读入输出。建立存储结构的时候,从根结点开始,赋值定义其左右指针,由于二叉树的每个结点操作类似,因此可以采用递归的方法。 4 算法描述 (1)输入建立二叉树:读入字符串,根据括号表示法的规则,a(b,c)的括号中左右元素表示结点的左右子树结点,若结点是树(括号中还有括号),则再调用改操作,直至结点全部读入。 (2)输出二叉树:从根结点开始,打印根结点数据,如果结点的左右孩子指针不为空,就打印左括号,并按先左后右的次序调用此操作,最后输出右括号完成括号表示。 (3)输出二叉树的深度:从根结点开始,如果左或右孩子不是树的话返回深度加一,否则继续调用此操作,直到完全返回(返回深度是左、右深度中的最大值)。 (4)输出二叉树叶子结点数:从根结点开始,用ln和r n分别表示结点左右叶子结点数,函数返回叶子结点数之和,递归调用该函数,直到左右指针指空。 (5)输出二叉树结点数:结点数即是叶子数加一。 5 程序结构图

6 源程序 typedef struct node{ char data; struct node *lchild; struct node *rchild; }*Bitree; Bitree bt; void CreateBitree(Bitree &bt,char *str){ Bitree St[100],p=NULL;//100个结点的二叉树 int top=-1,k,j=0; char ch; bt=NULL; ch=str[j]; while(ch!='\0') { switch(ch) { case'(':top++;St[top]=p;k=1;break; case')':top--;break; case',':k=2;break; default:p = (struct node*)malloc(sizeof(struct node)); p->data=ch;p->lchild=p->rchild=NULL; if (bt==NULL)//是根结点 bt=p; else//是叶子结点

数据结构课程实验指导书

数据结构实验指导书 一、实验目的 《数据结构》是计算机学科一门重要的专业基础课程,也是计算机学科的一门核心课程。本课程较为系统地论述了软件设计中常用的数据结构以及相应的存储结构与实现算法,并做了相应的性能分析和比较,课程内容丰富,理论系统。本课程的学习将为后续课程的学习以及软件设计水平的提高打下良好的基础。 由于以下原因,使得掌握这门课程具有较大的难度: 1)理论艰深,方法灵活,给学习带来困难; 2)内容丰富,涉及的知识较多,学习有一定的难度; 3)侧重于知识的实际应用,要求学生有较好的思维以及较强的分析和解决问题的能力,因而加大了学习的难度; 根据《数据结构》课程本身的特性,通过实验实践内容的训练,突出构造性思维训练的特征,目的是提高学生分析问题,组织数据及设计大型软件的能力。 课程上机实验的目的,不仅仅是验证教材和讲课的内容,检查自己所编的程序是否正确,课程安排的上机实验的目的可以概括为如下几个方面: (1)加深对课堂讲授内容的理解 实验是对学生的一种全面综合训练。是与课堂听讲、自学和练习相辅相成的必不可少的一个教学环节。通常,实验题中的问题比平时的习题复杂得多,也更接近实际。实验着眼于原理与应用的结合点,使学生学会如何把书上学到的知识用于解决实际问题,培养软件工作所需要的动手能力;另一方面,能使书上的知识变" 活" ,起到深化理解和灵活掌握教学内容的目的。 不少学生在解答习题尤其是算法设计时,觉得无从下手。实验中的内容和教科书的内容是密切相关的,解决题目要求所需的各种技术大多可从教科书中找到,只不过其出

现的形式呈多样化,因此需要仔细体会,在反复实践的过程中才能掌握。 (2) 培养学生软件设计的综合能力 平时的练习较偏重于如何编写功能单一的" 小" 算法,而实验题是软件设计的综合训练,包括问题分析、总体结构设计、用户界面设计、程序设计基本技能和技巧,多人合作,以至一整套软件工作规范的训练和科学作风的培养。 通过实验使学生不仅能够深化理解教学内容,进一步提高灵活运用数据结构、算法和程序设计技术的能力,而且可以在需求分析、总体结构设计、算法设计、程序设计、上机操作及程序调试等基本技能方面受到综合训练。实验着眼于原理与应用的结合点,使学生学会如何把书本上和课堂上学到的知识用于解决实际问题,从而培养计算机软件工作所需要的动手能力。 (3) 熟悉程序开发环境,学习上机调试程序一个程序从编辑,编译,连接到运行,都要在一定的外部操作环境下才能进行。所谓" 环境" 就是所用的计算机系统硬件,软件条件,只有学会使用这些环境,才能进行 程序开发工作。通过上机实验,熟练地掌握程序的开发环境,为以后真正编写计算机程序解决实际问题打下基础。同时,在今后遇到其它开发环境时就会触类旁通,很快掌握新系统的使用。 完成程序的编写,决不意味着万事大吉。你认为万无一失的程序,实际上机运行时可能不断出现麻烦。如编译程序检测出一大堆语法错误。有时程序本身不存在语法错误,也能够顺利运行,但是运行结果显然是错误的。开发环境所提供的编译系统无法发现这种程序逻辑错误,只能靠自己的上机经验分析判断错误所在。程序的调试是一个技巧性很强的工作,尽快掌握程序调试方法是非常重要的。分析问题,选择算法,编好程序,只能说完成一半工作,另一半工作就是调试程序,运行程序并得到正确结果。 二、实验要求 常用的软件开发方法,是将软件开发过程划分为分析、设计、实现和维护四个阶段。虽然数据结构课程中的实验题目的远不如从实际问题中的复杂程度度高,但为了培养一个软件工作者所应具备的科学工作的方法和作风,也应遵循以下五个步骤来完成实验题目: 1) 问题分析和任务定义 在进行设计之前,首先应该充分地分析和理解问题,明确问题要求做什么?限制条件是什么。本步骤强调的是做什么?而不是怎么做。对问题的描述应避开算法和所涉及的数据类型,而是对所需完成的任务作出明确的回答。例如:输入数据的类型、值的范围以及输入的

数据结构题目及c语言代码

目题程设计《数据结构》课)C语言程序实现采用():3选王(学时目 题1:猴子一堆猴子都有编号,编号是1,2,3 ...m,这群猴子(m个)按照1-m 的顺序围坐一圈,从第1开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,直到圈中只剩下最后一只猴子,则该猴子为大王。 要求:m及n要求从键盘输入,存储方式采用向量及链表两种方式实现该问题求解。 //链表 #include #include // 链表节点 typedef struct _RingNode { int pos; struct _RingNode *next; }RingNode, *RingNodePtr; // 创建约瑟夫环,pHead:链表头指针,count:链表元素个数 void CreateRing(RingNodePtr pHead, int count) { RingNodePtr pCurr = NULL, pPrev = NULL; int i = 1; pPrev = pHead; while(--count > 0) {

pCurr = (RingNodePtr)malloc(sizeof(RingNode)); i++; pCurr->pos = i; pPrev->next = pCurr; pPrev = pCurr; } pCurr->next = pHead; // 构成环状链表 } void KickFromRing(RingNodePtr pHead, int n) { RingNodePtr pCurr, pPrev; int i = 1; // 计数 pCurr = pPrev = pHead; while(pCurr != NULL) { if (i == n) { // 踢出环 printf(\ %d, pCurr->pos); // 显示出圈循序 pPrev->next = pCurr->next;

(完整版)数据结构实验报告全集

数据结构实验报告全集 实验一线性表基本操作和简单程序 1 .实验目的 (1 )掌握使用Visual C++ 6.0 上机调试程序的基本方法; (2 )掌握线性表的基本操作:初始化、插入、删除、取数据元素等运算在顺序存储结构和链表存储结构上的程序设计方法。 2 .实验要求 (1 )认真阅读和掌握和本实验相关的教材内容。 (2 )认真阅读和掌握本章相关内容的程序。 (3 )上机运行程序。 (4 )保存和打印出程序的运行结果,并结合程序进行分析。 (5 )按照你对线性表的操作需要,重新改写主程序并运行,打印出文件清单和运行结果 实验代码: 1)头文件模块 #include iostream.h>// 头文件 #include// 库头文件------ 动态分配内存空间 typedef int elemtype;// 定义数据域的类型 typedef struct linknode// 定义结点类型 { elemtype data;// 定义数据域 struct linknode *next;// 定义结点指针 }nodetype; 2)创建单链表

nodetype *create()// 建立单链表,由用户输入各结点data 域之值, // 以0 表示输入结束 { elemtype d;// 定义数据元素d nodetype *h=NULL,*s,*t;// 定义结点指针 int i=1; cout<<" 建立一个单链表"<> d; if(d==0) break;// 以0 表示输入结束 if(i==1)// 建立第一个结点 { h=(nodetype*)malloc(sizeof(nodetype));// 表示指针h h->data=d;h->next=NULL;t=h;//h 是头指针 } else// 建立其余结点 { s=(nodetype*) malloc(sizeof(nodetype)); s->data=d;s->next=NULL;t->next=s; t=s;//t 始终指向生成的单链表的最后一个节点

大数据结构与算法课程设计程序及报告材料

数据结构与算法课程设计报告 题目 两两相连的房间问题: 一所奇怪的房子,这所房子里有n个房间,每个房间里有一些门通向别的房间,可是这些门十分奇怪,它们只能从房间a开向房间b,也就是说,一扇从a开向b的门是不能让一个人从b房间走到a房间的。你能计算一下任意两个房间之间都互相相通吗? 问题分析 此程序需要完成如下要求:在这所房子里,从任意一个房间开始,按照开门的方向,均能够找到一个合适的路线,使得一个人能够不重复的到达其他的每一个房间,所以,需以每一个房间都为一次起始点来走向其他的房间,以此来判断这所房子里的任意两个房间之间是否互相相通。 实现本程序需要解决以下问题: 1.如何表示每一个房间,即存储房间的信息,并且还要确定这所房子里的各个房间的位置。 2.各个房间之间的门,以及门是从哪个房间开向哪个房间的该如何表示和存储的。 3.从某一个房间开始,如何走到其他各个房间,即如何对房间进行遍历。 4.为了在遍历过程中,不重复的遍历每一个房间,该如何标记已被遍历过的房间,从而只 访问未走过的房间。 5.最后通过什么的遍历方式才能判断各个房间之间是否互相相通。

数据结构的选择和概要设计 通过对题目要求的理解,我们可以用图来表示这所房子,而房子中的各个房间就相当于图中的各个结点,由于房间的门是有方向的,一扇从a开向b的门是不能让一个人从b房间走到a 房间的,从而可知该图为有向图,那么门就相当于有向图中的弧,从一个门开向另一个门即代表有向图中弧的起始点和终止点。 对于图的存储,我采用邻接表的形式来存储,并将每一个房间进行编号,对于邻接表,则需要定义一个邻接表结点类型、邻接表表头结点类型,通过表头与结点的连接而将有向图中弧的信息存储起来。那么人从任意一个房间走向另一个房间,即相当于有向图中从一个结点按照弧的信息访问其他的结点,可以采用深度优先搜索遍历。如果从每一个结点以起始点开始一次遍历就都能访问到其他结点的话则说明有向图是连通图,即该房子里的各个房间能够互相相通。定义一个全局的整形变量flag,如果是连通图的话则flag=1,否则flag=0。 程序实现的流程图如下:

数据结构实验报告代码

线性表 代码一 #include "stdio.h" #include "malloc.h" #define OK 1 #define ERROR 0 #define OVERFLOW -2 #define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 typedef struct { int * elem; int length; int listsize; }SqList; int InitList_Sq(SqList *L) { L->elem = (int*)malloc(LIST_INIT_SIZE*sizeof(int)); if (!L->elem) return ERROR; L->length = 0; L->listsize = LIST_INIT_SIZE; return OK; } int ListInsert_Sq(SqList *L, int i,int e) { int *p,*newbase,*q; if (i < 1 || i > L->length+1) return ERROR; if (L->length >= L->listsize) { newbase = (int *)realloc(L->elem,(L->listsize+LISTINCREMENT)*sizeof (int)); if (!newbase) return ERROR; L->elem = newbase; L->listsize += LISTINCREMENT; } q = &(L->elem[i-1]); //插入后元素后移for(p=&(L->elem[L->length-1]);p>=q;p--) *(p+1)=*p; *q=e; L->length++; return OK; } int ListDelete_Sq(SqList *L, int i, int *e) {

数据结构:树形结构完整代码,各种遍历方法,直接能跑

#include #include #define TElemType int typedef struct BiTNode { TElemType data; struct BiTNode *lchild, *rchild; } BiTNode, *BiTree; typedef BiTree DataType; typedef struct queuenode{ DataType data; struct queuenode *next; } QueueNode; //LINKQUEUE //HEAD POINTER, AND REAR POINTER ARE A V ALIBALE typedef struct { QueueNode *front; QueueNode *rear; } LinkQueue; int InitQueue(LinkQueue *Q); int DestroyQueue(LinkQueue *Q); int QueueEmpty(LinkQueue Q); int EnQueue(LinkQueue *Q, DataType e); DataType DeQueue(LinkQueue *Q); int CreateBiTree(BiTree *T); int PreOrderTraverse(BiTree T, int (*visit)(TElemType e)); int PreOrderTraverse2(BiTree T, int (*visit)(TElemType e)); int InOrderTraverse(BiTree T, int (*visit)(TElemType e)); int InOrderTraverse2(BiTree T, int (*visit)(TElemType e)); int PostOrderTraverse(BiTree T, int (*visit)(TElemType e)); int PostOrderTraverse2(BiTree T, int (*visit)(TElemType e)); int LevelOrderTraverse(BiTree T, int (*visit)(TElemType e)); int printElem(TElemType e); int InitBiTree(BiTree *T); int DestroyBiTree(BiTree *T); int ClearBiTree(BiTree *T); int BiTreeEmpty(BiTree T); int BiTreeDepth(BiTree T);

约瑟夫问题数据结构实验报告汇总.

中南民族大学管理学院学生实验报告 实验项目: 约瑟夫问题 课程名称:数据结构 年级: 专业:信息管理与信息系统 指导教师: 实验地点:管理学院综合实验室 完成日期: 小组成员: 2012 学年至2013 学年度第1 学期

一、实验目的 (1)掌握线性表表示和实现; (2)学会定义抽象数据类型; (3)学会分析问题,设计适当的解决方案; 二、实验内容 【问题描述】:编号为1,2,…,n的n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自 1 开始顺序报数,报到m 时停止报数。报m 的人出列,将他的密码作为新的m 值,从他在顺时针方向上的下一个人开始重新从1 报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。 【基本要求】:利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。 【测试数据】:m 的初值为20;密码:3,1,7,2,4,8,4(正确的结果应为6,1,4,7,2,3,5)。 三、实验步骤 (一)需求分析 对于这个程序来说,首先要确定构造链表时所用的插入方法。当数到m 时一个人就出列,也即删除这个节点,同时建立这个节点的前节点与后节点的联系。由于是循环计数,所以才采用循环列表这个线性表方式。 程序存储结构利用单循环链表存储结构存储约瑟夫数据(即n个人的编码等),模拟约瑟夫的显示过程,按照出列的顺序显示个人的标号。编号为1,2,…,n 的 n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值 m,从第一个人开始按顺时针方向自1 开始顺序报数,报到 m 时停止报数。报 m 的人出列,将他的密码作为新的 m 值,从他在顺时针方向上的下一个人开始重新从 1 报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。基本要求是利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。 程序执行的命令(1)构造单向循环链表。 (2)按照出列的顺序引出各个人的标号。 测试数据 m 的初值为 20;密码:3,1,7,2,4,8,4(正确的结果应为 6,1,4,7,2,3,5) (1)、插入:在把元素插入到循环链表中时,由于是采用的头插法,所以我保留了front头结点。在每加入一个节点时,都会直接连接在front后面,从而保证一开始就赋值的rear尾节点不用修改。 伪代码阐释如下:

天津科技大学数据结构与算法课程设计

《数据结构与算法分析》课程设计教学任务书 一、课程设计的目的 数据结构与算法课程主要是研究非数值计算的程序设计问题中所出现的计算机操作对象以及它们之间的关系和操作的学科。数据结构是介于数学、计算机软件和计算机硬件之间的一门计算机专业的核心课程,它是计算机程序设计、数据库、操作系统、编译原理及人工智能等的重要基础,广泛的应用于信息学、系统工程等各种领域。 学习数据结构与算法是为了将实际问题中涉及的对象在计算机中表示出来并对它们进行处理。通过课程设计可以提高学生的思维能力,促进学生的综合应用能力和专业素质的提高。通过此次课程设计主要达到以下目的: 了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力; 初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能; 提高综合运用所学的理论知识和方法独立分析和解决问题的能力; 训练用系统的观点和软件开发一般规范进行软件开发,培养软件工作者所应具备的科学的工作方法和作风。 二、课程设计的基本要求 1. 独立思考,独立完成:课程设计中各任务的设计和调试要求独立完成,遇到问题可以讨论,但不可以拷贝。 2. 做好上机准备:每次上机前,要事先编制好准备调试的程序,认真想好调试步骤和有关环境的设置方法,准备好有关的文件。 3. 按照课程设计的具体要求建立功能模块,每个模块要求按照如下几个内容认真完成: a)需求分析: 在该部分中叙述,每个模块的功能要求 b)概要设计: 在此说明每个部分的算法设计说明(可以是描述算法的流程图),每个程序中使用的存储结构设计说明(如果指定存储结构请写出该存储结构的定义) c)详细设计: 各个算法实现的源程序,对每个题目要有相应的源程序(可以是一组程序,每个功能模块采用不同的函数实现) 源程序要按照写程序的规则来编写。要结构清晰,重点函数的重点变量,重点功能部分要加上清晰的程序注释 d)调试分析: 测试数据,测试输出的结果,时间复杂度分析,和每个模块设计和调试时存在问题的思考(问题是哪些,问题如何解决?),算法的改进设想 课程设计总结:(保存在word文档中)总结可以包括:课程设计过程的收获、遇到的问题、解决问题过程的思考、程序调试能力的思考、对数据结构这门课程的思考、在课程设计过程中对《数据结构》课程的认识等内容 4. 实现的结果必须进行检查和演示,程序源代码和程序的说明文件必须上交,作为考核内容的一部分。(上交时每人交一份,文件夹的取名规则为:“学号姓名”,如“09201199王五”。该文件夹下至少包括:“源代码”、“课程设计报告”、“可执行文件”。由学习委员收

数据结构实验一的源代码

#include #include typedef struct Node { int key;//密码 int num;//编号 struct Node *next;//指向下一个节点 } Node, *Link; void InitList(Link &L) //创建一个空的链表{ L = (Node *)malloc(sizeof(Node)); if (!L) exit(1); L->key = 0; L->num = 0; L->next = L; } void Creatlinklist(int n, Link &L) //初始化链表{ Link p, q; q = L; for (int i = 1; i <= n; i++) { p = (Node *)malloc(sizeof(Node)); if (!p) exit(1); scanf("%d", &p->key); p->num = i; L->next = p; L = p; } L->next = q->next; free(q); } Link Locate_m(Link &p, int m)//找到第m个 { Link q; for (int j = 1; jnext; q = p->next; m = q->key;

return q; } void Delete_m(Link &L, Link p, Link q)//删除第m个{ p->next = q->next; free(q); } void main() { Link L, p, q; int n, m; L = NULL; InitList(L);//构造出一个只有头结点的空链表 printf("请输入初始密码人数每个人的密码:\n"); scanf("%d", &m);//初始密码为m scanf("%d", &n);// Creatlinklist(n, L);//构建 p = L; for (int i = 1; i <= n; i++) { q = Locate_m(p, m);//找到第m个 printf("%d", q->num); Delete_m(L, p, q);//删除第m个 } system("pause"); }

数据结构源代码(清华大学+严蔚敏)

void Union(List &La, List Lb) { // 算法2.1 // 将所有在线性表Lb中但不在La中的数据元素插入到La中 int La_len,Lb_len,i; ElemType e; La_len = ListLength(La); // 求线性表的长度 Lb_len = ListLength(Lb); for (i=1; i<=Lb_len; i++) { GetElem(Lb, i, e); // 取Lb中第i个数据元素赋给e if (!LocateElem(La, e, equal)) // La中不存在和e相同的数据元素 ListInsert(La, ++La_len, e); // 插入 } } // union void MergeList(List La, List Lb, List &Lc) { // 算法2.2 // 已知线性表La和Lb中的元素按值非递减排列。 // 归并La和Lb得到新的线性表Lc,Lc的元素也按值非递减排列。int La_len, Lb_len; ElemType ai, bj; int i=1, j=1, k=0; InitList(Lc); La_len = ListLength(La); Lb_len = ListLength(Lb); while ((i <= La_len) && (j <= Lb_len)) { // La和Lb均非空 GetElem(La, i, ai); GetElem(Lb, j, bj); if (ai <= bj) { ListInsert(Lc, ++k, ai); ++i; } else { ListInsert(Lc, ++k, bj); ++j; } } while (i <= La_len) { GetElem(La, i++, ai); ListInsert(Lc, ++k, ai); } while (j <= Lb_len) { GetElem(Lb, j++, bj); ListInsert(Lc, ++k, bj); } } // MergeList Status InitList_Sq(SqList &L) { // 算法2.3 // 构造一个空的线性表L。 L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType)); if (!L.elem) return OK; // 存储分配失败 L.length = 0; // 空表长度为0 L.listsize = LIST_INIT_SIZE; // 初始存储容量 return OK; } // InitList_Sq Status ListInsert_Sq(SqList &L, int i, ElemType e) { // 算法2.4 // 在顺序线性表L的第i个元素之前插入新的元素e, // i的合法值为1≤i≤ListLength_Sq(L)+1 ElemType *p; if (i < 1 || i > L.length+1) return ERROR; // i值不合法 if (L.length >= L.listsize) { // 当前存储空间已满,增加容量 ElemType *newbase = (ElemType *)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof (ElemType)); if (!newbase) return ERROR; // 存储分配失败 L.elem = newbase; // 新基址 L.listsize += LISTINCREMENT; // 增加存储容量 } ElemType *q = &(L.elem[i-1]); // q为插入位置 for (p = &(L.elem[L.length-1]); p>=q; --p) *(p+1) = *p; // 插入位置及之后的元素右移 *q = e; // 插入e ++L.length; // 表长增1 return OK; } // ListInsert_Sq Status ListDelete_Sq(SqList &L, int i, ElemType &e) { // 算法2.5 // 在顺序线性表L中删除第i个元素,并用e返回其值。 // i的合法值为1≤i≤ListLength_Sq(L)。 ElemType *p, *q; if (i<1 || i>L.length) return ERROR; // i值不合法 p = &(L.elem[i-1]); // p为被删除元素的位置 e = *p; // 被删除元素的值赋给e q = L.elem+L.length-1; // 表尾元素的位置 for (++p; p<=q; ++p) *(p-1) = *p; // 被删除元素之后的元素左移--L.length; // 表长减1 return OK; } // ListDelete_Sq int LocateElem_Sq(SqList L, ElemType e, Status (*compare)(ElemType, ElemType)) { // 算法2.6 // 在顺序线性表L中查找第1个值与e满足compare()的元素的位序。// 若找到,则返回其在L中的位序,否则返回0。 int i; ElemType *p; i = 1; // i的初值为第1个元素的位序 p = L.elem; // p的初值为第1个元素的存储位置 while (i <= L.length && !(*compare)(*p++, e)) ++i; if (i <= L.length) return i; else return 0; } // LocateElem_Sq void MergeList_Sq(SqList La, SqList Lb, SqList &Lc) { // 算法2.7 // 已知顺序线性表La和Lb的元素按值非递减排列。 // 归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列。ElemType *pa,*pb,*pc,*pa_last,*pb_last; pa = La.elem; pb = Lb.elem; Lc.listsize = Lc.length = La.length+Lb.length; pc = Lc.elem = (ElemType *)malloc(Lc.listsize*sizeof(ElemType)); if (!Lc.elem) exit(OVERFLOW); // 存储分配失败 pa_last = La.elem+La.length-1; pb_last = Lb.elem+Lb.length-1;

数据结构停车场问题实验报告汇总

数据结构课程设计 ——停车场管理问题 姓名: 学号: 问题描述 设有一个可以停放n辆汽车的狭长停车场,它只有一个大门可以供车辆进出。车辆按到达停车场时间的早晚依次从停车场最里面向大门口处停放(最先到达的第一辆车放在停车场的最里面)。如果停车场已放满n辆车,则后来的

车辆只能在停车场大门外的便道上等待,一旦停车场内有车开走,则排在便道上的第一辆车就进入停车场。停车场内如有某辆车要开走,在它之后进入停车场的车都必须先退出停车场为它让路,待其开出停车场后,这些车辆再依原来的次序进场。每辆车在离开停车场时,都应根据它在停车场内停留的时间长短交费。如果停留在便道上的车未进停车场就要离去,允许其离去,不收停车费,并且仍然保持在便道上等待的车辆的次序。编制一程序模拟该停车场的管理。 二、实现要求 要求程序输出每辆车到达后的停车位置(停车场或便道上),以及某辆车离开停车场时应交纳的费用和它在停车场内停留的时间。 三、实现提示 汽车的模拟输入信息格式可以是:(到达/离去,汽车牌照号码,到达/离去的时刻)。例如,(‘A',,1,5)表示1号牌照车在5这个时刻到达,而(‘ D ',,5,20)表示5号牌照车在20这个时刻离去。整个程序可以在输入信息为(‘ E ',0,0)时结束。本题可用栈和队列来实现。 四、需求分析 停车场采用栈式结构,停车场外的便道采用队列结构(即便道就是等候队列)。停车场的管理流程如 下 ①当车辆要进入停车场时,检查停车场是否已满,如果未满则车辆进栈(车辆进入停车场);如果停车场已满,则车辆进入等候队列(车辆进入便道等候)。 ②当车辆要求出栈时,该车到栈顶的那些车辆先弹出栈(在它之后进入的车辆必须先退出车场为它让路),再让该车出栈,其他车辆再按原次序进栈(进入车场)。当车辆出栈完毕后,检查等候队列(便道) 中是否有车,有车则从队列头取出一辆车压入栈中。

数据结构实验程序

顺序表的基本操作 #include using namespace std; typedef int datatype; #define maxsize 1024 #define NULL -1 typedef struct { datatype *data; int last; }sequenlist; void SETNULL(sequenlist &L) { L.data=new datatype[maxsize]; for(int i=0;i>https://www.docsj.com/doc/c918671967.html,st; cout<<"请输入"<>L.data[i]; } int LENGTH(sequenlist &L) { int i=0; while(L.data[i]!=NULL) i++; return i; } datatype GET(sequenlist &L,int i) { if(i<1||i>https://www.docsj.com/doc/c918671967.html,st) { cout<<"error1"<

int j=0; while(L.data[j]!=x) j++; if(j==https://www.docsj.com/doc/c918671967.html,st) { cout<<"所查找值不存在!"<=maxsize-1) { cout<<"overflow"; return NULL; } else if(i<1||(i>https://www.docsj.com/doc/c918671967.html,st)) { cout<<"error2"<=i-1;j--) L.data[j+1]=L.data[j]; L.data[i-1]=x; https://www.docsj.com/doc/c918671967.html,st++; } return 1; } int DELETE(sequenlist &L,int i) { int j; if((i<1)||(i>https://www.docsj.com/doc/c918671967.html,st+1)) { cout<<"error3"<

数据结构课程设计文章编辑(附录中有全部代码)

课程设计任务书 专业名称:计算机科学与技术(软件工程) 课程名称:数据结构课程设计 设计题目:文章编辑问题 起止时间:2013年6 月24 日至2013年7 月12 日 问题描述 静态存储一页文章,每行最多不超过80个字符,共N行,程序可以统计出文字、数字、空格的个数,并且可以对文章中特定内容进行查找及替换,同时也可以删除指定内容。 基本要求 (1)分别统计出其中英文字母数和空格数及整篇文章总字数; (2)统计某一字符串在文章中出现的次数,并输出该次数; (3)查找出文章中某一段文字,并用其他文字进行替换; (4)删除某一子串,并将后面的字符前移。 输出形式: (1)分行输出用户输入的各行字符; (2)分4行输出"全部字母数"、"数字个数"、"空格个数"、"文章总字数"; (3)查找出指定字符串在文章中出现的所有地方并替换,输出替换后结果; (4)输出删除某一字符串后的文章; 实现提示 存储结构使用线性表,分别用几个子函数实现相应的功能,并且使用菜单的形式,可以选择所要进行的操作(查找、替换、删除、统计等)。

文章编辑系统 1概要设计 本次课程设计的题目是文章编辑系统,本系统的功能描述如下:用户新建文本、浏览新建文本、文本字符统计、指定字符串统计、指定字符串删除、指定字符串替换等操作。 1.新建文本 2.浏览输入文本 3.文本字符统计 4.指定字符串统计 5.指定字符串删除 6.指定字符串替换 7.退出系统 本系统包含七个功能模块,分别为:新建文本模块,浏览输入文本模块,指定字符串统计模块,指定字符串删除模块,指定字符串删除模块,指定字符串替换模块以退出系统模块。新建文本模块实现用户录入文本信息,并且系统自动保存录入信息。浏览输入文本模块实现了显示用户录入信息的功能。指定字符串统模块实现了对英文字母数和空格数及整篇文章总字数的统计。指定字符串统计实现了统计用户自定义字符串个数的功能。指定字符串删除模块实现了对用户自定义字符串的删除。指定字符串替换模块实现了替换用户自定义字符串为用户定义的新字符功能。退出系统模块实现了退出系统功能。

数据结构实验报告

数据结构实验报告 一.题目要求 1)编程实现二叉排序树,包括生成、插入,删除; 2)对二叉排序树进行先根、中根、和后根非递归遍历; 3)每次对树的修改操作和遍历操作的显示结果都需要在屏幕上用树的形状表示出来。 4)分别用二叉排序树和数组去存储一个班(50人以上)的成员信息(至少包括学号、姓名、成绩3项),对比查找效率,并说明在什么情况下二叉排序树效率高,为什么? 二.解决方案 对于前三个题目要求,我们用一个程序实现代码如下 #include #include #include #include "Stack.h"//栈的头文件,没有用上 typedefintElemType; //数据类型 typedefint Status; //返回值类型 //定义二叉树结构 typedefstructBiTNode{ ElemType data; //数据域 structBiTNode *lChild, *rChild;//左右子树域 }BiTNode, *BiTree; intInsertBST(BiTree&T,int key){//插入二叉树函数 if(T==NULL) { T = (BiTree)malloc(sizeof(BiTNode)); T->data=key; T->lChild=T->rChild=NULL; return 1; } else if(keydata){ InsertBST(T->lChild,key); } else if(key>T->data){ InsertBST(T->rChild,key); } else return 0; } BiTreeCreateBST(int a[],int n){//创建二叉树函数 BiTreebst=NULL; inti=0; while(i

数据结构上机实验线性表单链表源代码

#include template class LinearList { public: virtual bool IsEmpty()const=0; virtual int Length()const=0; virtual bool Find(int i,T& x)const=0; virtual int Search(T x)const=0; virtual bool Insert(int i,T x)=0; virtual bool Update(int i,T x)=0; virtual bool Delete(int i)=0; virtual void Output(ostream& out)const=0; protected: int n; }; #include "linearlist" template class SeqList:public LinearLisr { public: SeqList(int mSize); ~SeqList(){delete [] elements;} bool IsEmpty()const; bool Find(int i,T& x)const; int Length()const; int Search(T x)const; bool Insert(int i,T x); bool Update(int i,T x); bool Delete(int i); void Output(ostream& out)const; private: int maxLength; T *elements; }; template SeqList::SeqList(int mSize) { maxLength=mSize;

相关文档
相关文档 最新文档