上期已经实现了将十六进制转二进制的操作,现在这期写的是将txt文件里的十六进制的每两个字节合成一个十六进制的一个字节,把每个字节当做一个节点建立链表。再将他们进行排序,这里面用到的是快速排序法,快速排序不懂原理的童鞋可以先看这个视频:https://www.bilibili.com/video/BV1at411T75o?spm_id_from=333.337.search-card.all.click&vd_source=b9705750db39c27d796acd63578ceb55
快速排序法用数组遍历的方法排序是很简单的,若要用链表遍历,难度会变大点,因此要实现快速排序法,需要用到数组的思想实现快速排序。我这里封装了一个seekLinkAdd函数,通过链表的遍历能够找到某个元素的值,然后返回某个元素的地址。调用这个函数时用*取值符,能得到某个元素的值。快速排序中将某元素的地址传过来,再对里面的值进行修改,这样就可以实现数组的快速排序思想。
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include<assert.h>
struct charLink
{
int c;
struct charLink *next;
};
uint32_t a = 0;
uint32_t cnt = 0;
struct charLink *head = NULL;
struct charLink *new = NULL;
int out, in;
//尾插法动态添加结点
struct charLink *addLink(struct charLink *head,struct charLink *new)
{
struct charLink *p =head;
if(head == NULL)
{
return new;
}
//遍历到最后一个
while(p->next != NULL )
{
p = p->next;
}
//然后让新节点作为头结点
p->next = new;
return head;
}
//统计结点个数
int sumNode(struct charLink* head)
{
int data=0;
while(head != NULL)
{
data++;
head = head->next;
}
return data;
}
//查找某个元素的地址
int* seekLinkAddr(struct charLink *head,int idx)
{
int data = sumNode(head);
//printf("idx = %d\n",idx);
//断言,如果不满足0=<idx<data,编译器会报错
assert(idx>=0 && idx< data);
struct charLink *p = head;
//遍历到某个元素的位置
while(p !=NULL && idx !=0)
{
p=p->next;
idx--;
}
//然后返回某个元素的地址
return &(p->c);
}
//打印链表
void printLink(struct charLink*head)
{
struct charLink *point = head;
while(point != NULL){
printf("%02x\n",point->c);
point = point->next;
}
putchar('\n');
}
//字节的合成
int handChar(char *filename,FILE *fp)
{
int data[2];
while (1)
{
out = fgetc(fp);
if (out == EOF)
{
if (a == 1)
{
fputc(data[0], fp);
cnt++;
}
break;
}
else if (out == ' ' || out == '\n' || out == '\r')
{
continue;
}
else if (out >= '0' && out <= '9')
{
out = out - '0';
}
else if (out >= 'a' && out <= 'f')
{
out = out - 'a' + 10;
}
else if (out >= 'A' && out <= 'F')
{
out = out - 'A' + 10;
}
else
{
printf("存在其他二进制文件!\n");
fclose(fp);
return -1;
}
data[a] = out;
a++;
if (a == 2)
{
a = 0;
new = (struct charLink*)malloc(sizeof(struct charLink));
new->next=NULL;
new->c = (data[0] * 16) + data[1];
fputc(new->c, fp);
head = addLink(head,new);
cnt++;
}
}
return 1;
fclose(fp);
}
//快速排序法
void quickSort(struct charLink* head,int left,int right)
{
int i = left;
int j = right;
//int temp;
//选第一个为准基数
int pivot=*seekLinkAddr(head,i);
if(i>=j)
{
return ;
}
while(i<j)
{
//printf("i = %d,j = %d\n",i,j);
//printf("j = %02x\n",*seekLinkAddr(head,i));
//如果这个数比准基数大,则右边退一个
while( *seekLinkAddr(head,j) >= pivot && i<j)
{
j--;
}
//否则比他小的话就将i的位置赋值j的值
*seekLinkAddr(head,i) = *seekLinkAddr(head,j);
//如果这个数比准基数大,则左边前进一个
while( (*seekLinkAddr(head,i)) <= pivot && i<j)
{
i++;
}
//否则的话将j的位置赋值i的值
*seekLinkAddr(head,j)=*seekLinkAddr(head,i);
*seekLinkAddr(head,i) = pivot;
//将左边递归,重复以上动作
if(i-1>left){ //注意 要写i-1<left 这个条件,不然会出现段错误
quickSort(head,left,i-1);
}
//将右边递归,重复以上动作
if(i+1<right){
quickSort(head,i+1,right);
}
//printf("i = %d,j = %d\n",i,j);
}
}
int main()
{
FILE* fp;
int ret=0;
int i;
char filename[12]="src.txt";
/*if(argc <=1)
{
printf("please input ./a.out xxx.txt\n");
}*/
fp = fopen(filename, "r");
if (fp ==NULL)
{
//printf("%s cannot be open!\n", argv[1]);
return -1;
}
//字节的合成
handChar(filename,fp);
//节点数
int len = sumNode(head);
//head = twoSort(head);
//BubbleSort(head);
quickSort(head,0,len-1);
printf("done!\n");
//打印链表
printLink(head);
return 0;
}
实现的效果显示: