C语言实现个人通讯录(功能优化)-2

简介: C语言实现个人通讯录(功能优化)

C语言实现个人通讯录(功能优化)-1

https://developer.aliyun.com/article/1536733


3.6 通讯录的排序:

这个功能实现就相对于前面的功能来说就有意思多了,来听我细细道来:


  • 排序算法有八种,各种排序都是很不错的思路,比如被用于教学的冒泡排序,简单易懂,思想也贴切排序思想,所以常常用来教学初级;(具体八大排序算法,之后也会写成博客)
  • 这里我就选用八大排序最舒服的快排,为什么选用快排呢,当然是快咯,哈哈,但快排也在这里有一些缺陷,如果数据很少,或者有很多都是顺序输入,快排就有一点点吃亏,没事儿----会优化!!!
  • 先来介绍一下快排的思路吧,快排最开始是Hoare大佬提出来的思路如图: cdfe875b08184cac82ce0986b910dfd1.gif


这就是最开始Hoare大佬的快排思路:

  • 1.先定一个key值,把比key小的放key的以边,把比key大的放一边,这样key就找到了正确位置,这就是一趟的思路,不断二分,就可以排序了。
  • 2.不断二分,可递归,可不用递归,这里我就只是说一下递归方式。
void Swap( int* left,int* right)
{
  int t = *left;
  *left = *right;
  *right = t;
}
void Hoare_QuickSort(int* a, int left, int right)
{
//当二分到key值的一边只有一个数,或者没有时,便递归结束
  if (left >= right)
    return;
    
  int end = right, begin = left;
  int keyi = left;//这里表示的是key的下标索引
  while (left < right)
  {
    //左边做key,右边先走,可以保证相遇位置比key更小
    //right找小找到和找不到:
    //找到:left没有找到大,直到相遇
    //没找到:直接和left相遇,直接找到keyi值
    while (left<right&&a[right] >= a[keyi])//right找小停下
      right--;

    while (left<right&&a[left] <= a[keyi])//left找大(保证相遇小于key)
      left++;
    Swap( &a[left],&a [right]);//交换两者,分配
  }
  //最后相遇位置便是key的位置:
  Swap(&a[left], &a[keyi]);
  keyi = left;
  //key左边数组的初末索引:begin,keyi-1
  Hoare_QuickSort(a, begin, keyi - 1);
  //key右边数组的初末索引:keyi+1,end
  Hoare_QuickSort(a, keyi + 1, end);
}

当然Hoare大佬提出的版本肯定是存在一定缺陷的,需要优化,但是这种思想真的厉害!

这里直接给出时间复杂度:O(NlgN)~O(N*N)


  • 缺陷: 1.当所需要排的数列是顺序或者逆序时,快排时间复杂度是最大N的平方,严重影响快排的速度。2.快排在对数据少,并且部分具有一定顺序的排序并不是很完美。3.Hoare大佬的快排思路难以理解,思路理解困难。

对于上述缺陷我这里就不过度介绍了,但的确有优化方式(我会在后续的八大排序中介绍)在通讯录排序中用较优秀的方式来实现(这里就是和库里排序函数实现相近了):


void Swap(PeoInfo* left, PeoInfo* right)
{
  PeoInfo t = *left;
  *left = *right;
  *right = t;
}

int GerMidNumi(PeoInfo* a, int left, int right)
{
  int mid = (right + left) / 2;

  if (strcmp(a[left].name, a[mid].name) > 0)
  {
    if (strcmp(a[mid].name, a[right].name) > 0)
    {
      return mid;
    }
    else if (strcmp(a[left].name, a[right].name) < 0)
    {
      return left;
    }
    else
    {
      return right;
    }
  }
  else
  {
    if (strcmp(a[left].name, a[right].name) > 0)
    {
      return left;
    }
    else if (strcmp(a[mid].name, a[right].name) < 0)
    {
      return mid;
    }
    else
    {
      return right;
    }
  }
}

void  DP_QuickSort(PeoInfo* a, int left, int right)
{
  int end = right, begin = left;
  if (left >= right)
    return;
  //小区间优化:
  if ((right - left + 1) > 10)
  {
    //方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
    int midi = GerMidNumi(a, left, right);
    if (midi != left)
      Swap(&a[left], &a[midi]);

    int prev = left;
    int cur = prev + 1;
    int keyi = left;

    while (cur <= right)
    {
      if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
        Swap(&a[cur], &a[prev]);
      cur++;
    }
    Swap(&a[prev], &a[keyi]);
    keyi = prev;

    DP_QuickSort(a, begin, keyi - 1);
    DP_QuickSort(a, keyi + 1, end);
  }
  else
  {
    InsertSort(a, right - left + 1);
  }
}

void InsertSort(PeoInfo* a, int n)
{
  for (int i = 1; i < n; i++)
  {
    int end = i - 1;
    PeoInfo tmp = a[i];
    // 将tmp插入到[0,end]区间中,保持有序
    while (end >= 0)
    {
      if (strcmp(tmp.name, a[end].name) < 0)
      {
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = tmp;
  }
}

运行效果:

1fc44db07f565dd3433b41d14c0f00d8_092ab7206c0d43ea93fa1d2060ccc0a0.png


这里很有趣,但在这个部分就不过度介绍了,在后续博客会有详细介绍哈!


3.7 文件导入和导出功能:

我们当前所写的代码都是在内存里写的,一旦关闭数据便会清除,所以需要把数据导入到本地磁盘中进行保存,这里就需要文件相关知识了。知识掌握了,就十分简单了!


  • 本地导入内存:
void LondContact(Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
  if (NULL == pf)
  {
    perror("LondContact error");
  }
  else
  {
    int i = 0;
    PeoInfo tmp = { 0 };
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))
    {
      CapacityContact(pc);
      pc->data[i] = tmp;
      pc->sz++;
      i++;
    }
    fclose(pf);
    pf = NULL;
  }
}
  • 内存存入本地:
void SaveContact(const Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
  if (NULL == pf)
  {
    perror("SaveContact error");
  }
  else
  {
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
      fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    printf("保存成功\n");
  }
}

这就实现了通讯录的基本功能喽


3.8 分组打印:

这里我的通讯录是把分组定义为联系人的属性了的,所以只需要按照分组查找打印即可:


  void SearchByClass(const Contact* ps)
{
  {
    int i = 0;
    char class[CLASS_MAX];
    int flag = 0;
    int k = 1;
    printf("请输入需要查找联系人的组别:");
    scanf("%s", class);
    for (i = 0; i < ps->sz; i++)
    {
      if (strcmp(class, ps->data[i].class) == 0)
      {
        flag = 1;
        if (k == 1)
        {
          printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
          k--;
        }
        printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
          ps->data[i].name,
          ps->data[i].age,
          ps->data[i].sex,
          ps->data[i].address,
          ps->data[i].phone,
          ps->data[i].class);
      }
    }
    if (flag)
    {
      return;
    }
    else
    {
      printf("无法找到该联系人信息\n");
    }
  }
}


3.9 隐蔽空间的实现:

  • 这里的思路就是另外开辟本地文件,作为存储空间,但要注意的是,调用隐蔽空间时,切记先保存通讯录原本空间,并且退出(销毁)。再打开隐蔽空间的文件,就相当于实现一个小的通讯录,功能可照搬所以就不过多介绍。
  • 只介绍一下进入空间时的一些优化吧,比如ShowHide()函数,看似只是加载界面,其实他还可以实现清除屏幕(调用windows自带的cls)原先信息,做到更舒服的访问。代码如下:
void ShowHide()
{
  char arr1[] = "Welcome to Hide Room !!!";
  char arr2[] = "########################";

  int left = 0;
  int right = strlen(arr1) - 1;

  while (left <= right)
  {
    arr2[left] = arr1[left];
    arr2[right] = arr1[right];
    printf("%s\n", arr2);
    Sleep(1000);
    //清屏
    system("cls");
    left++;
    right--;
  }
  printf("%s\n", arr1);
}
  • 输入密码进入bool EncryptionContact()函数,这个函数还有太多可优化的地方:比如三次密码输入失败,24小时重试,这里用C语言就不方便了,可以用linux实现(后续会出相关博客)这里只能打印表示,还有就是密码的修改,这里我想的是还可以实现一个管理程序(哈哈,写博客想着想着就去实现了个,现在和大家分享!!!)
void Administrators(char* password)
{
  char newpassword[20];
  printf("请输入修改密码》:");
  scanf("%s", newpassword);
  strcpy(password, newpassword);
  printf("修改成功\n");
}

bool EncryptionContact()
{
  int i = 0;
  char password[20] = { 0 };
  char insure[20] = { "123456" };
//打开一个文件夹用来记录空间密码:
  FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
  if (NULL == pf1)
  {
    perror("password1 error");
  }
  else
  {
    char tmp[20] = { 0 };
    fread(&tmp, 20, 1, pf1);
    strcpy(insure, tmp);
    fclose(pf1);
    pf1 = NULL;
  }
//判断的主要函数:
  printf("请输入进入密码》:");
  for (i = 0; i < 3; i++)
  {
    scanf("%s", password);
    if (0 == strcmp(password, insure))
    {
      return true;
    }
    else if (0==strcmp(password,"管理员入口"))
    {
    //进入管理员系统进行密码修改
      Administrators(insure);
    //存入密码文件中
      FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
      if (NULL == pf2)
      {
        perror("password2 error");
      }
      else
      {
        fwrite(insure, 20, 1, pf2);
        fclose(pf2);
        pf2 = NULL;
        printf("保存成功\n");
      }
      printf("请输入进入密码》:");
    }
    else
    {
      printf("第%d次密码输入错误\n", i + 1);
      if (i < 2)
        printf("请重新输入》:");
    }
  }
  //linux操作系统实现
  printf("密码输入三次错误!请在24小时后重试\n");
  return false;
}

运行效果:

51ef82c8be39392ee0da248ca9122d3f_539d0879214942d6bb574b86e2e61bf5.png

0df86f41180968f71ce776d28fad0225_ac185cdb1a3f42428cd82b468db4a8b0.png


这里可以形成一个对比,就是代码没有封装可读性就很差,这里可以把写入和写出封装成函数。这里关于隐蔽空间其他功能大致相同就不过多介绍了。


Contact.c完整代码:


#include"Contact.h"

void mune()
{
  printf("*******************************************************\n");
  printf("********1.SearchByName    2.SearchByAge ***************\n");
  printf("********3.SearchBySex     4.SearchByAddr   ************\n");
  printf("********5.SearchByPhone   6.SearchByclass  ************\n");
  printf("*******************  0.exit  **************************\n");
  printf("*******************************************************\n");
}
void mune1()
{
  printf("**************************************\n");
  printf("********1.ADD    2.DEL ***************\n");
  printf("********3.SEARCH 4.MODIFY ************\n");
  printf("********5.SHOW   6.SORT   ************\n");
  printf("********0.EXIT            ************\n");

}

void func(Contact* pc)
{
  int input;
  mune1();
  do {
    printf("请输入选项>:");
    scanf("%d", &input);
    //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
    //若输入为0,则判断为FALSE,跳出循环,退出通讯录
    switch (input)
    {
    case ADD:
      AddContact(pc);
      break;
    case DEL:
      DelContact(pc);
      break;
    case SEARCH:
      SearchContact(pc);
      break;
    case MODIFY:
      ModifyContact(pc);
      break;
    case SHOW:
      PrintContact(pc);
      break;
    case SORT:
      SortContact(pc);
      break;
    case EXIT:
      //保存到文件中
      Hide_SaveContact(pc);
      //销毁通讯录空间
      DestroyContact(pc);
      printf("退出通讯录\n");
      break;
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  } while (input);

  return;
}

void LondContact(Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
  if (NULL == pf)
  {
    perror("LondContact error");
  }
  else
  {
    int i = 0;
    PeoInfo tmp = { 0 };
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))
    {
      CapacityContact(pc);
      pc->data[i] = tmp;
      pc->sz++;
      i++;
    }
    fclose(pf);
    pf = NULL;
  }
}

//主要用于函数的实现操作,功能实现处
//动态内存处理
void InitContact(Contact* pc)
{
  assert(pc);
  pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
  if (pc->data == NULL)
  {
    perror("malloc error");
  }
  pc->sz = 0;
  pc->capacity = INIT_MAX;

  //读取文件
  LondContact(pc);
}

void CapacityContact(Contact* pc)
{
  if (pc->sz == pc->capacity)
  {
    pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2);
    if (pc->data == NULL)
    {
      perror("realloc error");
    }
    pc->capacity = pc->capacity * 2;
    printf("扩容成功\n");
  }
}

void AddContact(Contact* pc)
{
  assert(pc);
  //自动扩容
  CapacityContact(pc);

  printf("请输入联系人名字:");
  scanf("%s", pc->data[pc->sz].name);
  printf("请输入联系人年龄:");
  scanf("%d", &(pc->data[pc->sz].age));
  printf("请输入联系人性别:");
  scanf("%s", pc->data[pc->sz].sex);
  printf("请输入联系人地址:");
  scanf("%s", pc->data[pc->sz].address);
  printf("请输入联系人电话:");
  scanf("%s", pc->data[pc->sz].phone);
  printf("请设置联系人组别:");
  scanf("%s", pc->data[pc->sz].class);

  pc->sz++;
  return;
}

void DelContact(Contact* pc)
{
  assert(pc);
  if (pc->sz == 0)
  {
    printf("通讯录中无对象可操作!请先增加!");
    mune1();
    return;
  }
  int ret = SearchByName(pc);
  if (ret == -1)
  {
    printf("删除失败请重新操作!");
    mune1();
    return;
  }
  int i = ret;
  for (i = ret; i < pc->sz - 1; i++)
  {
    pc->data[i] = pc->data[i + 1];

  }

  printf("删除成功!\n");
  //这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间
  pc->sz--;
  mune1();
}

int SearchContact(const Contact* pc)
{
  assert(pc);
  //多种方式查找:
  mune();
  int input;
  int ret = -1;
  do {
    //选项的输入
    printf("请输入选项>:");
    scanf("%d", &input);
    //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
    //若输入为0,则判断为FALSE,跳出循环,
    switch (input)
    {
    case S_ByName:
      ret = SearchByName(pc);
      break;
    case S_ByAge:
      SearchByAge(pc);
      break;
    case S_BySex:
      SearchBySex(pc);
      break;
    case S_ByAddr:
      SearchByAddr(pc);
      break;
    case S_ByPhone:
      ret = SearchByPhone(pc);
      break;
    case S_ByClass:
      SearchByClass(pc);
      break;
    case EXIT:
      printf("查找完成,已经返回上一级\n");
      mune1();
      break;
    default:
      printf("该查找方式还待开发哦,请重新输入\n");
      break;
    }
  } while (input);
  return ret;
}

  int SearchByName(const Contact* ps)
{
  int i = 0;
  char name[NAME_MAX];
  int k = 1;
  printf("请输入需要的联系人名字:");
  scanf("%s", name);
  for (i = 0; i < ps->sz; i++)
  {
    if (strcmp(name, ps->data[i].name) == 0)
    {
      //暂时不考虑重名
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }

      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);

      return i;
    }
  }
  printf("无法找到该联系人信息\n");
  return -1;
}

  void SearchByAge(const Contact* ps)
{
  int i = 0;
  int age;
  int flag = 0;
  int k = 1;
  printf("请输入需要查找联系人的年龄:");
  scanf("%d", &age);
  for (i = 0; i < ps->sz; i++)
  {
    if (age == ps->data[i].age)
    {
      flag = 1;
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }

      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);
    }
  }
  if (flag)
  {
    return;
  }
  else
  {
    printf("无法找到该联系人信息\n");
  }
}

  void SearchBySex(const Contact* ps)
{
  int i = 0;
  char sex[SEX_MAX];
  int flag = 0;
  int k = 1;
  printf("请输入需要查找联系人的性别:");
  scanf("%s", sex);
  for (i = 0; i < ps->sz; i++)
  {
    if (strcmp(sex, ps->data[i].sex) == 0)
    {
      flag = 1;
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }
      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);
    }
  }
  if (flag)
  {
    return;
  }
  else
  {
    printf("无法找到该联系人信息\n");
  }
}

  void SearchByAddr(const Contact* ps)
{
  {
    int i = 0;
    char addr[ADDR_MAX];
    int flag = 0;
    int k = 1;
    printf("请输入需要查找联系人的地址:");
    scanf("%s", addr);
    for (i = 0; i < ps->sz; i++)
    {
      if (strcmp(addr, ps->data[i].address) == 0)
      {
        flag = 1;
        if (k == 1)
        {
          printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
          k--;
        }
        printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
          ps->data[i].name,
          ps->data[i].age,
          ps->data[i].sex,
          ps->data[i].address,
          ps->data[i].phone,
          ps->data[i].class);
      }
    }
    if (flag)
    {
      return;
    }
    else
    {
      printf("无法找到该联系人信息\n");
    }
  }
}

  void SearchByClass(const Contact* ps)
{
  {
    int i = 0;
    char class[CLASS_MAX];
    int flag = 0;
    int k = 1;
    printf("请输入需要查找联系人的组别:");
    scanf("%s", class);
    for (i = 0; i < ps->sz; i++)
    {
      if (strcmp(class, ps->data[i].class) == 0)
      {
        flag = 1;
        if (k == 1)
        {
          printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
          k--;
        }
        printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
          ps->data[i].name,
          ps->data[i].age,
          ps->data[i].sex,
          ps->data[i].address,
          ps->data[i].phone,
          ps->data[i].class);
      }
    }
    if (flag)
    {
      return;
    }
    else
    {
      printf("无法找到该联系人信息\n");
    }
  }
}

  int SearchByPhone(const Contact* ps)
{
  int i = 0;
  char phone[PHONE_MAX];
  int k = 1;
  printf("请输入需要查找联系人电话号码:");
  scanf("%s", phone);
  for (i = 0; i < ps->sz; i++)
  {
    if (strcmp(phone, ps->data[i].phone) == 0)
    {
      if (k == 1)
      {
        printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
        k--;
      }

      printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
        ps->data[i].name,
        ps->data[i].age,
        ps->data[i].sex,
        ps->data[i].address,
        ps->data[i].phone,
        ps->data[i].class);

      return i;
    }
  }
  printf("无法找到该联系人信息\n");
  return -1;
}

void ModifyContact(Contact* pc)
{
  int ret = -1;
  int i;
  i = SearchByName(pc);
  if (i != ret)
  {
    printf("请输入修改的内容(部分):\n");
    printf("请输入联系人名字:");
    scanf("%s", pc->data[i].name);
    printf("请输入联系人年龄:");
    scanf("%d", &(pc->data[i].age));
    printf("请输入联系人性别:");
    scanf("%s", pc->data[i].sex);
    printf("请输入联系人地址:");
    scanf("%s", pc->data[i].address);
    printf("请输入联系人电话:");
    scanf("%s", pc->data[i].phone);

  }

}

void PrintContact(const Contact* pc)
{
  assert(pc);
  int i = 0;
  printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
  for (i = 0; i < pc->sz; i++)
  {
    printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
      pc->data[i].name,
      pc->data[i].age,
      pc->data[i].sex,
      pc->data[i].address,
      pc->data[i].phone,
      pc->data[i].class);
  }
}

void DestroyContact(Contact* pc)
{
  free(pc->data);
  pc->data = NULL;
  pc->capacity = 0;
  pc->sz = 0;
  pc = NULL;
}

void SaveContact(const Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
  if (NULL == pf)
  {
    perror("SaveContact error");
  }
  else
  {
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
      fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    printf("保存成功\n");
  }
}

void SortContact(const Contact* pc)
{
  assert(pc);

  DP_QuickSort(pc->data, 0, pc->sz - 1);

  printf("排序完成\n");

}

void Swap(PeoInfo* left, PeoInfo* right)
{
  PeoInfo t = *left;
  *left = *right;
  *right = t;
}

int GerMidNumi(PeoInfo* a, int left, int right)
{
  int mid = (right + left) / 2;

  if (strcmp(a[left].name, a[mid].name) > 0)
  {
    if (strcmp(a[mid].name, a[right].name) > 0)
    {
      return mid;
    }
    else if (strcmp(a[left].name, a[right].name) < 0)
    {
      return left;
    }
    else
    {
      return right;
    }
  }
  else
  {
    if (strcmp(a[left].name, a[right].name) > 0)
    {
      return left;
    }
    else if (strcmp(a[mid].name, a[right].name) < 0)
    {
      return mid;
    }
    else
    {
      return right;
    }
  }
}

void  DP_QuickSort(PeoInfo* a, int left, int right)
{
  int end = right, begin = left;
  if (left >= right)
    return;
  //小区间优化:
  if ((right - left + 1) > 10)
  {
    //方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
    int midi = GerMidNumi(a, left, right);
    if (midi != left)
      Swap(&a[left], &a[midi]);

    int prev = left;
    int cur = prev + 1;
    int keyi = left;

    while (cur <= right)
    {
      if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
        Swap(&a[cur], &a[prev]);
      cur++;
    }
    Swap(&a[prev], &a[keyi]);
    keyi = prev;

    DP_QuickSort(a, begin, keyi - 1);
    DP_QuickSort(a, keyi + 1, end);
  }
  else
  {
    InsertSort(a, right - left + 1);
  }
}

void InsertSort(PeoInfo* a, int n)
{
  for (int i = 1; i < n; i++)
  {
    int end = i - 1;
    PeoInfo tmp = a[i];
    // 将tmp插入到[0,end]区间中,保持有序
    while (end >= 0)
    {
      if (strcmp(tmp.name, a[end].name) < 0)
      {
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = tmp;
  }
}

void  Hide_InitContact(Contact* pc)
{
  assert(pc);
  pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
  if (pc->data == NULL)
  {
    perror("Hide_malloc error");
  }
  pc->sz = 0;
  pc->capacity = INIT_MAX;

  //读取文件
  Hide_LondContact(pc);
}

void Hide_LondContact(Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "rb");
  if (NULL == pf)
  {
    perror("Hide_LondContact error");
  }
  else
  {
    int i = 0;
    PeoInfo tmp = { 0 };
    while (fread(&tmp, sizeof(PeoInfo), 1, pf))
    {
      CapacityContact(pc);
      pc->data[i] = tmp;
      pc->sz++;
      i++;
    }
    fclose(pf);
    pf = NULL;
  }
}

void ShowHide()
{
  char arr1[] = "Welcome to Hide Room !!!";
  char arr2[] = "########################";

  int left = 0;
  int right = strlen(arr1) - 1;

  while (left <= right)
  {
    arr2[left] = arr1[left];
    arr2[right] = arr1[right];
    printf("%s\n", arr2);
    Sleep(1000);
    system("cls");
    left++;
    right--;
  }
  printf("%s\n", arr1);
}

void Administrators(char* password)
{
  char newpassword[20];
  printf("请输入修改密码》:");
  scanf("%s", newpassword);
  strcpy(password, newpassword);
  printf("修改成功\n");
}

bool EncryptionContact()
{
  int i = 0;
  char password[20] = { 0 };
  char insure[20] = { "123456" };

  FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
  if (NULL == pf1)
  {
    perror("password1 error");
  }
  else
  {
    char tmp[20] = { 0 };
    fread(&tmp, 20, 1, pf1);
    strcpy(insure, tmp);
    fclose(pf1);
    pf1 = NULL;
  }

  printf("请输入进入密码》:");
  for (i = 0; i < 3; i++)
  {
    scanf("%s", password);
    if (0 == strcmp(password, insure))
    {
      return true;
    }
    else if (0==strcmp(password,"管理员入口"))
    {
      Administrators(insure);
      FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
      if (NULL == pf2)
      {
        perror("password2 error");
      }
      else
      {
        fwrite(insure, 20, 1, pf2);
        fclose(pf2);
        pf2 = NULL;
        printf("保存成功\n");
      }
      printf("请输入进入密码》:");
    }
    else
    {
      printf("第%d次密码输入错误\n", i + 1);
      if (i < 2)
        printf("请重新输入》:");
    }
  }
  //linux操作系统实现
  printf("密码输入三次错误!请在24小时后重试\n");
  return false;

}

void Hide_SaveContact(const Contact* pc)
{
  FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "wb");
  if (NULL == pf)
  {
    perror("Hide_SaveContact error");
  }
  else
  {
    int i = 0;
    for (i = 0; i < pc->sz; i++)
    {
      fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    printf("保存成功\n");
  }
}

4.代码缺陷,以及优化:

4.1 内存泄漏:

内存泄漏是必须注意的,这里开始malloc了空间,如果没有释放则会影响项目的速度,举个例子:


  • 这里是一个死循环,用来模拟长期在线的服务器,当出现内存泄漏问题会有什么后果:

c9fb5d169f2f8d09096603ac17abdc31_98ca36b7554f4c2084793b491d3c6945.png

  • 开始运行代码:

47f1c78933c097d10a5511220c7b0b10_8d12e19edb5e41f2b07107ffae11aa2b.png

可以注意vs2019所占得内存以及多了这么多,这些没用的空间,会影响项目整体性能,当然在这里只需要把黑匣子关掉,就马上恢复了,这是结束的时候自动释放了。如果未来我们从事的是24小时在线的服务器(比如各种app),出现这种内存泄漏可是及其危险的。所以我们需要手动释放。

void DestroyContact(Contact* pc)
{
  free(pc->data);
  pc->data = NULL;
  pc->capacity = 0;
  pc->sz = 0;
  pc = NULL;
}

代码简单不累,相当实惠哈哈,所以这是要养成的习惯,在申请空间后一定记住手动free多余空间;


4.2 代码可读性维护:

  • 有句流传江湖的话:程序员写完代码,只有自己和上帝认识!
  • 在项目合作过程中的,代码可读性十分重要
  • 比如函数命名、Switch语句的case选项可以枚举代替、以及增加必要注释。增加代码可读性,这里就举case这个例子

05c5afd80876a6819a31a04d9ade1f02_59d319d2d511416e897646df58c10dc4.png

是不是还是有些区别的呢?


4.3 代码的可调式性:

我们往往可以发现我们在写类似“项目”的时候,发现代码一长,是真的难调,一调就是一天,所以我们就要用一些技巧:


  • 1.善用const关键字,对于一些参数无需修改的函数,大胆加上这个关键字,比如通讯录的打印函数
  • 2.会用assert()函数,使用函数我们通常成为暴力检查,这个函数会让你的调试找到方向,明白什么地方错了,便于调试。
  • 3.perror()函数也是如此,若不清楚可以自行查询。

PS:好久没写博客咯,后续会抓紧的哈哈!美图献上(夹带私货),一起加油!

相关文章
|
18天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
46 1
|
2月前
|
算法 搜索推荐 C语言
【C语言】冒泡排序+优化版
【C语言】冒泡排序+优化版
|
2月前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
32 2
|
2月前
|
存储 C语言
手把手教你用C语言实现通讯录管理系统
手把手教你用C语言实现通讯录管理系统
|
3月前
|
网络协议 C语言
C语言 网络编程(十三)并发的TCP服务端-以进程完成功能
这段代码实现了一个基于TCP协议的多进程并发服务端和客户端程序。服务端通过创建子进程来处理多个客户端连接,解决了粘包问题,并支持不定长数据传输。客户端则循环发送数据并接收服务端回传的信息,同样处理了粘包问题。程序通过自定义的数据长度前缀确保了数据的完整性和准确性。
|
3月前
|
存储 测试技术 C语言
C语言实现链表的各种功能
本文详细介绍了如何使用C语言实现链表的各种功能,包括链表节点结构的定义与操作函数的实现。链表作为一种常用的数据结构,具有节点自由插入删除、动态变化等特点。文中通过`link_list.h`和`link_list.c`两个文件,实现了链表的初始化、插入、删除、查找、修改等核心功能,并在`main.c`中进行了功能测试。这些代码不仅展示了链表的基本操作,还提供了丰富的注释帮助理解,适合作为学习链表的入门资料。
|
3月前
|
网络协议 C语言
C语言 网络编程(十四)并发的TCP服务端-以线程完成功能
这段代码实现了一个基于TCP协议的多线程服务器和客户端程序,服务器端通过为每个客户端创建独立的线程来处理并发请求,解决了粘包问题并支持不定长数据传输。服务器监听在IP地址`172.17.140.183`的`8080`端口上,接收客户端发来的数据,并将接收到的消息添加“-回传”后返回给客户端。客户端则可以循环输入并发送数据,同时接收服务器回传的信息。当输入“exit”时,客户端会结束与服务器的通信并关闭连接。
|
3月前
|
C语言
C语言 网络编程(八)并发的UDP服务端 以进程完成功能
这段代码展示了如何使用多进程处理 UDP 客户端和服务端通信。客户端通过发送登录请求与服务端建立连接,并与服务端新建的子进程进行数据交换。服务端则负责接收请求,验证登录信息,并创建子进程处理客户端的具体请求。子进程会创建一个新的套接字与客户端通信,实现数据收发功能。此方案有效利用了多进程的优势,提高了系统的并发处理能力。
|
3月前
|
C语言
C语言 网络编程(九)并发的UDP服务端 以线程完成功能
这是一个基于UDP协议的客户端和服务端程序,其中服务端采用多线程并发处理客户端请求。客户端通过UDP向服务端发送登录请求,并根据登录结果与服务端的新子线程进行后续交互。服务端在主线程中接收客户端请求并创建新线程处理登录验证及后续通信,子线程创建新的套接字并与客户端进行数据交换。该程序展示了如何利用线程和UDP实现简单的并发服务器架构。
|
4月前
|
存储 数据可视化 C语言
【C语言】C语言 手机通讯录系统的设计 (源码+数据+论文)【独一无二】
【C语言】C语言 手机通讯录系统的设计 (源码+数据+论文)【独一无二】